Skip to content

Commit 16b2cd1

Browse files
authored
Final
1 parent dd8ee50 commit 16b2cd1

File tree

2 files changed

+133
-0
lines changed

2 files changed

+133
-0
lines changed

usr/local/bin/iss-tracker.py

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
#!/usr/bin/env python3
2+
3+
import tkinter as tk
4+
from tkinter import Canvas
5+
import requests
6+
from sgp4.api import Satrec, WGS72
7+
from datetime import datetime, timedelta
8+
import math
9+
import cartopy.crs as ccrs
10+
import matplotlib.pyplot as plt
11+
from PIL import Image, ImageTk
12+
import io
13+
14+
15+
def generate_map():
16+
fig = plt.figure(figsize=(8, 4))
17+
ax = fig.add_subplot(1, 1, 1, projection=ccrs.PlateCarree())
18+
ax.set_global()
19+
ax.stock_img()
20+
ax.coastlines()
21+
buf = io.BytesIO()
22+
plt.savefig(buf, format='png', dpi=100)
23+
buf.seek(0)
24+
plt.close(fig)
25+
return Image.open(buf)
26+
27+
def get_pi_location():
28+
try:
29+
response = requests.get("http://ip-api.com/json/")
30+
data = response.json()
31+
return data['lat'], data['lon']
32+
except:
33+
return 0, 0
34+
35+
def fetch_iss_tle():
36+
url = "https://celestrak.org/NORAD/elements/stations.txt"
37+
tle_data = requests.get(url).text
38+
lines = tle_data.split('\n')
39+
for i, line in enumerate(lines):
40+
if "ISS (ZARYA)" in line:
41+
return lines[i+1], lines[i+2]
42+
return None, None
43+
44+
def latlon_to_xy(lat, lon, width, height):
45+
x = (lon + 180) * (width / 360)
46+
y = (90 - lat) * (height / 180)
47+
return x, y
48+
49+
class ISSTrackerApp:
50+
def __init__(self, root):
51+
self.root = root
52+
self.root.title("ISS Tracker")
53+
self.canvas = Canvas(root, width=800, height=400)
54+
self.canvas.pack()
55+
56+
self.image = generate_map().resize((800, 400))
57+
self.tk_image = ImageTk.PhotoImage(self.image)
58+
self.canvas.create_image(0, 0, anchor="nw", image=self.tk_image)
59+
60+
self.lat, self.lon = get_pi_location()
61+
self.load_tle()
62+
63+
self.time_offset = timedelta(seconds=0)
64+
65+
self.root.bind("<Left>", self.go_back)
66+
self.root.bind("<Right>", self.go_forward)
67+
self.root.bind("<space>", self.reset_time)
68+
69+
self.update_display()
70+
71+
def load_tle(self):
72+
tle1, tle2 = fetch_iss_tle()
73+
if tle1 and tle2:
74+
self.satellite = Satrec.twoline2rv(tle1, tle2)
75+
else:
76+
self.satellite = None
77+
78+
def update_display(self):
79+
self.canvas.delete("markers")
80+
self.canvas.create_image(0, 0, anchor="nw", image=self.tk_image)
81+
82+
x, y = latlon_to_xy(self.lat, self.lon, 800, 400)
83+
self.canvas.create_oval(x-4, y-4, x+4, y+4, fill="red", tags="markers")
84+
85+
if self.satellite:
86+
now = datetime.utcnow() + self.time_offset
87+
jd, fr = self.satellite.jday(now.year, now.month, now.day, now.hour, now.minute, now.second + now.microsecond/1e6)
88+
e, pos, vel = self.satellite.sgp4(jd, fr)
89+
iss_lat = math.degrees(math.asin(pos[2]/(WGS72.radiuse + pos[0]**2 + pos[1]**2 + pos[2]**2)**0.5))
90+
iss_lon = math.degrees(math.atan2(pos[1], pos[0]))
91+
if iss_lon > 180:
92+
iss_lon -= 360
93+
94+
iss_x, iss_y = latlon_to_xy(iss_lat, iss_lon, 800, 400)
95+
self.canvas.create_oval(iss_x-4, iss_y-4, iss_x+4, iss_y+4, fill="purple", tags="markers")
96+
97+
for mins in range(5, 90, 5):
98+
future_time = now + timedelta(minutes=mins)
99+
jd_fut, fr_fut = self.satellite.jday(future_time.year, future_time.month, future_time.day,
100+
future_time.hour, future_time.minute,
101+
future_time.second + future_time.microsecond / 1e6)
102+
e_fut, pos_fut, vel_fut = self.satellite.sgp4(jd_fut, fr_fut)
103+
lat_fut = math.degrees(math.asin(pos_fut[2]/(WGS72.radiuse + pos_fut[0]**2 + pos_fut[1]**2 + pos_fut[2]**2)**0.5))
104+
lon_fut = math.degrees(math.atan2(pos_fut[1], pos_fut[0]))
105+
if lon_fut > 180:
106+
lon_fut -= 360
107+
path_x, path_y = latlon_to_xy(lat_fut, lon_fut, 800, 400)
108+
self.canvas.create_oval(path_x-1, path_y-1, path_x+1, path_y+1, fill="blue", tags="markers")
109+
110+
self.root.after(1000, self.update_display)
111+
112+
def go_forward(self, event):
113+
self.time_offset += timedelta(minutes=10)
114+
115+
def go_back(self, event):
116+
self.time_offset -= timedelta(minutes=10)
117+
118+
def reset_time(self, event):
119+
self.time_offset = timedelta(seconds=0)
120+
121+
if __name__ == "__main__":
122+
root = tk.Tk()
123+
app = ISSTrackerApp(root)
124+
root.mainloop()
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[Desktop Entry]
2+
Version=1.0
3+
Type=Application
4+
Name=ISS Tracker
5+
Comment=Track ISS and your Pi location with live world map
6+
Exec=/usr/local/bin/iss-tracker.py
7+
Icon=utilities-terminal
8+
Terminal=false
9+
Categories=Education;Science;Utility;

0 commit comments

Comments
 (0)