Я увлекаюсь робототехникой и занимаюсь ей уже полтора года. Робототехника, это прикладная наука, занимающаяся разработкой автоматизированных технических систем. Она опирается на такие дисциплины, как электроника, механика, информатика, а также радиотехника и электротехника. Обычно все новички в этой интересной науке начинают с наборов LEGO Mindstorms. В этих наборах уже даны готовые основные элементы, не требующие спайки и легкие в использовании, удобная среда программирования, позволяющая быстро собрать и запрограммировать робота, используя визуальную среду программирования Lego Mindstorm NXT, в которой запрограммировать робота, может даже человек, незнакомый с языками программирования. Я начинал именно с такого. Это отличный набор, позволяющий изучить основы робототехники, программирования. Несмотря на простоту использования, с помощью этих наборов можно собрать очень сложных роботов, решающих сложные математические задачи. Например, из данного набора собран самый быстрый в мире робот собирающий кубик Рубика 3 X 3 за 4 секунды (Cubestormer II), в котором программа, взаимодействующая с датчиками и двигателями, вращающими кубик, выполняется на телефоне Samsung Galaxy S.
При работе с наборами Lego, содержимое модулей скрыто от нас пластиковой оболочкой. Для того чтобы лучше понять как устроены элементы робота, можно использовать платформу Arduino, при работе с которой нужно глубже понимать как работает робот на уровне “железа”, дает больше гибкости при использовании составных элементов робота. Также, в настоящей робототехнике используются более сложные языки программирования, чем в LEGO Mindstorms, которые дают больше гибкости при программировании роботов и более высокую скорость выполнения программ, что дает большую скорость реакции робота на данные, получаемые с датчиков. Именно поэтому я решил выяснить, возможно ли самому в домашних условиях собрать настоящего действующего робота, не используя LEGO Mindstorms.
Я начал сборку робота с планировки месторасположения его составляющих на платформе. Робот получился двухэтажный. На нижнем ярусе я расположил мотор-редукторы и отсеки с батареями (общее напряжение 9 вольт). Я использовал пластиковые трубочки-стойки для крепления второго яруса. На нем располагались микроконтроллер Arduino UNO и жидкокристаллический дисплей. На микроконтроллер Arduino я установил драйвер управления моторами. Я воспользовался им, так, как моторы потребляют ток, с которым мой микроконтроллер не смог бы обрабатывать, и просто-напросто бы сгорел. В нижней части робота, со стороны колес установлен цифровой датчик линии Pololu QTR-8RC состоящий из 6 отдельных датчиков.
План месторасположения компонентов на моём роботе
Теперь несколько слов о самой платформе Arduino Uno. Arduino — это открытая платформа, которая позволяет собирать всевозможные электронные устройства. Платформа состоит из аппаратной и программной частей; обе чрезвычайно гибки и просты в использовании. Для программирования используется упрощенная версия языка С++. Разработку можно вести как с использованием бесплатной среды Arduino IDE, так и с помощью другого инструментария. “Мозгом” аппаратной части является микропроцессор ATmega328 работающий на частоте 16 MГц. Платформа имеет 14 цифровых входов/выходов (6 из которых могут использоваться как выходы широтно-импульсной модуляции), 6 аналоговых входов (в моем проекте не используются). На плате установлен разъем USB, через который платформу можно подключить к компьютеру и осуществлять программирование платформы, разъем для подключения питания (7 – 12 Вольт), разъёмы выхода стабилизированного напряжения 5В, 3,3В и кнопку перезагрузки. Также имеется 2 кб оперативной памяти, которые используются для хранения временных данных вроде переменных программы. Эта память очищается при обесточивании. Ещё имеется 1 кб памяти для долговременного хранения данных. По своему назначению это аналог жёсткого диска для Arduino.
После распланировки места для «внутренностей» робота требовалось подключить их к плате Arduino. На плате 14 входов. Датчики требуют 6 портов, моторы 4, а дисплей 6. В сумме 16. 14<16. А вот и первая проблема. Но на просторах интернет нашлось решение. Для уменьшения количества выводов при управлении цифровыми устройствами можно использовать сдвиговый регистр на микросхеме 74HC595. Чип преобразовывает входящий последовательный сигнал на 1 пине (Ds) в выходной параллельный на 8 пинах (Qx). Последовательная передача синхронна: для такта используется дополнительный пин (SHcp). Также отдельным пином управляется регистр данных (STcp), что позволяет изменять сигнал на 8 выходах единовременно, когда все данные переданы.
Принципиальная схема подключения сдвигового регистра:
Для решения данной задачи потребовалось самому сделать печатную плату для крепления элементов схемы. Этим я и занялся. До этого я и не представлял, насколько это увлекательный процесс. Для начала надо выпилить основу из фольгированного стеклотекстолита. На основе нарисовать дорожки маркером. На будущих местах расположения радиоэлементов просверлить отверстия. Окунуть получившуюся заготовку в раствор хлорного железа на 15-20 минут. За это время фольга растворится на открытых участках и останется только на тех местах, где мы провели маркером. Оставшуюся фольгу надо залудить и в просверленные отверстия впаять радиоэлементы. Эти полоски фольги выполняют роль проводников электричества при соединении элементов схемы. Ну, вот и готова наша плата. Вот её фотография в готовом виде:
Теперь благодаря этой микросхеме для дисплея требуется всего лишь 3 порта. Подсоединяем провода к плате Arduino. Вот что получилось:
Вид снизу робота на датчик линии. Этот датчик имеет 6 пар инфракрасный светодиод/фототранзистор.
Теперь осталось собрать второй ярус робота. Он будет держаться на специальных стойках. Вот и все. Робот собран.
В программе используется пропорционально дифференциальный алгоритм управления скоростью моторов, при котором скорость вращения одного из моторов увеличивается и другого уменьшается в зависимости от величины смещения линии относительно центра датчика. Этим поддерживается плавное движение робота по трассе.
#include <ShiftLCD.h> // подключение библиотеки для работы с дисплеем при помощи сдвигового регистра
#include <QTRSensors.h> // подключение библиотеки для работы с световыми сенсорами
// Коэффициенты KP и KD подбираются опытным путем, т.о. что бы обеспечить стабильность и плавность движения робота.
#define KP .2
#define KD 50
#define M1_DEFAULT_SPEED 255
#define M2_DEFAULT_SPEED 255
#define M1_MAX_SPEED 255
#define M2_MAX_SPEED 255
#define MIDDLE_SENSOR QTR_NO_MIDDLE_SENSOR
#define NUM_SENSORS 6 // number of sensors used
#define TIMEOUT 2500 // waits for 2500 us for sensor outputs to go low
#define EMITTER_PIN QTR_NO_EMITTER_PIN // emitter is controlled by digital pin 2
#define DEBUG 0 // set to 1 if serial debug output needed
ShiftLCD lcd(2, 0, 1);
QTRSensorsRC qtrrc((unsigned char[]) {8,9,10,11,12,13} ,NUM_SENSORS, TIMEOUT, EMITTER_PIN);
unsigned int sensorValues[NUM_SENSORS];
void setup()
{
lcd.begin(16, 2);
lcd.setCursor(0,0);
lcd.clear();
lcd.print("Artem's");
lcd.setCursor(0,1);
lcd.print("-=RoBoT=-");
if (DEBUG) {
delay(1000);
manual_calibration();
}
load_calibration();
}
int lastError = 0;
int last_proportional = 0;
int integral = 0;
// Порты для подключения двигателей
int E1 = 5;
int M1 = 4;
int E2 = 6;
int M2 = 7;
void loop()
{
unsigned int sensors[6];
// Управление моторами c использованием пропорционально интегрального (PI) способа управления.
int position = qtrrc.readLine(sensors);
int error = position - 2500;
int motorSpeed = KP * error + KD * (error - lastError);
lastError = error;
int leftMotorSpeed = M1_DEFAULT_SPEED + motorSpeed;
int rightMotorSpeed = M2_DEFAULT_SPEED - motorSpeed;
// установить новую скорость левого и правтого мотора
set_motors(leftMotorSpeed, rightMotorSpeed);
}
void set_motors(int motor1speed, int motor2speed)
{
if (motor1speed > M1_MAX_SPEED ) motor1speed = M1_MAX_SPEED; // Ораничение максимальной скорости
if (motor2speed > M2_MAX_SPEED ) motor2speed = M2_MAX_SPEED; // Ораничение максимальной скорости
if (motor1speed < 0) motor1speed = 0; // Проверка скорости на отрицательное значение
if (motor2speed < 0) motor2speed = 0; // Проверка скорости на отрицательное значение
digitalWrite(M1,HIGH);
digitalWrite(M2, HIGH);
analogWrite(E1, motor1speed); //Управление скоростью моторов с помощью широтно импульсной модуляции
analogWrite(E2, motor2speed); //Управление скоростью моторов с помощью широтно импульсной модуляции
}
void load_calibration() {
qtrrc.calibrate(QTR_EMITTERS_ON);
// Присваиваем данные по датчикам, полученные при калибровке
qtrrc.calibratedMinimumOn[0] = 172;
qtrrc.calibratedMinimumOn[1] = 128;
qtrrc.calibratedMinimumOn[2] = 208;
qtrrc.calibratedMinimumOn[3] = 292;
qtrrc.calibratedMinimumOn[4] = 288;
qtrrc.calibratedMinimumOn[5] = 336;
qtrrc.calibratedMaximumOn[0] = 1200;
qtrrc.calibratedMaximumOn[1] = 872;
qtrrc.calibratedMaximumOn[2] = 1150;
qtrrc.calibratedMaximumOn[3] = 1520;
qtrrc.calibratedMaximumOn[4] = 1460;
qtrrc.calibratedMaximumOn[5] = 1760;
}
void manual_calibration() {
// Калибровка датчиков. Робот вращается в разные стороны,
// в это время происходит считывание максимальных и минимальных значений для калибровки.
digitalWrite(M1,LOW);
digitalWrite(M2, HIGH);
//Управление скоростью моторов с помощью широтно импульсной модуляции
analogWrite(E1, 255);
analogWrite(E2, 255);
int i;
for (i = 0; i < 250; i++)
{
qtrrc.calibrate(QTR_EMITTERS_ON);
delay(20);
if (i == 100){
digitalWrite(M1,HIGH);
digitalWrite(M2, LOW);
//Управление скоростью моторов с помощью широтно импульсной модуляции
analogWrite(E1, 0);
analogWrite(E2, 0);
}
if (i == 125){
digitalWrite(M1,HIGH);
digitalWrite(M2, LOW);
//Управление скоростью моторов с помощью широтно импульсной модуляции
analogWrite(E1, 255);
analogWrite(E2, 255);
}
}
if (DEBUG) { // В режиме отладки данные можно посмотреть в среде разработки
Serial.begin(9600);
for (int i = 0; i < NUM_SENSORS; i++)
{
Serial.print(qtrrc.calibratedMinimumOn[i]);
Serial.print(' ');
}
Serial.println();
for (int i = 0; i < NUM_SENSORS; i++)
{
Serial.print(qtrrc.calibratedMaximumOn[i]);
Serial.print(' ');
}
Serial.println();
Serial.println();
}
//Управление скоростью моторов с помощью широтно импульсной модуляции
analogWrite(E1, 0);
analogWrite(E2, 0);
}
Датчики линии перед началом работы необходимо откалибровать. Для этого программу переключаем в режим отладки (#define DEBUG 1) , помещаем робота на линию, включаем. Робот будет вращаться, датчики будут перемещаться над черно- белой поверхностью и через окно монитора порта (Ctrl+Shift+M в среде разработки) после завершения калибровки мы сможем посмотреть максимальные и минимальные значения, которые означают, как датчик воспринимает черный и белый цвет поверхности, над которой он расположен. Эти значения прописываем в программе.
Контроллер DFRduino UNO v3 на ATmega328 + ATmega8U2 (arduino)
Драйвер моторов двухканальный DFRobot для Arduino на L298P v1.2 <2А
Датчик линии Pololu QTR-8RC (цифровой)
ЖК-дисплей символьный 16x2 (белый на синем)
1) Русскоязычный сайт о платформе Ардуино.
2) Англоязычный сайт о платформе Ардуино.
3) Виды плат Ардуино.
4) Управление LCD дисплеем с использованием сдвигового регистра по 3 проводам.
cjparish.blogspot.ru/2010/01/controlling-lcd-display-with-shift.html
5) Пропорционально интегральное (PI) управление.
inpharmix.com/jps/PID_Controller_For_Lego_Mindstorms_Robots.html
6) Бесплатная среда разработки для Ардуино (Arduino IDE):
arduino.cc/en/Main/Software#toc1
7) Описание работы с программной библиотекой для цифрового датчика линии Pololu QTR-8RC
8) Библиотека для работы с жидкокристаллическим дисплеем используя сдвиговый регистр 74HC595 (по 3-м проводам вместо 6-и)
github.com/cjameshuff/shiftlcd
Автор: Вешкин Артём для РОБОТОТЕХНИКА