International Space Station Tracker (ISS) with a WiFi enabled Raspberry Pi Pico
As the Raspberry Pi Pico doesn't have WiFi I brought a ESP32spi co-processor to allow the Pico to communicate over wifi. For my first wifi Pico project I decided to build a Space Station Tracker which displays the ISS's current location on a map. I have previously done this with a Raspberry Pi Zero W using a Triple Colour e-ink display , but I though I would see if I can get it to work on a RP2040 Pico with only 264k of memory.
The concept for this projects is to get a Json file from api.open-notify.org which contains the current Latitude and Longitude of the ISS. Then compare that to a list of Latitude and Longitude co-ordinates for the Capital Cities of the world. This is then plotted on a map of the world with information on how far the ISS is from the closest Capital City.
It is not only interesting to know where the Space Station is but also helps kids and adults learn the geography of the world while watching the dot move across the map.
I am using Circuitpython to build the ISS Tracker as I have the Adafruit ESP32spi Wifi breakout board.
To build this project I used:
- Raspberry Pi RP2040 Pico
- Adafruit ESP32spi WiFi co-processor
- ST7789V 1.3 inch 240 x 240 LCD Display by Pimoroni
- Pimoroni - Pico Proto board and female headers
- CircuitPython firmware installed to the Pico
The programs flow is:
- Retrieve the json file of the ISS's co-ordinates from the internet
- Compare the co-ordinates to a list of Capital City co-ordinates to find the closes city
- Calculate the position of the red dot on the world map
- Calculate the trail of dots to show where the ISS has been
- Build the display image of a map and location text
- Display image
Retrieving the ISS's Location
The first stage is to get the ESP32spi setup and able to retrieve the Json file from the internet to read it's current location. Create a file called code.py and start coding.
The ESP32 requires these adafruit CircuitPython libraries:
import board
import busio
from digitalio import DigitalInOut
from adafruit_esp32spi import adafruit_esp32spi
from adafruit_esp32spi import adafruit_esp32spi_wifimanager
import adafruit_esp32spi.adafruit_esp32spi_socket as socket
from time import sleep
Additional libraries that will be needed for this project are:
import displayio
from adafruit_st7789 import ST7789
import terminalio
import adafruit_requests as requests
from time import sleep
import haversine
from adafruit_display_text import label
import adafruit_imageload
from adafruit_display_shapes.circle import Circle
from adafruit_display_shapes.rect import Rect
from adafruit_bitmap_font import bitmap_font as bitf
The ESP32 was connected with Pico SPi pins. Pico GPIO Layout cheatsheet
#ESP32 Setup on Pico:
esp32_cs = DigitalInOut(board.GP13)
esp32_ready = DigitalInOut(board.GP8)
esp32_reset = DigitalInOut(board.GP9)
spi = busio.SPI(board.GP10, board.GP11, board.GP12) #sck, tx, rx
esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset)
Create a file called secrets.py and save it to the Pico's CIRCUITPY folder. The secrets file should contain your WiFi networks SSID and password like this;
secrets = {
'ssid' : 'YOUR-SSID',
'password' : 'YOUR-PASSWORD'
}
The next step in code.py is to set the wifi manger up with the secrets.py file.
try:
from secrets import secrets
except ImportError:
print("WiFi secrets are kept in secrets.py, please add them there!")
raise
wifi = adafruit_esp32spi_wifimanager.ESPSPI_WiFiManager(esp, secrets)
This next function will be used to connect the ESP32's wifi to your wifi network and also reconnect if the signal is lost while the program is running
def esp32():
try:
s = esp.status
print("ESP32 Status", s)
if s == 0:
wifi.connect()
except RuntimeError as r:
wifi.reset()
Now the code is in place to give the Pico internet access the next function is used to retrieve the ISS co-ordinates.
def iss_lat_lon():
JSON_URL = "http://api.open-notify.org/iss-now.json"
try:
result = requests.get(JSON_URL).json()["iss_position"]
except RuntimeError as r:
wifi.reset()
#esp.reset
esp32()
result = requests.get(JSON_URL).json()["iss_position"]
lat = result["latitude"]
lon = result["longitude"]
return lat,lon
To reduce load on open-notify.org it is recommended that the json file is not accessed more than once every 5 seconds. For this project I have set it at once every 30 seconds which is the delay of the main loop.
Now enter this code and run the script. This will show the co-ordinates in the output window
while 1:
print(iss_lat_lon())
sleep(10)
Once the ISS position is ready, it can be compared against a csv list of global capital cities. I would have liked to use a list of the major cities of the world but the Pico does not have enough memory to achieve this. So a list of 196 Capital cities just about fits. The base list came from https://simplemaps.com/data/world-cities which was then limited.
The haversine calculation is used to get the distance between two locations on the earth. I have used the python code by Wayne Dyck and saved it as haversine.py to the CIRCUITPY folder. This can be downloaded from https://gist.github.com/rochacbruno/2883505
The full code for this project is available at the end of this article, so for the next stage a list of city latitude and longitude co-ordinates have already been loaded. This next function takes the ISS co-ordinates and compares it to every city's co-ordinates and records the closest city using the haversine calculation
"data" is the latitude, longitude, country, city from the csv converted to a list.
-41.28646 174.776236 New Zealand Wellington -35.282 149.128684 Australia Canberra -34.901113 -56.164531 Uruguay Montevideo -34.603684 -58.381559 Argentina Buenos Aires
"sz" is the amount of rows in the list
"iss" is the current ISS co-ordernates
Each cities lat, lon co-ordinates are compared to the ISS's lat, lon co-ordinates and the distance, country and city is logged in the variables. If the current distance is closer then the logged distance then the variables are updated. At the end the closest city will be left in the variables.
def CalcLoc(data, sz, iss):
country = ""
city = ""
citydist = 0
mindist = 99999999
for i in range(sz):
d = haversine.distance((float(data[i][0]),float(data[i][1])),(float(iss[0]),float(iss[1])))
if d < mindist:
city = data[i][2]
country = data[i][3]
citydist = d
mindist = d
return (country,city,round(citydist,2))
Position the ISS's location on a Map
To be able to draw the ISS's location on a map the Latitude & Longitude need to be converted to the pixels of a map.
Latitude and Longitude coordinates pinpoint locations on the earth 180 degrees North to South and 360 degrees West to East.
The north pole is +90 and the south pole -90 with the equator at zero.
For left to right, -180 to +180 is at the international date line near Japan, Australia in the Pacific Ocean. Latitude Zero is a vertical line through the UK.
The best way to show this on a map is to use world images that are multiples of 360 x 180.
I am using a 240 pixel screen but an image of 180 X 90 is a bit small. So I have gone with a image that is 360 x 180. The display will then move left and right as the ISS moves across the world.
The latitude co-ordinates go from +90 at the north pole to -90 at the south pole. The display co ordinates for the screen map is 0 at the north pole and 179 at the south pole.
To get the red dot that shows the ISS's location in the correct place, a calculation neds to be made to convert between the two coordinated systems.
180-(ISS_lat+90) = image Y.
ie if the latitude is -20 then 180-(-20+90) = 110 pixels from the top.
The longitude is a little easier. Longitude goes -180 to +180. The image goes from 0 to 179 pixels left to right.
So just add 180 to the ISS's longitude to get the correct point on the image. -30 + 180 = 150 pixels from the left.
The image of the world should be the equirectangular version, which is a flattened sphere. The top and bottom of the image are stretched and distorted. If a flat world map is used the coordinates won't line up.
This image will show the ISS's location correctly.
This image will cause the location to be wrong.
The Earth images for this project were created from the ones here https://visibleearth.nasa.gov/collection/1484/blue-marble
For CircuitPython the world image needs to be in BMP format and as low quality as you can use to save memory. I have used 16 colours, Dithered with RLE compression and 4bit colour. This is 21k.
Now all the information is available to build the display image. In addition to the Circle showing the ISS's location, a trail of dots are drawn to show the route where the ISS's has been during the last orbit. It takes the Space Station about 90 minutes to orbit the Earth. Due to the Pico's limited memory the trail is 32 dots with 1 dot every 2 minutes.
The Pico Space Station Tracker
The project files can be downloaded https://www.raspberryconnect.com/images/scripts/Pico-Iss-Tracker-Project-Files.zip
Unzip the files to your CIRCUITPY folder on the Pico.
The following Circuitpython Libraries will be needed in the CIRCUITPY/lib folder.
- adafruit_bus_device
- adafruit_esp32spi
- adafruit_display_text
- adafruit_display_shapes
- adafruit_imageload
- adafruit_bitmap_font
- adafruit_st7789.mpy
- adafruit_request.mpy
The secrets.py file is also required with the WiFi network connection details as described in the article.
If you have any issues with zip file link above please visit
https://www.raspberryconnect.com/projects/39-programming/194-raspberry-pi-pico-with-wifi-used-as-an-international-space-station-tracker-iss
and use the zip download link at the bottom of the article.
I hope you find this useful
International Space Station Tracker (ISS) with a WiFi enabled Raspberry Pi Pico
- Comments(0)
- Likes(4)
- Engineer Oct 01,2024
- LUIS EMILIO LOPEZ Feb 12,2024
- ugur tezer Jan 07,2024
- Engineer Jun 14,2021
- 1 USER VOTES
- YOUR VOTE 0.00 0.00
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
-
3design
-
4usability
-
3creativity
-
4content
More by Graeme Richards
-
-
-
3D printed Enclosure Backplate for Riden RD60xx power supplies
74 1 1 -
-
-
-
Sega Master System RGB Encoder Switcher Z80 QSB v1.2
68 0 0 -
18650 2S2P Battery Charger, Protection and 5V Output Board
98 0 0 -
High Precision Thermal Imager + Infrared Thermometer | OpenTemp
501 0 7 -
Sony PlayStation Multi Output Frequency Oscillator (MOFO) v1
143 0 2 -