
Chisme del Lince AstroPi08: ¿dónde está la ISS?
Sábado por la noche en la terraza de la cueva. La Raspberry Pi hace una foto cada quince segundos: la pared, un cable, una esquina del cuadro… y cada vez más oscuro.
—Gata, mira —dice Víctor Vílchez, el Lince de la Noche—. Ocho fotos de la terraza. Ciencia pura.
—¿Y sabes dónde estaba la ISS en cada una?
—¿La ISS? Yo estaba en la terraza.
La Gata Montesa señala la pantalla. En el CSV, al lado de cada foto, hay dos columnas nuevas: lat y lon.
—Mientras tú fotografiabas tu pared, la estación cruzaba de Camerún al Chad. 742 kilómetros en menos de dos minutos.
—¿Y eso lo ha medido mi Pi?
—No. Lo ha calculado. Y esa diferencia es la clave de hoy.
La Gata se queda mirando el mapa. Piensa en la foto que hizo la Voyager 1 el 14 de febrero de 1990: la Tierra como un punto diminuto. La Astro Pi la mira desde solo 400 km, pero la idea es la misma: saber dónde estás mirando.
—Una foto de la Tierra sin saber de dónde es —dice— es solo una foto bonita.
Introducción
En los chismes anteriores la Astro Pi ya mide, hace fotos, guarda en CSV, controla los 10 minutos y se prueba con el Replay Tool. Ahora toca responder a una pregunta muy simple: ¿dónde estaba la ISS cuando hicimos cada medida?
Para obtener la posición ISS Python usamos la librería astro_pi_orbit. Con una sola línea nos da la latitud y la longitud del punto de la Tierra que hay justo debajo de la estación.
Por qué este chisme
Si vuestro experimento estudia nubes, desiertos, mares o el campo magnético, necesitáis saber sobre qué lugar se tomó cada dato. Sin la posición, 40 fotos de la Tierra son 40 fotos sin contexto.
Pero la guía de Mission Space Lab avisa de un error habitual: la posición calculada con astro_pi_orbit no cuenta como dato de sensor. Un programa que solo guarda posiciones no cumple las normas. La posición es información complementaria de las medidas de la Sense HAT o de la cámara.
Qué necesitamos
- La Raspberry Pi 4 B con la Sense HAT V2 y la cámara del AstroPi04.
- La librería
astro_pi_orbit(la instalamos ahora). - El programa del AstroPi06, que usamos como base.
El simulador paso a paso
Usad el simulador de la posición de la ISS. Tiene 6 pasos: instalar la librería, distinguir medida de modelo, ejecutar el programa, ver en el mapa por dónde pasaba la ISS, calcular su velocidad y decidir cada cuánto hacer una foto. Las posiciones, tiempos y tamaños son los reales de nuestra prueba.

