Введение
В заключительной статье цикла и всего расширенного плана статей собираем итоговый проект — гибрид метеостанции и простого мобильного робота, объединяющий значимую часть модулей нового набора: датчики окружающей среды (почвенный, фоторезистор), движение и навигация (гироскоп, ИК-обход препятствий), управление (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при долговременной, продолжительной работе устройства — для проекта, предназначенного для длительного автономного мониторинга (например, обхода большой теплицы в течение многих часов или дней), стоит заранее предусмотреть либо ротацию файлов, либо альтернативный, более компактный формат хранения данных, чтобы длительная эксплуатация не привела к неконтролируемому росту единственного файла лога.