- Глава 1. Общая информация и ссылки
- Глава 2. Архитектура платы
- Глава 3. Тесты моторов
- Глава 4. Библиотека
- Глава 5. Движение по энкодерам
- Глава 6. Веб-интерфейс
- Глава 7. Датчик линии
- Визуализаторы
Этот репозиторий будет хранить эксперименты с контроллером MATRIX R4 / Mini R4: движение по энкодерам, повороты, работа с IMU, движение по линии и тесты датчиков.
MATRIX R4 / Mini R4 — робототехнический контроллер MATRIX Robotics на базе Arduino UNO R4 WiFi. Он программируется из Arduino IDE обычными .ino sketch-файлами через библиотеку MatrixMiniR4.
Изображение: MATRIX Robotics, страница MATRIX Mini R4 Controller Set.
Кратко по возможностям контроллера:
- 4 порта DC-моторов с поддержкой энкодеров:
M1,M2,M3,M4; - 4 RC-servo выхода:
RC1,RC2,RC3,RC4; - встроенный 6-осевой IMU/гиро;
- встроенный OLED-дисплей
128x32; - 2 кнопки:
BTN_UP,BTN_DOWN; - Wi-Fi и Bluetooth за счет базы Arduino UNO R4 WiFi;
- 3 аналоговых порта:
A1,A2,A3; - 4 I2C-порта плюс
I2C0наA3; - мониторинг напряжения питания через
MiniR4.PWR.
- MatrixMiniR4 Arduino Library — официальная Arduino-библиотека.
- MATRIX Programming API Docs — портал документации MATRIX.
- MatrixMiniR4 Class Reference — API объекта
MiniR4. - MATRIX Products Documentation — общий репозиторий документации MATRIX.
- MS-018 MATRIX Line Tracer 10CH — страница датчика линии.
- Arduino UNO R4 WiFi Docs — официальная документация Arduino по базе UNO R4 WiFi.
MATRIX Mini R4 устроен как двухпроцессорный контроллер. Верхний уровень — это Arduino UNO R4 WiFi, который выполняет пользовательский sketch, работает с Arduino API, Wi-Fi/Bluetooth и частью внешних портов. Нижний уровень — STM32F103, который используется как сопроцессор для задач реального времени: моторы, энкодеры, сервоприводы, IMU и служебные данные питания.
Официальную электрическую схему платы не нашел в открытых ресурсах. Ниже логическая схема по официальному описанию MATRIX и структуре библиотеки MatrixMiniR4.
flowchart TB
sketch["Arduino sketch (.ino)"] --> api["MatrixMiniR4 API"]
api --> r4["Arduino UNO R4 WiFi core"]
r4 --> wireless["Wi-Fi / Bluetooth"]
r4 --> usb["USB-C upload / Serial"]
r4 --> i2c0["Wire / I2C0 on A3"]
r4 --> i2c1["Wire1"]
r4 <--> lower["STM32F103 lower MCU"]
i2c0 --> ms018["MS-018 Line Tracer 10CH"]
i2c1 --> oled["OLED 128x32, address 0x3D"]
i2c1 --> exti2c["I2C1-I2C4 external ports"]
lower --> motorPorts["M1-M4 motor ports"]
lower --> encoders["Encoder feedback"]
lower --> servos["RC1-RC4 servo outputs"]
lower --> imu["Built-in 6-axis IMU"]
lower --> buttons["BTN_UP / BTN_DOWN"]
lower --> power["Battery voltage monitor"]
На этом уровне выполняется пользовательский код. Когда sketch вызывает MiniR4.begin(), библиотека инициализирует объект MiniR4, OLED, порты, связь с нижним контроллером и встроенные модули.
Этот уровень отвечает за:
- выполнение
.inoпрограммы; - работу с USB-C загрузкой и Serial;
- Wi-Fi/Bluetooth возможности Arduino UNO R4 WiFi;
- OLED
128x32черезWire1; - внешние I2C-устройства через
I2C0/I2C1-I2C4; - analog/digital порты, которые проброшены на Arduino-сторону.
STM32F103 работает как отдельный контроллер реального времени. В библиотеке он доступен через внутренний слой MMLower: пользователь обычно не вызывает его напрямую, а работает через удобные классы MiniR4.M1, MiniR4.M2, MiniR4.Motion, MiniR4.PWR и так далее.
Через этот нижний уровень идут:
- команды скорости/мощности DC-моторов;
- чтение энкодеров;
- торможение моторов;
- управление RC-servo;
- чтение кнопок;
- чтение IMU;
- чтение напряжения питания.
В локальном коде библиотеки связь с нижним контроллером создается как MMLower mmL(8, 9, 57600), то есть через внутренний serial-протокол библиотеки.
Вызов вида:
MiniR4.M1.setSpeed(30);не управляет PWM напрямую с Arduino-процессора. Он отправляет команду в нижний STM32, а тот уже управляет моторным портом. Поэтому поведение setSpeed(), setPower(), тормоза и энкодеров зависит не только от sketch, но и от прошивки нижнего контроллера.
В наших тестах используются энкодерные TT-моторы MATRIX, подключенные к портам M1 и M2. Для документации важны две разные вещи: паспортные параметры мотора и реальные измерения на конкретном роботе. Паспорт дает ориентир, но код движения нужно настраивать по реальной скорости колес, потому что батарея, вес, трение, покрытие и колеса меняют результат.
Официальная страница MATRIX TT Encoder Motor with metal gear box указывает модель METT-MG001 и такие свойства:
- металлический редуктор и два выходных вала;
- встроенный энкодер с A/B-фазами;
- измерение скорости, угла и направления вращения;
- поддержка точного движения на расстояние, регулирования скорости и синхронизации моторов;
- разъем
PH2.0-6P.
Для обычной версии MATRIX TT Motor with metal gear box MATRIX указывает скорость редуктора около 130 rpm при 4.5V. На странице энкодерной версии эта цифра в текстовом описании не продублирована, поэтому для METT-MG001 используем ее только как ориентир по семейству TT-моторов, а не как точный предел для нашего робота.
Тестовый sketch подавал на левый и правый мотор одинаковую команду от 0 до 100 с шагом 5, считывал энкодеры и считал скорость вращения колес. Питание во время теста было примерно 8.04V в начале и 7.91V в конце.
Исходные данные:
- motor_speed_data.csv — сырые значения
deg/s; - motor_speed_data_mm.csv — пересчет в
mm/sдля колеса65 mmи вrpm.
Графики строятся скриптом plot_motor_speed.py.
Для графиков используются два файла:
MatrixMotorSpeedGraphTest/MatrixMotorSpeedGraphTest.ino— sketch на роботе;plot_motor_speed.py— Python-скрипт на компьютере.
MatrixMotorSpeedGraphTest прогоняет моторы M1 и M2 по командам от 0 до 100 с шагом 5. Для каждой точки он:
- задает одинаковую скорость левому и правому мотору;
- ждет стабилизацию;
- сбрасывает энкодеры;
- измеряет, сколько градусов колеса прошли за фиксированное время;
- печатает строку CSV в
Serial.
Формат Serial-вывода:
power,left_deg_s,right_deg_s,avg_deg_s,battery_v
plot_motor_speed.py читает эти строки с COM-порта или берет уже сохраненный CSV. Потом он:
- сохраняет расширенный CSV в
data/motor_speed_data_mm.csv; - пересчитывает
deg/sвmm/sчерез диаметр колеса65 mm; - пересчитывает
deg/sвrpmпо формулеrpm = deg/s / 6; - строит три PNG-графика в
assets/.
Запуск с живого робота:
python plot_motor_speed.py --port COM8Запуск по уже сохраненным данным:
python plot_motor_speed.py --input-csv data\motor_speed_data.csvЗависимости Python:
python -m pip install -r requirements.txtДля запуска по готовому CSV нужен только matplotlib; pyserial нужен для чтения данных с COM-порта.
Перед измерением нужно загрузить MatrixMotorSpeedGraphTest, открыть порт только в одном месте и нажать кнопку на роботе. Arduino Serial Monitor при этом должен быть закрыт, иначе Python не сможет открыть COM-порт.
deg/s удобен для энкодеров: это прямая скорость вращения оси колеса. Пересчет в обороты простой:
rpm = deg/s / 6
Например, 1025.7 deg/s при команде 100 — это примерно 171 rpm.
mm/s полезнее для движения по расстоянию. Пересчет сделан для диаметра колеса 65 mm:
mm/s = deg/s * pi * 65 / 360
По нашим данным команда 100 дает около 582 mm/s на холостом тесте. На полу под нагрузкой реальная скорость будет ниже.
Короткая сводка по точкам:
| Команда | Среднее, deg/s | Среднее, rpm | Среднее, mm/s |
|---|---|---|---|
| 50 | 513.0 | 85.5 | 291.0 |
| 80 | 822.3 | 137.1 | 466.4 |
| 100 | 1025.7 | 171.0 | 581.8 |
Команда setSpeed(100) — это не гарантированные 100% физической скорости и не паспортная скорость мотора. Это верхняя команда контроллера. Для нашего робота при 2S батарее и колесах 65 mm практический потолок на холостом тесте получился около 170 rpm или 580 mm/s.
Поэтому в движении лучше задавать целевую скорость в mm/s, а внутри кода переводить ее в команду мотора по измеренной таблице. Если робот едет по полу, таблицу нужно уточнить уже под нагрузкой.
Основная библиотека для платы — MatrixMiniR4. В sketch она подключается так:
#include <MatrixMiniR4.h>Почти вся работа идет через глобальный объект MiniR4. Минимальный старт:
void setup() {
MiniR4.begin();
}| Объект | Что делает | Частые методы |
|---|---|---|
MiniR4.M1 ... MiniR4.M4 |
DC-моторы с энкодерами | setSpeed(), setPower(), getDegrees(), resetCounter(), setBrake() |
MiniR4.DriveDC |
готовое управление парой моторов | begin(), Move(), MoveSync(), MoveGyro(), TurnGyro(), brake() |
MiniR4.RC1 ... MiniR4.RC4 |
RC-servo выходы | setAngle() |
MiniR4.Motion |
встроенный IMU/гиро | getGyro(), getAccel(), getEuler(), resetIMUValues() |
MiniR4.PWR |
питание и батарея | setBattCell(), getBattVoltage(), getBattPercentage() |
MiniR4.OLED |
OLED 128x32 |
clearDisplay(), setCursor(), print(), display() |
MiniR4.BTN_UP, MiniR4.BTN_DOWN |
две кнопки на плате | getState() |
MiniR4.LED |
встроенные RGB-светодиоды | setColor(), setBrightness() |
MiniR4.Buzzer |
встроенный buzzer | Tone(), NoTone() |
MiniR4.D1 ... MiniR4.D4 |
digital/PWM порты | getL(), getR(), setL(), setR(), setPWML(), setPWMR() |
MiniR4.A1 ... MiniR4.A3 |
analog порты | getAIL(), getAIR() |
MiniR4.I2C0 ... MiniR4.I2C4 |
I2C-порты | используются для MATRIX I2C-датчиков |
MiniR4.Uart / Serial1 |
UART-порт | обычный Arduino UART |
MiniR4.WiFi |
Wi-Fi через UNO R4 WiFi | API совместим с WiFiS3 |
setSpeed() — регулируемая скорость через нижний STM32. Это не физические mm/s, а команда от -100 до 100, которую контроллер пытается удерживать по энкодеру.
MiniR4.M1.setSpeed(30);
MiniR4.M2.setSpeed(30);setPower() — более прямое управление мощностью/PWM без удержания скорости:
MiniR4.M1.setPower(30);
MiniR4.M2.setPower(30);Энкодеры:
MiniR4.M1.resetCounter();
long deg = MiniR4.M1.getDegrees();DriveDC — встроенный высокоуровневый слой для двухмоторной базы. Он умеет движение двумя моторами, синхронизацию, движение по гиро и поворот по гиро.
MiniR4.DriveDC.begin(1, 2, true, false);
MiniR4.DriveDC.MoveSync(30, 30);
MiniR4.DriveDC.brake(true);В библиотеке есть PID-настройки:
MiniR4.DriveDC.setMoveSyncPID(kp, ki, kd);
MiniR4.DriveDC.setMoveGyroPID(kp, ki, kd);
MiniR4.DriveDC.setTurnGyroPID(kp, ki, kd);Для угла поворота обычно нужен Yaw:
MiniR4.Motion.resetIMUValues();
double yaw = MiniR4.Motion.getEuler(MiniR4Motion::AxisType::Yaw);Для угловой скорости вокруг вертикальной оси:
double zRate = MiniR4.Motion.getGyro(MiniR4Motion::AxisType::Z);Официальный диапазон входного питания MATRIX Mini R4: 6V ... 24V. Для экспериментов в этом репозитории используется 2S аккумулятор: примерно 6.0V ... 8.4V.
Для 2S аккумулятора:
MiniR4.PWR.setBattCell(2);
float v = MiniR4.PWR.getBattVoltage();setBattCell(2) не меняет питание моторов. Он задает пороги мониторинга батареи в нижнем STM32: полный заряд 8.4V, номинал 7.4V, нижний порог 6.8V.
Входное напряжение аккумулятора идет на силовую часть платы и влияет на моторы. setSpeed() и setPower() задают команду контроллеру мотора, но реальная скорость и тяга зависят от напряжения батареи, просадки под нагрузкой, веса робота и трения. Поэтому графики из главы 3 привязаны к конкретному питанию теста.
Для MS-018 в библиотеке есть MatrixLineTracer. Он дает сырые значения 10 каналов и готовую ошибку линии.
MiniR4.I2C0.MXLineTracer.begin();
uint8_t sensors[10];
MiniR4.I2C0.MXLineTracer.getAllSensors(sensors);
float error = MiniR4.I2C0.MXLineTracer.getError();Для PID по линии удобнее читать датчик часто и держать цикл простым: датчик → ошибка → поправка моторов.
В этой главе лежат несколько версий кода движения по энкодерам для двухмоторной базы на M1 и M2. В них нет DriveDC, гиро, Serial и библиотечных поворотов. Только свои функции движения по расстоянию и поворота по энкодерам.
Текущие варианты:
MatrixEncoderMotionV0/MatrixEncoderMotionV0.ino— упрощенный профиль: расстояние напрямую превращается в командуsetSpeedчерезsmoothstep, безmm/s, ускорения и jerk;MatrixEncoderMotionV1/MatrixEncoderMotionV1.ino— старая версия профиля сtargetSpeed,targetAccel,sCurveStopDistance()и переключением разгон/торможение;MatrixEncoderMotionV2/MatrixEncoderMotionV2.ino— новая версия с velocity governor: разрешенная скорость считается по оставшемуся расстоянию, затем профиль плавно догоняется через accel/jerk;MatrixEncoderMotionTest/MatrixEncoderMotionTest.ino— рабочий тестовый sketch, оставлен как промежуточная версия.
Для сравнения профилей без робота:
Основная идея: пользователь задает расстояние в mm или угол в градусах, а код сам считает профиль скорости, синхронизирует моторы по энкодерам и останавливается по фактической остановке колес.
Ключевые константы:
| Константа | Значение | Зачем нужна |
|---|---|---|
BATTERY_CELLS |
2 |
настройка контроля 2S аккумулятора |
WHEEL_DIAMETER_MM |
65.0 |
диаметр колеса для пересчета энкодеров в миллиметры |
WHEEL_BASE_MM |
142.0 |
расстояние между колесами для расчета поворота |
LEFT_MOTOR_REVERSED |
false |
направление левого мотора |
RIGHT_MOTOR_REVERSED |
true |
направление правого мотора |
DEFAULT_DRIVE_ACCEL_MM_S2 |
2000.0 |
ускорение по умолчанию для прямого движения |
DEFAULT_DRIVE_JERK_MM_S3 |
35000.0 |
ограничение рывка для плавного старта/торможения |
DEFAULT_TURN_ACCEL_DEG_S2 |
720.0 |
ускорение поворота |
DEFAULT_TURN_JERK_DEG_S3 |
10000.0 |
рывок поворота |
DRIVE_SYNC_KP |
0.35 |
сила синхронизации левого и правого энкодера |
В setup() плата инициализируется, включается режим 2S батареи и задаются направления моторов:
MiniR4.begin();
MiniR4.PWR.setBattCell(BATTERY_CELLS);
MiniR4.M1.setReverse(LEFT_MOTOR_REVERSED);
MiniR4.M2.setReverse(RIGHT_MOTOR_REVERSED);В loop() стоит защита static bool testDone, поэтому тест выполняется один раз. Перед стартом на OLED показывается напряжение батареи, движение начинается только после нажатия BTN_UP или BTN_DOWN.
Текущий тестовый сценарий:
driveMm(500, 300);
turnDeg(90, 180);То есть робот проезжает 500 mm, потом поворачивает на 90 градусов по энкодерам.
Главная функция:
driveMm(distanceMm, maxSpeedMmS);
driveMm(distanceMm, maxSpeedMmS, accelMmS2);
driveMm(distanceMm, maxSpeedMmS, accelMmS2, jerkMmS3);Примеры:
driveMm(500, 300); // вперед 500 mm, цель 300 mm/s
driveMm(-500, 250); // назад 500 mm, цель 250 mm/s
driveMm(1000, 500, 600); // вперед 1000 mm, ускорение 600 mm/s^2Внутри driveMm() просто вызывает общий движок:
moveTankMm(distanceMm, distanceMm, speed, accel, jerk);Алгоритм moveTankMm():
- Сбрасывает энкодеры
M1иM2. - Переводит градусы энкодера в миллиметры через
WHEEL_DIAMETER_MM. - Считает пройденную дистанцию по среднему значению левого и правого колеса.
- Ведет целевую скорость через S-curve: ускорение меняется не резко, а через
jerk. - По фактической скорости колес подбирает команду мотора
0..100. - Синхронизирует колеса: если левое ушло дальше правого, левое замедляется, правое ускоряется.
- В конце вызывает
smartStopDrive().
Синхронизация простая:
syncErrorMm = leftMm - rightMm;
syncCorrection = syncErrorMm * DRIVE_SYNC_KP;Если робот виляет, первым делом меняется DRIVE_SYNC_KP. Если поправка слишком большая — робот дергается. Если маленькая — хуже держит прямую.
В этом sketch скорость не прыгает сразу к целевой. Код отдельно хранит:
targetSpeed— текущая целевая скорость;targetAccel— текущее целевое ускорение;jerkMmS3— насколько быстро можно менять ускорение.
Упрощенно:
targetAccel = approachFloat(targetAccel, desiredAccel, jerkMmS3 * dtS);
targetSpeed += targetAccel * dtS;Это убирает резкий старт. Чем меньше jerkMmS3, тем мягче начало и торможение. Чем больше jerkMmS3, тем ближе поведение к обычной трапеции.
Функция:
turnDeg(angleDeg, maxAngularSpeedDegS);
turnDeg(angleDeg, maxAngularSpeedDegS, accelDegS2);
turnDeg(angleDeg, maxAngularSpeedDegS, accelDegS2, jerkDegS3);Она считает, сколько миллиметров должно пройти каждое колесо:
wheelDistance = wheelBase * pi * abs(angle) / 360
Потом вызывает moveTankMm() с противоположными направлениями колес:
moveTankMm(+wheelDistance, -wheelDistance, ...);Для отрицательного угла направления меняются местами.
smartStopDrive() не просто делает delay(1000). Она:
- отправляет моторам
setSpeed(0); - включает тормоз;
- читает энкодеры;
- ждет, пока оба колеса перестанут менять градусы в течение
DRIVE.stopStableMs; - выходит не позже
DRIVE.stopMaxWaitMs.
Это нужно из-за инерции: мотор может получить 0, но колесо еще чуть докручивается.
| Симптом | Что менять |
|---|---|
| резкий старт | уменьшить DEFAULT_DRIVE_JERK_MM_S3 |
| слишком вялый старт | увеличить DEFAULT_DRIVE_ACCEL_MM_S2 или DEFAULT_DRIVE_JERK_MM_S3 |
| не держит прямую | увеличить DRIVE_SYNC_KP |
| дергается при синхронизации | уменьшить DRIVE_SYNC_KP |
| расстояние неверное | уточнить WHEEL_DIAMETER_MM |
| угол поворота по энкодерам неверный | уточнить WHEEL_BASE_MM |
Sketch MatrixWifiTurnPowerTest показывает, что MATRIX R4 можно использовать не только как автономный робот, но и как маленький Wi-Fi сервер с веб-пультом. Arduino UNO R4 WiFi подключается к домашней сети, запускает HTTP-сервер на порту 80, показывает IP на OLED, а управление открывается из браузера.
Файл sketch: MatrixWifiTurnPowerTest/MatrixWifiTurnPowerTest.ino.
После загрузки sketch:
- робот подключается к Wi-Fi;
- на OLED появляется IP-адрес;
- с телефона или компьютера в той же сети открывается
http://IP_РОБОТА/; - браузер показывает кнопки управления поворотом;
- робот отдает статус в JSON: энкодеры, yaw, скорость колес, напряжение батареи.
Это не загрузка прошивки по Wi-Fi. Это веб-интерфейс управления и телеметрии уже запущенного sketch.
Перед загрузкой нужно прописать сеть:
const char WIFI_SSID[] = "YOUR_WIFI_SSID";
const char WIFI_PASS[] = "YOUR_WIFI_PASSWORD";Пароль не стоит хранить в публичном репозитории. В текущем sketch оставлены заглушки.
Веб-страница отправляет простые HTTP-запросы:
| URL | Что делает |
|---|---|
/ |
отдает HTML-страницу пульта |
/set?p=100 |
задает команду поворота |
/step?d=10 |
меняет команду на шаг |
/stop |
останавливает моторы |
/status |
возвращает JSON-статус |
Команда p сейчас работает в диапазоне от -1000 до 1000. В sketch это сделано через:
mmL.SetDCMotorSpeedRange(1, 0, SPEED_RANGE_MAX);
mmL.SetDCMotorSpeedRange(2, 0, SPEED_RANGE_MAX);После этого поворот задается через MiniR4.M1.setSpeed() и MiniR4.M2.setSpeed(). Положительное значение крутит робота в одну сторону, отрицательное — в другую.
Даже при одинаковой команде моторы могут вращаться по-разному. Поэтому sketch сравнивает энкодеры и подправляет команды:
correction = (leftDeg - rightDeg) * TURN_SYNC_KP;
leftPower = basePower - correction;
rightPower = basePower + correction;Это не точный поворот на заданный угол. Это ручной веб-тест минимальной скорости, синхронизации и поведения моторов при разных командах.
/status возвращает примерно такие поля:
| Поле | Значение |
|---|---|
power |
текущая команда поворота |
yaw |
текущий yaw IMU |
m1, m2 |
градусы энкодеров |
lds, rds |
скорость колес в deg/s |
lms, rms |
скорость колес в mm/s |
left, right |
фактические команды левого и правого мотора |
battery |
напряжение батареи |
Страница обновляет статус каждые 500 ms, поэтому можно менять команду и сразу видеть, как реагируют энкодеры.
В sketch есть три простые защиты:
- кнопки
BTN_UPиBTN_DOWNсразу вызываютstopMotors(); - если команды не приходят дольше
COMMAND_TIMEOUT_MS, моторы останавливаются; - при потере Wi-Fi или ошибке подключения моторы остаются остановленными.
Ограничения тоже важны:
- веб-сервер без пароля и авторизации;
- использовать только в своей локальной сети;
- не оставлять робота на столе с колесами, которые могут зацепиться;
- для публичного репозитория не коммитить настоящий Wi-Fi пароль.
Для движения по линии используется MS-018 MATRIX Line Tracer 10CH. Это 10-канальный датчик линии, который подключается к контроллеру по I2C и подходит для PID-руления по черной линии.
Изображение: MATRIX Robotics, страница MS-018 MATRIX Line Tracer 10CH.
Кратко по официальному описанию:
- 10 каналов отражения для более точного определения положения линии;
- I2C-передача данных в контроллер;
- расчет
Error— смещение линии относительно центра датчика; - расчет
Line Width— ширина/количество активных сенсоров; - определение перекрестков: Left, Right, T-junction, Cross-junction;
- хранение
Last Sensorперед потерей линии; - встроенная калибровка кнопкой
CALи синий индикатор; - питание
3.3V ~ 5V; - оптимизация для слабого освещения.
На MATRIX R4 текущая версия датчика используется через I2C0, то есть порт A3:
MiniR4.I2C0.MXLineTracer.begin();
MiniR4.I2C0.MXLineTracer.getAllSensors(sensors);Файл sketch: MatrixMS018JSTTest/MatrixMS018JSTTest.ino.
Это тест подключения и чтения датчика. Он:
- запускает MS-018 на
I2C0; - читает 10 сырых каналов;
- считает ошибку линии
-4.5 ... 4.5; - показывает на OLED
Error,Line Width,Last Sensor,Junction Type; - рисует 10 столбиков по значениям сенсоров.
Этот sketch нужен первым: если он не видит линию или датчик, PID-код трогать рано.
Файл sketch: MatrixLineFollowPIDTest/MatrixLineFollowPIDTest.ino.
Это классическое движение по линии без ограничения по расстоянию. Логика:
- кнопка запускает движение;
- каждые
20 msчитается датчик; - ошибка линии идет в PID;
- PID дает поправку к левому и правому мотору;
- при потере линии робот тормозит и возвращается в ожидание;
- кнопка во время движения работает как stop.
Главные настройки:
const int BASE_SPEED = 30;
const int MAX_SPEED = 55;
const float KP = 7.0;
const float KI = 0.0;
const float KD = 18.0;
const int STEERING_SIGN = 1;Если робот уезжает от линии, первым делом поменять STEERING_SIGN на -1.
Файл sketch: MatrixLineDistanceTest/MatrixLineDistanceTest.ino.
Это движение по линии на заданное расстояние. Он объединяет:
- чтение MS-018;
- PID-поправку по линии;
- энкодеры
M1/M2; - S-curve разгон и торможение;
- остановку по расстоянию в миллиметрах.
Текущий тест:
const long TEST_DISTANCE_MM = 1000;
const int LINE_MAX_SPEED_MM_S = 250;Результат на OLED:
DONE— расстояние пройдено;LOST— линия потеряна;STOP— остановлено кнопкой;TIME— вышел timeout.
Этот sketch полезен для задач, где робот должен не просто ехать по линии, а проехать конкретный участок трассы.
Для GitHub Pages добавлена стартовая страница index.html. Через нее можно открыть оба визуализатора:
- визуализатор driveMm — прямое движение по энкодерам, сравнение
V0,V1,V2; - визуализатор turnDeg — поворот по энкодерам, пересчет угла робота в путь колес через
WHEEL_BASE_MM.
Эти страницы статические, поэтому их можно открывать локально из файла или через GitHub Pages без сервера.