Instalar astro_pi_orbit
En la Astro Pi de la ISS ya viene instalada. En vuestra Pi, abrid un terminal:
pip3 install --break-system-packages astro-pi-orbit
Tarda un par de minutos. Después comprobad que está:
python3 -c "import astro_pi_orbit; print('astro_pi_orbit OK')"
Posición ISS Python en tres líneas
from astro_pi_orbit import ISS
iss = ISS()
position = iss.coordinates()
print(position.latitude.degrees, position.longitude.degrees)
ISS()crea un objeto que conoce la órbita de la estación.iss.coordinates()calcula dónde está ahora el punto de la Tierra que hay justo debajo de la ISS..latitude.degreesy.longitude.degreesdan la latitud y la longitud en grados.
El código completo
Guardad este main.py en ~/astropi/astropi08. Para probar en clase dura 2 minutos y hace una foto cada 15 segundos.
"""
Chisme del Lince AstroPi08 - Where is the ISS?
Raspberry Pi 4 B + Sense HAT V2 + Camera Module + astro_pi_orbit.
Every second: magnetometer + ISS position. Every PHOTO_EVERY seconds: a photo.
The ISS position comes from an orbit model: it is extra information,
NOT sensor data. The sensor data is the magnetometer and the camera.
"""
from sense_hat import SenseHat
from picamzero import Camera
from astro_pi_orbit import ISS
from pathlib import Path
from datetime import datetime, timedelta
from time import sleep
import csv
base_folder = Path(__file__).parent.resolve()
data_file = base_folder / "data.csv"
print(f"Saving data in: {base_folder}")
sense = SenseHat()
sense.set_imu_config(True, True, True)
camera = Camera() # create the camera ONCE (opening it again and again wastes memory)
iss = ISS()
# ---------------------------------------------------------------
# PART 1 - Mission settings
# ---------------------------------------------------------------
RUN_MINUTES = 2 # 10 on the ISS (test with 2)
SAFETY_SECONDS = 10 # photos are slow: a bigger margin
SECONDS_BETWEEN = 1 # one reading per second
PHOTO_EVERY = 15 # one photo every 15 seconds
MAX_PHOTOS = 42 # Mission Space Lab limit
start_time = datetime.now()
end_time = start_time + timedelta(minutes=RUN_MINUTES) - timedelta(seconds=SAFETY_SECONDS)
next_reading = start_time
next_photo = start_time
longest_loop = timedelta(0)
count = 0
photos = 0
photo_bytes = 0
# ---------------------------------------------------------------
# PART 2 - THE IMPORTANT PART: sensor + position every second, photo when it is time
# ---------------------------------------------------------------
with open(data_file, "w", newline="") as f:
writer = csv.writer(f)
writer.writerow(["time", "elapsed_s", "work_ms", "lat", "lon",
"mag_x", "mag_y", "mag_z", "photo"])
while datetime.now() + longest_loop < end_time:
loop_start = datetime.now()
mag = sense.get_compass_raw()
position = iss.coordinates()
lat = position.latitude.degrees
lon = position.longitude.degrees
photo_name = ""
if loop_start >= next_photo and photos < MAX_PHOTOS:
photo_name = f"image_{photos:02d}.jpg"
photo_path = base_folder / photo_name
camera.take_photo(str(photo_path))
photo_bytes += photo_path.stat().st_size
photos += 1
next_photo += timedelta(seconds=PHOTO_EVERY)
print(f"Photo {photos}: {photo_name} at lat {lat:.2f}, lon {lon:.2f}")
work_ms = (datetime.now() - loop_start).total_seconds() * 1000
elapsed = (loop_start - start_time).total_seconds()
writer.writerow([loop_start.isoformat(timespec="milliseconds"),
round(elapsed, 3), round(work_ms, 1),
round(lat, 4), round(lon, 4),
round(mag["x"], 2), round(mag["y"], 2), round(mag["z"], 2),
photo_name])
f.flush()
count += 1
next_reading += timedelta(seconds=SECONDS_BETWEEN)
wait = (next_reading - datetime.now()).total_seconds()
if wait > 0:
sleep(wait)
longest_loop = max(longest_loop, datetime.now() - loop_start)
# ---------------------------------------------------------------
# PART 3 - Summary
# ---------------------------------------------------------------
total = (datetime.now() - start_time).total_seconds()
print(f"Readings: {count}")
print(f"Photos: {photos} ({photo_bytes / 1_000_000:.1f} MB)")
print(f"Total time: {total:.1f} s (limit: {RUN_MINUTES * 60} s)")
print(f"Longest loop: {longest_loop.total_seconds():.3f} s")
print("Done!")
Lo nuevo, línea a línea
camera = Camera()va una sola vez, fuera del bucle. La guía avisa: abrir y cerrar la cámara una y otra vez puede agotar la memoria.iss = ISS()también se crea una vez. Dentro del bucle solo se llama aiss.coordinates().next_photofunciona igual quenext_readingen el AstroPi06: guarda la hora de la próxima foto. Cuando llega esa hora, se hace la foto y se suman 15 s.photos < MAX_PHOTOSimpide pasar de 42 imágenes, el máximo de Mission Space Lab.photo_bytesva sumando lo que ocupan las fotos, para vigilar el espacio.- La columna
photodel CSV guarda el nombre de la foto en la fila en que se hizo. Así cada foto queda unida a su hora, su posición y su lectura del magnetómetro. SAFETY_SECONDS = 10: las fotos son lentas, así que dejamos más margen.
Cómo probarlo
Ejecutad main.py (2 minutos). En nuestra prueba salieron estas líneas:
Photo 1: image_00.jpg at lat 5.72, lon 12.12
Photo 2: image_01.jpg at lat 6.48, lon 12.67
Photo 3: image_02.jpg at lat 7.24, lon 13.22
Photo 4: image_03.jpg at lat 8.00, lon 13.77
Photo 5: image_04.jpg at lat 8.76, lon 14.32
Photo 6: image_05.jpg at lat 9.52, lon 14.87
Photo 7: image_06.jpg at lat 10.28, lon 15.43
Photo 8: image_07.jpg at lat 11.04, lon 15.99
Readings: 108
Photos: 8 (18.1 MB)
Y esta es una de nuestras fotos: la terraza, ya casi de noche.

