Полная миссия (main_full) ========================= «Полная миссия» — финальная прошивка кубсата. Она объединяет всё, что проверялось по отдельности на предыдущих страницах, и добавляет несколько служебных вещей, которых не было в учебных скетчах: - **самотест при включении** со звуковыми сигналами OK/FAIL для каждой подсистемы; - **CSV-лог на microSD** с 24 колонками — это «чёрный ящик» миссии; - **бинарный пакет 32 байта** ``TboyAirPkt`` — компактный, чтобы пройти через ограничение nRF24L01+; - **WS2812 LED-лента** показывает количество спутников и качество GPS-фикса цветом; - **зуммер** раз в минуту бипает «я жив». .. note:: Перед запуском полной миссии стоит пройти все модульные тесты (от :doc:`coding-first-check` до :doc:`coding-radio`). Полная прошивка не сообщает причину ошибки в виде текста — только звуковыми сигналами. Если что-то «молчит», возвращайтесь к модульным тестам. Прошивка кубсата ---------------- .. literalinclude:: ../../../examples/main_full/main_full_arduino/main_full_arduino.ino :language: cpp :caption: examples/main_full/main_full_arduino/main_full_arduino.ino Скетч объёмный (~860 строк) — но логически делится на четыре куска: - инициализация всех модулей (с пропуском не отозвавшихся); - ``runPowerOnSelfTest()`` — звуковой самотест; - основной ``loop()`` с тремя независимыми таймерами: - ``DT_LED_MS = 200`` мс — обновление LED-ленты; - ``DT_LOG_MS = 1000`` мс — чтение всех сенсоров → запись в CSV → отправка пакета по nRF; - ``DT_BEEP_MS = 60000`` мс — бип «всё нормально». Самотест при включении ---------------------- Сразу после ``setup()`` лента WS2812 загорается **сплошным белым** на всё время самотеста. Зуммер по очереди сообщает результат инициализации: .. list-table:: :header-rows: 1 :widths: 30 35 35 * - Подсистема - 1 короткий писк (OK) - 2 коротких писка (FAIL) * - nRF24L01+ - модуль ответил - не отвечает / не питание 3.3 В * - GPS - есть валидные NMEA-предложения - провод TX не подключён или GPS молчит * - SD-карта - инициализирована - не вставлена / не FAT32 / не отвечает После всех трёх — **три коротких писка подряд** = «самотест завершён», лента гаснет, начинается основной цикл. .. note:: GPS на самотесте проверяется только на наличие потока NMEA — наличие ``fix`` (реального позиционирования) тут не требуется, иначе на полу в помещении кубсат «никогда не запустится». Цикл миссии: 1 раз в секунду ---------------------------- Каждую секунду выполняется ``sampleAllAndLog()``: 1. Считать акселерометр и гироскоп (MPU); 2. Считать BME280 → температура, давление, влажность; 3. Прокинуть температуру и влажность в CCS811 для коррекции (это улучшает eCO2/TVOC); 4. Считать CCS811 → eCO2, TVOC; 5. Записать строку в ``TBOY.CSV`` на microSD; 6. Собрать и отправить ``TboyAirPkt`` по nRF. Параллельно с этим: - LED-лента обновляется каждые 200 мс по последним данным GPS; - зуммер «пикает» раз в минуту (``DT_BEEP_MS``). Бинарный пакет ``TboyAirPkt`` (32 байта) ---------------------------------------- Пакет фиксированно 32 байта (требование nRF24L01+ для надёжной работы). Сначала идут «полезные» 22 байта, потом 10 байт резерва на будущие расширения. .. list-table:: :header-rows: 1 :widths: 25 10 15 50 * - Поле - Размер - Тип - Содержимое * - ``ver`` - 1 Б - ``uint8`` - версия протокола (сейчас ``2``) * - ``fix`` - 1 Б - ``uint8`` - есть GPS-fix (``0``/``1``) * - ``sats`` - 1 Б - ``uint8`` - спутников в решении * - ``hdop_x10`` - 1 Б - ``uint8`` - HDOP × 10 (clip ``≤ 25.5``) * - ``lat_e7`` - 4 Б - ``int32`` - широта × 10⁷ * - ``lon_e7`` - 4 Б - ``int32`` - долгота × 10⁷ * - ``utc_hhmmss`` - 4 Б - ``uint32`` - UTC в формате ``HHMMSS`` * - ``temp_c10`` - 2 Б - ``int16`` - температура × 10 (°C) * - ``press_hpa10`` - 2 Б - ``uint16`` - давление × 10 (гПа) * - ``alt_m`` - 2 Б - ``int16`` - высота над уровнем моря (м) * - ``res[10]`` - 10 Б - reserved - нулями, для будущих полей Чтобы получить градусы из ``lat_e7``, ``lon_e7`` — поделить на 10⁷. Чтобы получить °C из ``temp_c10`` — поделить на 10. И т.д. CSV-лог ``TBOY.CSV`` -------------------- Если SD-карта инициализирована, лог пишется в файл ``TBOY.CSV`` в корне карты. Если файла нет, скетч сначала пишет шапку: :: ms,ax,ay,az,gx,gy,gz,T_C,P_hPa,H_%,CO2,TVOC, gps_fix,gps_sats,gps_hdop,lat,lon,gps_alt_m, utc_hhmmss,gps_date_ddmmyy,gps_chars,gps_crc_ok, gps_crc_bad,gps_sents_w_fix (в реальности — одна строка без переносов). Колонки: .. list-table:: :header-rows: 1 :widths: 25 15 60 * - Колонка - Единица - Что значит * - ``ms`` - мс - время с момента включения Nano * - ``ax,ay,az`` - LSB - сырые значения акселерометра * - ``gx,gy,gz`` - LSB - сырые значения гироскопа * - ``T_C`` - °C - температура BME280 * - ``P_hPa`` - гПа - давление BME280 * - ``H_%`` - % - влажность BME280 * - ``CO2`` - ppm - eCO₂ (расчётный) от CCS811 * - ``TVOC`` - ppb - летучие органические от CCS811 * - ``gps_fix`` - 0/1 - есть позиционирование * - ``gps_sats`` - шт - спутников в решении * - ``gps_hdop`` - — - HDOP (горизонтальная погрешность) * - ``lat``, ``lon`` - ° - широта, долгота (6 знаков) * - ``gps_alt_m`` - м - высота * - ``utc_hhmmss`` - — - UTC время * - ``gps_date_ddmmyy`` - — - дата (ddmmYYYY) * - ``gps_chars`` - шт - сколько байт NMEA получили (растёт всегда) * - ``gps_crc_ok``/``gps_crc_bad`` - шт - целостность NMEA * - ``gps_sents_w_fix`` - шт - предложений NMEA, в которых был fix Лог можно открыть в Excel/Google Sheets/Python через стандартный импорт CSV. LED-лента: индикация GPS ------------------------ Лента из 8 пикселей WS2812 (``D6``) показывает работу GPS: - **количество горящих пикселей** = ``min(спутников, 8)``; - **цвет всех горящих пикселей** зависит от качества фикса по HDOP: .. list-table:: :header-rows: 1 :widths: 25 25 50 * - HDOP - Цвет - Качество * - нет данных - тускло-синий - GPS не отдал HDOP * - ≥ 5.0 - красный - очень плохо (помехи, мало спутников) * - ≥ 3.8 - оранжево-красный - плохо * - ≥ 3.0 - оранжевый - средне * - ≥ 2.5 - жёлтый - приемлемо * - ≥ 2.0 - жёлто-зелёный - хорошо * - < 2.0 - зелёный - отлично «Если все 8 зелёных» = есть восемь+ спутников и точное решение. «Один синий или красный» = GPS только начал ловить. Зуммер: «я жив» --------------- Раз в минуту короткий писк (~80 мс). Если кубсат вдруг затих — проверьте питание и работу ``main_full`` (мог зависнуть). Прошивка ESP32 (приёмник полной миссии) --------------------------------------- .. literalinclude:: ../../../examples/main_full/main_esp32_nrf_rx_arduino/main_esp32_nrf_rx_arduino.ino :language: cpp :caption: examples/main_full/main_esp32_nrf_rx_arduino/main_esp32_nrf_rx_arduino.ino Отличие от ESP32 в :doc:`coding-base-station`: - здесь ESP32 подключается к **существующей** WiFi-сети (``WIFI_SSID``/``WIFI_PASS`` в начале файла) — не поднимает свою; - декодирует именно ``TboyAirPkt`` 32 байта (с GPS-полями), а не упрощённый 25-байтный пакет; - адрес страницы — IP, который выдаст ваш домашний роутер (виден в Serial Monitor 115200 после старта). Перед заливкой не забудьте поправить SSID/пароль на свой. Чек-лист запуска ---------------- 1. SD-карта вставлена в модуль. 2. Антенна GPS на свободном небе или у окна. 3. Антенна nRF на ESP32 направлена в сторону кубсата (или просто близко). 4. Включаете питание кубсата → лента белая → последовательность писков → лента гаснет, далее работают индикаторы по GPS. 5. На приёмнике ESP32 ловите телеметрию через WiFi. Если самотест выдал FAIL ------------------------ - На каком этапе двойной писк — там и проблема: - ``nRF FAIL`` — :doc:`coding-radio` (диагностика TX, питание 3.3 В); - ``GPS FAIL`` — :doc:`coding-gps` (проводка, отключали ли TX при заливке, виден ли индикатор моргания); - ``SD FAIL`` — :doc:`coding-sd` (формат FAT32, контакт SPI). Подробнее — в :doc:`coding-diagnostics`.