Общие сведения
Создать машинку, движущуюся по линии - классическая задача для соревнований. Да и, пожалуй, каждому было бы интересно заставить ехать машинку по трассе, которую можно создать практически на любой поверхности, даже с помощью изоленты (разумеется, можно воспользоваться и специально предназначенными для этого трассами).
В этом уроке мы покажем свой вариант такой машинки, и соберём её из наших новых модулей.
Нам понадобится:
- 2х Мотор-редуктор с энкодером N20-100rpm-12V с управляющим контроллером
- 1х Бампер с 9 датчиками линий с шагом 14мм или с шагом 7мм
- 1х Piranha Uno R3 (или другой контроллер такого же формата)
- 1х Trema Shield
- 1х Источник питания 5В, 5-12В (Li-ion 14500)
- 1х Аккумулятор 14500 Li-ion, 3.7V, 900mah, с защитой
- 2х i2C Hub (один из них мы используем для подключения питания моторов, чтобы обойтись без пайки)
- 2х Колесо для Micro Metal Gearmotor
- 1x Шаровая опора (12 мм)
- 1х Пластина большая (конструктор ПВХ)
- 1х Крепления Arduino (конструктор ПВХ) для Arduino
- 1х 4-проводной шлейф «мама-мама» 20 см
- 4х Шлейф питания, МАМА-МАМА
- 2х Стойки М3*12 Nylon-black (4 штуки в комплекте)
- 1х Стойки М3*6 Nylon-black (4 штуки в комплекте)
- 1х Винт М3х12, (10 шт в комплекте)
- 1х Винт М3х6 (10 шт в комплекте)
- 1х Гайка М3 (10 шт в комплекте)
- 4х Шайба М3 Nylon (5 шт в комплекте)
- iarduino_I2C_Motor
- iarduino_I2C_Bumper
При необходимости, ознакомьтесь с нашей инструкцией по установке библиотек в Arduino IDE.
Видео
Сборка корпуса
- Из большой пластины ПВХ при помощи канцелярского ножа вырезаем основание машинки. Также вырезаем боковые стойки для контроллера.
2. Контроллер крепим на маленькой пластине ПВХ для Arduino.
3. Приклеиваем (например с помощью двухстороннего скотча) шаровую опору на основание, вырезанное из ПВХ.
4. Крепим бампер на основание (шайбы подкладывайте с двух сторон ПВХ).
5. Прикручиваем стойки на моторы в соответствии с изображением ниже.
6. Прикручиваем моторы к основанию, но не затягиваем (шайбы подкладывайте с двух сторон ПВХ).
7. Устанавливаем на стойки моторов I2C Hub'ы, после чего выравниваем моторы и затягиваем крепящие их винты.
8. Прикручиваем источник питания, устанавливаем ВПХ-элементы.
Установите напряжение 12В на колодке 5-12В источника питания. Для этого выкрутите движок подстроечного резистора на плате по стрелке max в крайнее положение.
9. Устанавливаем I2C-адреса моторам (0х0А - левый и 0х0В - правый) и бамперу (0х0С). Подробно о настройке адресов можно почитать в статье о бампере и в статье о моторах
10. Подключаем провода питания и I2C шины согласно схеме
Мы использовали два I2C Hub'а для того, чтобы подать питание на моторы не используя пайку. Вы можете не обойтись без второго I2C Hub'а, в этом случае необходимо подключить питание моторов параллельно, спаяв провода.
11. Устанавливаем Trema Shield на Arduino, после чего крепим на основу.
12. Устанавливаем колёса
13. Откалибруйте бампер. Подробно о калибровке можно почитать в этой статье
14. Загрузите скетч в контроллер
Скетч проекта
// Подключаем библиотеки: // #include <Wire.h> // * Подключаем библиотеку для работы с аппаратной шиной I2C. #include <iarduino_I2C_Motor.h> // Подключаем библиотеку для работы с мотором I2C-flash. #include <iarduino_I2C_Bumper.h> // Подключаем библиотеку для работы с бампером I2C-flash. // // Создаём объекты: // iarduino_I2C_Motor mot[2]={0x0A,0x0B}; // Объявляем массив mot состоящий из двух объектов для работы с моторами I2C-flash, указав адреса модулей моторов на шине I2C (0x0A-левый, 0x0B-правый). iarduino_I2C_Bumper bum (0x0C); // Объявляем объект bum для работы с бампером I2C-flash, указав адрес модуля на шине I2C. // // Определяем константы: // const float val_Radius = 21.0f; // Радиуса колеса в мм. const float val_Speed = 0.06f; // Скорость движения машины в м/сек. const float pid_KP = val_Speed * 0.15f; // Коэффициент пропорциональной обратной связи ПИД регулятора. const float pid_KI = val_Speed * 0.005f; // Коэффициент интегральной обратной связи ПИД регулятора. const float pid_KD = val_Speed * 0.15f; // Коэффициент дифференциальной обратной связи ПИД регулятора. // // Объявляем переменные: // float arr_ERR[10] = {0,0,0,0,0,0,0,0,0,0}; // Массив последних ошибок для формирования интегральной составляющей ПИД регулятора. uint8_t i, j; // Переменные для работы с массивом последних ошибок. // void setup(){ // delay(500); // * Ждём завершение переходных процессов связанных с подачей питания. // ИНИЦИАЛИЗАЦИЯ МОДУЛЕЙ: // mot[0].begin(); // Инициируем работу с левым мотором I2C-flash. mot[1].begin(); // Инициируем работу с правым мотором I2C-flash. bum. begin(); // Инициируем работу с бампером I2C-flash. // НАСТРОЙКА МОДУЛЕЙ: // mot[0].radius = val_Radius; // Указываем радиус колеса левого мотора в мм. mot[1].radius = val_Radius; // Указываем радиус колеса правого мотора в мм. mot[0].setDirection(false); // Указываем левому мотору, что его вращение должно быть обратным (против часовой стрелки при положительных скоростях). mot[1].setDirection(true); // Указываем правому мотору, что его вращение должно быть прямым ( по часовой стрелке при положительных скоростях). mot[0].setStopNeutral(false); // Указываем не освобождать ротор левого мотора при его остановке (если указать true, то ротор остановленного мотора можно вращать). mot[1].setStopNeutral(false); // Указываем не освобождать ротор правого мотора при его остановке (если указать true, то ротор остановленного мотора можно вращать). bum.setTurnPeriod(BUM_TURN_800); // Задать период мигания поворотников равен 800 мс. bum.setTurnSignal(BUM_TURN_AUTO); // Работа поворотников в автоматическом режиме bum.settingsTurnAuto(BUM_AUTO_ON_2, BUM_AUTO_OFF_ANY, false); // поворотники работают в автоматическом режиме. } // // void loop(){ // if( bum.getLineSum() > 4 ){ // Если больше 4 датчиков бампера фиксируют линию, то ... bum.setLineType(BUM_LINE_CHANGE); // Меняем тип линии трассы. } if (!bum.getLineSum()){} // Если датчик не фиксирует линии, ничего не делаем else{ i++; i%=10; j=10; // Определяем значения переменных работы с массивом ошибок. // Получаем текущую ошибку центрирования линии: arr_ERR[i] = bum.getErrPID(); // Функция getErrPID() возвращает ошибку от 0 до ±4.5, где 0 - линия по центру, ±4.0 - линия на крайнем датчике, ±4.5 - линия потеряна. // Вычисляем все составляющие ПИД регулятора: float pid_P = arr_ERR[i]; // Пропорциональная составляющая «pid_P» представлена величиной текущей ошибки «ARR_ERR[i]». float pid_I = 0.0f; while(j--){pid_I+=arr_ERR[j-1];} // Интегральная составляющая «pid_I» представлена суммой последних ошибок взятых из массива «arr_ERR». float pid_D = arr_ERR[i]-arr_ERR[(i+9)%10]; // Дифференциальная составляющая «pid_D» представлена разницей между текущей «ARR_ERR[i]» и предыдущей «arr_ERR[(i+9)%10]» ошибкой. float PID = pid_P*pid_KP+pid_I*pid_KI+pid_D*pid_KD; // Вычисляем результат ПИД регулирования. // Устанавливаем скорость вращения колёс: mot[0].setSpeed( val_Speed + PID , MOT_M_S ); // Устанавливаем скорость левого мотора в м/сек. mot[1].setSpeed( val_Speed - PID , MOT_M_S ); // Устанавливаем скорость правого мотора в м/сек. } }
Обсуждение