Arduino

Итоговый мини-проект: многофункциональная метеостанция-робот на основе нового набора

1 просмотров

Введение

В заключительной статье цикла и всего расширенного плана статей собираем итоговый проект — гибрид метеостанции и простого мобильного робота, объединяющий значимую часть модулей нового набора: датчики окружающей среды (почвенный, фоторезистор), движение и навигация (гироскоп, ИК-обход препятствий), управление (PS2-геймпад), индикация (RGB-светодиод, зуммер), и логирование (SD-карта).

Концепция

Архитектура проекта: мобильная платформа с двумя моторами, управляемая либо автономно (обход препятствий через ИК-модули), либо вручную через PS2-геймпад (переключение между режимами по нажатию кнопки), несущая на себе датчики окружающей среды (почвенный модуль и фоторезистор, для измерения условий в разных точках при движении по территории, например теплицы), стабилизируемая или хотя бы информируемая о наклоне через гироскопический модуль , сигнализирующая о критичных событиях (препятствие, низкий уровень почвенной влажности в текущей точке) через RGB-светодиод и зуммер, и логирующая все собранные данные на SD-карту для последующего анализа маршрута и собранных показаний.

Пример кода

// Главный цикл, объединяющий все подсистемы проекта
#include <SD.h>
#include <PS2X_lib.h>

enum class OperatingMode { AUTONOMOUS, MANUAL };
OperatingMode currentMode = OperatingMode::AUTONOMOUS;

void setup() {
    Serial.begin(9600);
    setupObstacleAvoidance();  
    setupEncoder();             // не используется в этом проекте, но пины зарезервированы для одометрии
    SD.begin(SD_CS_PIN);         
    ps2x.config_gamepad(PS2_CLK_PIN, PS2_CMD_PIN, PS2_SEL_PIN, PS2_DAT_PIN, true, true); // статья 391

    if (!SD.exists("survey.csv")) {
        File f = SD.open("survey.csv", FILE_WRITE);
        f.println("timestamp_ms,soil_moisture,light_level,tilt_angle");
        f.close();
    }
}

void loop() {
    ps2x.read_gamepad();

    // Переключение режима по кнопке START
    if (ps2x.ButtonPressed(PSB_START)) {
        currentMode = (currentMode == OperatingMode::AUTONOMOUS)
                      ? OperatingMode::MANUAL : OperatingMode::AUTONOMOUS;
        setRgbColor(currentMode == OperatingMode::AUTONOMOUS ? 0 : 255, 0, currentMode == OperatingMode::AUTONOMOUS ? 255 : 0);
    }

    if (currentMode == OperatingMode::MANUAL) {
        controlRobotFromJoystick(); 
    } else {
        RobotAction action = decideNextAction(); 
        executeRobotAction(action);
    }

    // Периодический сбор и логирование данных окружающей среды независимо от режима движения
    static unsigned long lastSurveyTime = 0;
    if (millis() - lastSurveyTime > 5000) {
        int soilMoisture = analogRead(SOIL_ANALOG_PIN);
        int lightLevel = analogRead(LIGHT_SENSOR_PIN);
        float tiltAngle = readTiltAngleFromGyro(); // статья 383

        File f = SD.open("survey.csv", FILE_WRITE);
        if (f) {
            f.print(millis()); f.print(",");
            f.print(soilMoisture); f.print(",");
            f.print(lightLevel); f.print(",");
            f.println(tiltAngle);
            f.close();
        }

        // Сигнализация о критичных показаниях
        if (soilMoisture > 700) { // высокое сырое значение АЦП = сухая почва
            beepActive(200);
        }

        lastSurveyTime = millis();
    }
}

Пояснения к коду

Переключение режима (currentMode) по нажатию кнопки START на геймпаде, с одновременным изменением цвета RGB-индикатора (синий для автономного режима, красный для ручного управления) — практичный паттерн явной, недвусмысленной визуальной обратной связи о текущем режиме работы устройства, особенно важный для робота, который может быстро менять поведение в зависимости от режима, и оператору важно быстро, без долгого изучения, понимать, в каком режиме робот находится прямо сейчас. Периодическое логирование (раз в 5 секунд, независимо от режима движения) показывает архитектурное разделение между логикой движения/управления (выполняющейся на каждой итерации цикла максимально быстро) и менее частой, но более затратной по времени операцией записи на SD-карту — оба процесса работают параллельно в рамках одного цикла loop(), но с разной эффективной частотой благодаря проверке millis().

Подводные камни

  • Выполнение операции записи на SD-карту (потенциально занимающей заметное время, особенно при проблемах с конкретной картой) непосредственно в основном цикле управления движением робота, без учёта того, что это может временно «подвесить» реакцию на ИК-датчики препятствий именно в момент записи — для робота, движущегося в автономном режиме среди препятствий, даже относительно короткая задержка операции записи на карту может оказаться критичной, если в этот момент впереди появилось препятствие, реакция на которое будет отложена; для более надёжного поведения стоит либо логировать данные ещё реже, либо явно проверять датчики препятствий непосредственно перед и после операции записи, а не полагаться только на общую частоту цикла.
  • Конфликт пинов между несколькими одновременно используемыми SPI-устройствами (SD-карта, и потенциально другие SPI-периферийные устройства проекта) без явного, продуманного распределения отдельных Chip Select пинов для каждого устройства при сохранении общих линий SPI (MOSI/MISO/SCK) — для проекта с несколькими SPI-устройствами одновременно (что для итогового проекта, объединяющего множество модулей, особенно вероятно) важно тщательно спланировать распределение пинов заранее, до начала физической сборки, а не выяснять конфликты уже после того, как все компоненты физически распаяны.
  • Недостаточное тестирование автономного режима обхода препятствий перед переходом на полностью автономную работу без присутствия оператора, особенно с учётом дополнительной массы и центра тяжести от всех добавленных модулей (SD-карта, дополнительные датчики, батарея), отличающихся от более простых, ранее протестированных конфигураций робота из предыдущих циклов — изменение физических характеристик платформы (вес, баланс) может повлиять на манёвренность и реальную эффективность обхода препятствий по сравнению с более лёгкой, ранее протестированной версией, и итоговая, нагруженная множеством модулей конфигурация должна быть протестирована заново, а не предполагаться рабочей просто на основании того, что отдельные компоненты были по отдельности проверены ранее.
  • Отсутствие явного ограничения на размер файла survey.csv при долговременной, продолжительной работе устройства — для проекта, предназначенного для длительного автономного мониторинга (например, обхода большой теплицы в течение многих часов или дней), стоит заранее предусмотреть либо ротацию файлов, либо альтернативный, более компактный формат хранения данных, чтобы длительная эксплуатация не привела к неконтролируемому росту единственного файла лога.