Qué miden realmente nuestros datos
Medida frente a modelo
La foto y el magnetómetro son medidas: un aparato de la Astro Pi capta algo real. La latitud y la longitud son un cálculo: astro_pi_orbit usa un modelo de la órbita de la ISS para saber dónde debería estar en cada instante.
Es una diferencia importante en ciencia. Un modelo puede ser muy bueno, pero no es una observación. Por eso Mission Space Lab no acepta un programa que solo guarde posiciones.
Por dónde pasaba la ISS
En nuestra prueba, la ISS pasó de 5,7° N 12,1° E (Camerún) a 11,1° N 16,1° E (el Chad), rumbo al nordeste. Allí también era de noche: unas fotos tomadas desde la ISS en ese momento habrían salido negras. Por eso los programas de Mission Space Lab se ejecutan durante las horas de luz.
En la ISS, cada foto de verdad quedaría unida a la posición de la Tierra que fotografía. Esa es la utilidad de este chisme.
Un adelanto: la velocidad
Entre la primera y la última lectura, la ISS recorrió 742 km en 107 s: unos 6,9 km/s sobre el suelo.
La ISS va a unos 7,66 km/s en su órbita, pero a unos 400 km de altura. Su sombra sobre el suelo va más despacio, unos 7,2 km/s. Y como la Tierra gira hacia el este mientras la ISS sube hacia el nordeste, el suelo «se escapa» un poco más. En el AstroPi09 mediremos la velocidad de otra forma: con fotos, que sí son datos de la Astro Pi.
Cuánto cuesta cada foto
Cada vuelta con foto tardó unos 2 s; sin foto, unos 21 ms. Cada foto ocupó unos 2,3 MB. Con una foto cada 15 s, en 10 minutos saldrían unas 40 fotos y unos 90 MB: por debajo de las 42 fotos y de los 250 MB de almacenamiento.
Posición ISS Python en la ISS de verdad
Para el vuelo, RUN_MINUTES = 10. Con PHOTO_EVERY = 15 caben unas 40 fotos repartidas por toda la misión. Si bajáis a 10 s, el programa querría hacer 59, MAX_PHOTOS lo cortaría en 42 y los últimos minutos se quedarían sin fotos.
Probadlo antes en el Replay Tool, como en el AstroPi07. Allí las fotos y la posición serán de la ISS.
Para el aula
- Clasifica: de todo lo que guarda el programa, ¿qué es medida y qué es modelo?
- Mapa: pasad las latitudes y longitudes de las fotos a un mapa (por ejemplo, en una hoja de cálculo o en un mapa en papel). ¿Por qué países pasó la ISS?
- Cuentas: si cada foto ocupa 2,3 MB, ¿cuántas caben en 250 MB? ¿Cuál es entonces el límite que manda, el de las 42 fotos o el de los 250 MB?
- Luz: buscad a qué hora se hizo la prueba y si era de día o de noche en el lugar por el que pasaba la ISS.
Retos
Reto 1
Haz que funcione: instala astro_pi_orbit, ejecuta el programa y busca en el CSV la posición de cada foto.
Reto 2
Cambia PHOTO_EVERY a 30 s. ¿Cuántas fotos salen en 2 minutos? ¿Y en 10?
Reto 3
Añade una columna con la altura de la ISS. Busca en la documentación de astro_pi_orbit cómo obtenerla.
Reto 4
Calcula la velocidad de la ISS sobre el suelo entre cada par de fotos y comprueba si siempre sale lo mismo.
Reto 5
Sube el programa al Replay Tool con RUN_MINUTES = 10 y compara las posiciones que salen con las de tu Pi.
Qué hemos aprendido
astro_pi_orbitda la posición ISS Python usandoiss.coordinates().- Esa posición viene de un modelo: no cuenta como dato de sensor, pero da contexto a las medidas.
- La cámara se crea una sola vez, y las fotos se programan con su propia hora, igual que las lecturas.
- Hay que vigilar el número de fotos (42 como máximo) y el espacio (250 MB).
Próximamente: AstroPi09, la velocidad de la ISS medida con fotos.
Para seguir investigando
Etiqueta:AIDARAC, Astro Pi, astro_pi_orbit, ies monterroso, ISS, Mission Space Lab, montesteam, python, Raspberry Pi, Sense HAT



