Занятия 1–2. Платформа, ТБ и HAL: фундамент, который переживёт смену железа
Занятия 1–2. Платформа, ТБ и HAL
Цель занятия 1: обучающиеся измеряют и документируют свою платформу картой конфигурации. Цель занятия 2: обучающиеся оборачивают своё железо в 6 функций HAL и проверяют их тестовой программой.
Техника безопасности
ЛиПо/Li-ion аккумуляторы:
- заряд — только в присутствии человека, на негорючей поверхности, штатным ЗУ с балансиром;
- вздутый, пробитый, горячий аккумулятор → немедленно к тренеру, не заряжать, не втыкать;
- не разряжать ниже 3,3 В/банку (ставим индикатор напряжения или пищалку);
- короткое замыкание силовых проводов = пожар: силовые разъёмы только с защитой от переполюсовки (XT30/XT60), никаких «крокодилов» на батарее.
Механика и электрика:
- пальцы, волосы, шнурки — вне зоны колёс и редукторов при поданном питании; отладка захвата — только на подставке, колёса в воздухе;
- перепрошивка — при выключенном силовом питании моторов;
- ESP32 — 3,3-вольтовая логика: выход 5-вольтового датчика (например, echo УЗ-дальномера) подключается через делитель напряжения, иначе порт выгорает;
- пайка: 30 сек проветривание рабочей зоны, подставка под паяльник, не паять на весу над коленями.
Разбор (worked example): карта конфигурации
Эталонная карта (значения — примерные, каждая пара заполняет свою):
| Параметр | Обозн. | Как измерить | Пример |
|---|---|---|---|
| Диаметр колеса | D | штангенциркулем по резине (не по диску!), 3 замера, среднее | 65,0 мм |
| Колея | B | между серединами пятен контакта колёс | 142 мм |
| Прорезей энкодерного диска | N | посчитать; если ловим оба фронта — ×2 | 20 |
| Тиков на оборот колеса | N_т | N × передаточное число, если диск не на оси колеса | 20 |
| мм на тик | m | πD / N_т (проверяется калибровкой, зан. 4) | 10,2 мм |
| База датчиков линии | L_д | от оси колёс до датчиков линии (вперёд — «+») | 68 мм |
| Вылет дальномера | L_у | от передней кромки корпуса до датчика | 12 мм |
| Питание | U | номинал и тип батареи | 2S Li-ion 7,4 В |
| Драйвер моторов | — | модель, макс. ток | TB6612, 1,2 А |
Типичные ошибки:
- D измерен по ободу без резины → систематическая недоезд/переезд ~3–5%;
- B измерена между внутренними краями колёс → все повороты «перекручены»;
- энкодерный диск стоит на валу мотора до редуктора, а N_т посчитан как для колеса → путь врёт в «передаточное число» раз;
- датчики линии прикручены «на глаз» не симметрично оси → робот «ведёт» на линии, и это не лечится программой.
HAL: 6 функций, на которых стоит весь модуль
Контракт интерфейса. Реализация под конкретный драйвер/датчик — отдельная задача (код под своё железо запрашивается и пишется точечно), алгоритмы модуля используют только эти вызовы:
// ===== HAL: единственное место, где живёт конкретное железо =====
void drive(int pwmL, int pwmR); // -255..255; знак = направление; 0 = стоп
void stopBrake(); // активное торможение (замыкание обмоток)
void stopCoast(); // свободный выбег
long ticksL(); long ticksR(); // счётчики энкодеров (наращиваются в прерываниях)
void resetTicks();
int lineRaw(int i); // сырое значение датчика линии i (0..4095 на ESP32)
bool touch(); // датчик касания: true = нажат
int distMM(); // дистанция, мм: медиана из 5 замеров УЗ или ToF
Правила слоя:
- Энкодеры считаются только в прерываниях (
attachInterrupt), никогда опросом в цикле — иначе тики теряются на скорости. distMM()всегда возвращает медиану из 5 замеров: одиночные выбросы УЗ-датчика (эхо от угла, мягкая поверхность) — норма, а не поломка.- Полярность:
drive(100,100)обязан везти вперёд, тики обязаны расти при движении вперёд. Если нет — меняем провода/знаки внутри HAL, не в алгоритмах. - Смена датчика (УЗ → лазерный ToF) меняет только тело
distMM(). Смена драйвера — толькоdrive/stop*.
Практика
Измерить и заполнить карту конфигурации
Каждая пара — свою. Карта вклеивается в журнал заездов и обновляется при любой доработке робота.
Реализовать HAL под своё железо
По одной функции за раз, после каждой — проверка. Порядок: drive → stop* → энкодеры → датчики.
Прогнать тест-программу HAL
Эталонный смоук-тест (worked example, разобрать построчно перед запуском):
void setup() {
Serial.begin(115200);
halInit();
drive(120, 120); delay(1000); stopBrake(); // 1. едет вперёд? ровно-ли — неважно
Serial.printf("L=%ld R=%ld\n", ticksL(), ticksR()); // 2. тики выросли? примерно равны?
drive(-120, -120); delay(1000); stopCoast(); // 3. назад; сравнить выбег с торможением
while (!touch()) delay(10); // 4. нажать кнопку рукой
Serial.println("touch OK");
for (int i = 0; i < 20; i++) { // 5. поводить ладонью перед дальномером
Serial.println(distMM()); delay(200);
}
for (int i = 0; i < 5; i++) // 6. датчики линии: рука/чёрное/белое
Serial.printf("S%d=%d ", i, lineRaw(i));
}Зафиксировать полярности
В карту: какой мотор левый, знаки, направление роста тиков. Это спасает после каждой пересборки.
Мини-проверка выхода
- Робот пары проезжает вперёд и назад через
drive(), тики обоих колёс растут при движении вперёд — показ тренеру. - Вопрос: «завтра меняем УЗ-дальномер на лазерный — какие файлы/функции трогаем?» (правильный ответ: только
distMM()в HAL).
Над-образовательная активность (Такман: формирование)
Знакомство пар, договорённость о ролях (пилот/программист, роли меняются каждые 2 занятия), общие правила: заезды по протоколу, журнал ведём всегда, батарея на зарядке = записка с временем постановки.