На орбите Земли много искусственных объектов, самый большой из которых — Международная космическая станция. Её даже можно увидеть невооружённым глазом, но для этого нужно знать, когда и куда смотреть из той точки, где находишься.
Сегодня мы упростим жизнь всем, кто хочет посмотреть на МКС, и напишем для этого программу на Python. Она будет выводить на экран карту Земли и иконку МКС, которая будет перемещаться по этой карте согласно положению станции в реальном времени. Одновременно с отображением карты программа будет выводить в консоль координаты станции и список космонавтов на борту. Получится мини-ЦУП, только без связи с космонавтами.
Если вы ещё не программировали на Python и только знакомитесь с этим языком, почитайте наш мастрид и эти статьи:
Что сделаем
Мы напишем код, который будет запрашивать по API актуальные данные о положении и перемещении МКС и о людях на борту. В интернете есть несколько открытых API, по которым можно получить подобную информацию, мы будем использовать api.open-notify.org.
Чтобы видеть движение станции относительно Земли, мы загрузим в программу карту, которая покрывает от −900 до 900 широты и от −1800 до 1800 долготы. Мы наложим на эту карту положение МКС и отобразим её в виде иконки. Точные координаты станции будем выводить в консоли Python. При загрузке программа также будет отображать список космонавтов, которые находятся на МКС.
Что для этого нужно
Нам понадобится несколько встроенных модулей Python. Устанавливать отдельно их не нужно, достаточно просто импортировать.
Json — модуль для работы с файлами формата JSON. Чаще всего API возвращают ответы в этом формате.
Urllib позволяет делать запросы на URL и использовать ответы. Мы будем использовать только один конкретный метод для получения информации из API — urllib.request
.
Turtle нужен для рисования и работы с изображениями. У него небольшие возможности, но для нашего проекта хватит.
Os даёт доступ к функциям, связанным с операционной системой.
Time предоставляет методы для работы со временем.
Webbrowser может открывать файлы в отдельном окне при запуске скрипта. Если файл можно открыть в браузере, откроется браузер по умолчанию. Для других форматов будут использованы подходящие программы — например, текстовый файл откроется в текстовом редакторе.
Аннотации типов — подсказки, которые объясняют, какой тип данных будет храниться в каждой переменной. Указывать их необязательно, но с ними код становится понятнее. Аннотации ставятся после двоеточия:
# в переменной var должно храниться целое число, которое мы получим
# после извлечения элемента списка newlist под номером index
var: int = newlist[index]
Typing и http.client понадобятся, чтобы мы могли указать корректные типы данных в аннотациях. Из typing мы добавим типы Dict
, List
и Any
, а из http.client — HTTPResponse
.
Весь код положим в одну функцию.
Ещё нам понадобится подходящее изображение карты в пропорции 2:1 и иконка для отображения МКС. Мы возьмём те, для которых не нужна лицензия.
Импортируем модули
Загружаем модули для работы программы:
# добавляем модуль для работы с JSON-форматом
import json
# добавляем модуль для HTTP-запросов
import urllib.request
# добавляем модуль рисования
import turtle
# модуль для использования возможностей операционной системы
import os
# добавляем модуль для работы со временем
import time
# добавляем модуль для открытия URL-адресов по умолчанию
import webbrowser
# импортируем типы данных для аннотации типов
from typing import Dict, List, Any
from http.client import HTTPResponse
👉 Модуль turtle — часть графической библиотеки tkinter
. На Windows эта библиотека сразу устанавливается вместе с Python, а на MacOS и Linux её иногда нет. Проверить, есть tkinter
или нет, можно такой командой в терминале:
python3 -m tkinter
Должно появиться небольшое окно:
Если нет, терминал выдаст примерно такую ошибку:
ModuleNotFoundError: No module named '_tkinter
Tkinter нельзя установить через pip
— вместо этого лучше установить пакетный менеджер Homebrew и потом в консоли выполнить такую команду:
brew install python-tk
Получаем и выводим список космонавтов
В api.open-notify.org
можно сделать всего два запроса:
- для получения списка космонавтов на борту;
- для получения координат МКС.
Открываем страницу с описанием запроса списка космонавтов и видим, по какому адресу нужно отправить запрос и что придёт в ответ:
Вот что мы сделаем:
- создадим функцию
def main()
, в которой будет работать весь остальной код; - сохраним URL-адрес в переменную
url
(тип переменной — строка); - отправим на этот адрес запрос и сохраним ответ в переменной
res
(тип переменной — HTTP-ответ, то есть сохраняем в том виде, в каком придёт — JSON); - сохраним ответ в переменной
result
в формате словаря, где в качестве ключей будут строки, а значениями может быть любой формат.
# пишем основную и единственную функцию
def main():
# задаём адрес для запроса списка космонавтов
url: str = 'http://api.open-notify.org/astros.json'
# открываем URL, используя urllib.request
res: HTTPResponse = urllib.request.urlopen(url)
# загружаем и читаем json-файл
result: Dict[str, Any] = json.loads(res.read())
Для создания и записи текстового файла создадим контекстный менеджер. Это конструкция, которая выполняет дополнительный код до и после блока кода, который пишет программист. Контекстных менеджеров много, мы будем использовать with open:
он создаст текстовый файл в корневой папке проекта и откроет его для записи, а после блока кода закроет его.
Создаём менеджер и указываем в скобках имя файла и тип работы с ним — у нас будет 'w'
, запись:
# создаём текстовый файл с именами членов экипажа
# открываем файл для записи
with open('iss.txt', 'w') as file:
Сначала добавляем общее количество космонавтов. Для этого из словаря result
нам нужно получить значение по ключу number
:
# добавляем запись и дублируем текст в консоль
file.write(f'В настоящий момент на МКС {str(result["number"])} космонавтов:\n\n')
print('В настоящий момент на МКС ' + str(result["number"]) + ' космонавтов:\n')
Чтобы получить конкретные имена членов экипажа, нам понадобится список people
. Достаём его из result
:
# получаем список имён космонавтов
people: List[Dict[str, str]] = result['people']
Список состоит из словарей, где ключи и значения — строки. Нам нужны значения по ключу name
. Для этого перебираем список циклом и записываем в наш файл все значения по этому ключу:
# для каждого человека в списке выводим его имя
for person in people:
file.write(person['name'] + '\n')
# и сразу дублируем текст в консоль
print(person['name'] )
На этом работа контекстного менеджера закончена, можно выводить файл на экран.
Сначала получаем абсолютный путь до нашего файла и сохраняем его в переменную-строку file_path
:
# получаем абсолютный путь к файлу
file_path: str = os.path.abspath('iss.txt')
Теперь, если что, мы всегда можем открыть этот файл (он будет лежать в той же папке, что и проект) и посмотреть список космонавтов.
А вот что у нас уже появилось в консоли после запуска:
Настраиваем изображение карты и станции
Чтобы Python выводил карту на экран и отображал на ней перемещение станции, нужно объяснить программе, как должно выглядеть итоговое изображение.
Сначала создаём переменную типа Screen
из модуля turtle
и устанавливаем размеры экрана:
# создаём главное окно для графической работы
screen: turtle.Screen = turtle.Screen()
# устанавливаем размеры окна
screen.setup(1280, 720)
По нашей карте будет двигаться мини-изображение МКС. Чтобы программа отрисовывала его в правильном месте, карту нужно разметить: задать минимальные и максимальные координаты по горизонтальной и вертикальной осям.
Модуль turtle
позволяет задать отрицательные и положительные координаты, что будет соответствовать отрицательной и положительной широте и долготе:
# устанавливаем систему координат для экрана, аналогичную координатам Земли
screen.setworldcoordinates(-180, -90, 180, 90)
Модуль turtle
умеет работать только с изображениями в формате gif. Загружаем изображение карты как фон главного экрана:
# загружаем изображение карты мира из файла
screen.bgpic('map.gif')
Turtle используется для рисования, причём во время рисования у нас должен быть объект класса Turtle()
, который оставляет след. Это как карандаш или ручка для бумаги.
Регистрируем новое изображение, которое можно будет использовать в качестве видимого объекта Turtle()
:
# загружаем изображение станции из файла
screen.register_shape('iss.gif')
Создаём переменную — объект этого класса:
# присваиваем переменной iss значение объекта Turtle
iss = turtle.Turtle()
Говорим программе, что для отображения нового Turtle()
нужно использовать изображение iss.gif:
# придаём переменной вид изображения станции из файла
iss.shape('iss.gif')
Нам сейчас не нужно, чтобы станция оставляла след, — поэтому используем метод penup()
, который отключает функцию рисования у объекта.
# выключаем функцию рисования следа от объекта Turtle()
iss.penup()
Отображаем перемещение станции в реальном времени
Для получения координат МКС берём второй метод API. Из документации берём адрес запроса и формат ответа:
Нам понадобится постоянно обновлять изображение МКС на карте. Для этого подойдёт бесконечный цикл.
Для первых действий получается такой алгоритм:
- создаём цикл;
- сохраняем URL-адрес в переменную
url
(тип переменной — строка); - посылаем на этот адрес запрос и сохраняем JSON-ответ в переменной
res
(тип переменной — HTTP-ответ); - переводим ответ
res
в переменнуюresult
с типом «словарь», ключами которого будут строки, а значениями — другие словари:
# запускаем бесконечный цикл
while True:
# прописываем адрес для запроса о текущем положении МКС
url: str = 'http://api.open-notify.org/iss-now.json'
# объявляем переменную и сохраняем в неё ответ
res: HTTPResponse = urllib.request.urlopen(url)
# переводим ответ в JSON и читаем
result: Dict[str, Dict[str, str]] = json.loads(res.read())
Чтобы получить ширину и долготу, делаем так:
- извлекаем из переменной
result
словарь по ключу'iss_position'
и сохраняем его в переменную-словарьlocation
; - из
location
по очереди достаём и сохраняем в разные переменные значения по ключам'latitude'
и'longitude'
.
# извлекаем локацию станции
location: Dict[str, str] = result['iss_position']
# извлекаем только широту станции
lat: float = float(location['latitude'])
# извлекаем только долготу станции
lon: float = float(location['longitude'])
Добавим вывод координат в консоль и будем фиксировать, в какое время в какой точке появляется МКС. Для этого сохраним в отдельную переменную-строку current_time
запись о текущем моменте времени и напечатаем все три строки:
# Получение текущего времени
current_time: str = time.strftime("%Y-%m-%d %H:%M:%S")
# Вывод на экран
print("\nДата и время:", current_time)
# выводим широту и долготу в терминал
print(f'Широта: {lat}')
print(f'Долгота: {lon}')
Чтобы станция начала двигаться, делаем так:
Отправляем объект iss
на новые координаты:
# обновляем локация станции на карте
iss.goto(lon, lat)
Обновляем весь цикл каждые 5 секунд:
# обновляем каждые 5 секунд
time.sleep(5)
Чтобы всё заработало, запускаем функцию:
# запускаем программу
main()
Что дальше
На карту можно добавить не только МКС, но и все спутники и космическую технику, координаты которых можно узнать через API. Ещё можно фиксировать их пройденный путь, задать для каждой отдельную иконку с анимацией и добавить вывод экипажа и координат по наведению на каждую.
Этим займёмся в следующий раз.
# добавляем модуль для работы с JSON-форматом
import json
# добавляем модуль для HTTP-запросов
import urllib.request
# добавляем модуль рисования
import turtle
# модуль для использования возможностей операционной системы
import os
# добавляем модуль для работы со временем
import time
# добавляем модуль для открытия URL-адресов по умолчанию
import webbrowser
# импортируем типы данных для аннотации типов
from typing import Dict, List, Any
from http.client import HTTPResponse
# пишем основную и единственную функцию
def main():
# задаём адрес для запроса списка космонавтов
url: str = 'http://api.open-notify.org/astros.json'
# открываем URL, используя urllib.request
res: HTTPResponse = urllib.request.urlopen(url)
# загружаем и читаем json-файл
result: Dict[str, Any] = json.loads(res.read())
# создаём текстовый файл с именами членов экипажа
# открываем файл для записи
with open('iss.txt', 'w') as file:
# добавляем запись
file.write(f'В настоящий момент на МКС {str(result["number"])} космонавтов:\n\n')
print('В настоящий момент на МКС ' + str(result["number"]) + ' космонавтов:\n')
# получаем список имён космонавтов
people: List[Dict[str, str]] = result['people']
# для каждого человека в списке выводим его имя
for person in people:
file.write(person['name'] + '\n')
print(person['name'] )
# создаём главное окно для графической работы
screen: turtle.Screen = turtle.Screen()
# устанавливаем размеры окна
screen.setup(1280, 720)
# устанавливаем систему координат для экрана, аналогичную с координатами Земли
screen.setworldcoordinates(-180, -90, 180, 90)
# загружааем изображение карты мира из файла
screen.bgpic('map.gif')
# загружаем изображение станции из файла
screen.register_shape('iss.gif')
# присваиваем переменной iss значение объекта Turtle
iss = turtle.Turtle()
# придаём переменной вид изображения станции из файла
iss.shape('iss.gif')
# выключаем функцию рисования следа от объекта Turtle()
iss.penup()
# запускаем бесконечный цикл
while True:
# прописываес адрес для запроса о текущем положении МКС
url: str = 'http://api.open-notify.org/iss-now.json'
# объявляем переменную и сохраняем в неё ответ
res: HTTPResponse = urllib.request.urlopen(url)
# переводим ответ в JSON и читаем
result: Dict[str, Dict[str, str]] = json.loads(res.read())
# извлекаем локацию станции
location: Dict[str, str] = result['iss_position']
# извлекаем только широту станции
lat: float = float(location['latitude'])
# извлекаем только долготу станции
lon: float = float(location['longitude'])
# Получение текущего времени
current_time: str = time.strftime("%Y-%m-%d %H:%M:%S")
# Вывод на экран
print("\nДата и время:", current_time)
# выводим широту и долготу в терминал
print(f'Широта: {lat}')
print(f'Долгота: {lon}')
# обновляем локация станции на карте
iss.goto(lon, lat)
# обновляем каждые 5 секунд
time.sleep(5)
# запускаем программу
main()