Робот, ездящий по линии под управлением Arduino [Амперка / Вики]

В данной статье будет описан процесс создания робота, ездящего по линии. Эта задача является классической, идейно простая, она может решаться много раз, и каждый раз вы будете открывать для себя что-то новое. Решение этой задачи и реализация полученного решения позволяют приобрести необходимые начальные навыки для дальнейшего совершенствования в робототехнике.

Существует множество подходов для решения задачи следования по линии. Выбор одного из них зависит от конкретной конструкции робота, от количества сенсоров, их расположения относительно колёс и друг друга.

В нашем примере будет собран робот на лёгкой платформе с двумя колёсами и двумя датчиками линии, расположенными на днище робота перед колёсами.

В результате выглядеть он будет так:

Что понадобится

Для нашего примера понадобятся следующие детали:

Вообще говоря, лучше было бы использовать NiMH-аккумуляторы: они лучше отдают ток и значительно дольше держат напряжение, но для целей этого проекта одной батарейки на 9 В вполне хватило.

Собираем робота

Сначала соберём робота, установим всю механику и электронику.

Собираем платформу

Для начала прикрепим колёса к моторам.

Затем с помощью пластиковых П-образных креплений прикручиваем моторчики к платформе. Обратите внимание на взаимное расположение крепления и моторчики: в креплении есть небольшие углубления, так что если всё соединить правильно, то моторчики будут крепко держаться и никуда не выскочат.

Теперь крепим балансировочный шар.

Отлично! Платформа собрана. Если вам кажется, что колёсам отведено слишком мало места и они трутся о платформу, то скорее всего вам нужно посильнее надавить на колёса, чтобы они плотнее сели на вал мотора.

Крепим сенсоры

Закрепим их, как показано на фото:

Можно было бы выбрать и другое место. Это могло бы сделать контроль проще или сложнее, а самого робота более или менее эффективным. Оптимальное расположение — вопрос серии экспериментов. Для этого проекта просто был выбран такой способ крепления.

Крепим Arduino

Arduino закрепим с противоположной стороны двумя винтиками и гайками.

Опять же, можно выбрать и другое место. Например над колёсами, если приподнять Arduino на латунных стойках. Это изменило бы положение центра масс и повлияло бы на эффективность робота в лучшую или худшую сторону.

Крепим Motor Shield и соединительные провода

Установим Motor Shield на Arduino и подсоединим соединительные провода. Обратите внимание, чтобы соотвествовать программному коду из примера ниже, моторчики соединены с Motor Shield так: правый — к клеммам M1 с прямой полярностью (плюс к плюсу), а левый — к M2 с обратной (плюс к минусу).

В этом проекте, для экономии времени концы соединительных проводов просто скручены с контактами моторов. При работе «начисто» стоит жёстко припаять провода к моторам.

Крепим Troyka Shield

Присоединяем сверху Troyka Shield и подключаем датчики к 8 и 9 цифровым контактам. В итоге получаем следующую конструкцию:

Программирование

Теперь напишем программу, которая заставит собранную конструкцию двигаться по нарисованной линии. В проекте мы будем использовать чёрную линию, напечатанную на белых листах бумаги.

Основная идея алгоритма

Пусть у нас усть белое поле, и на нём чёрным нарисован трек для нашего робота. Используемые датчики линии выдают логический ноль, когда «видят» чёрное и единицу, когда «видят» белое.

На прямой робот должен пропускать трек между сенсоров, то есть оба сенсора должны показывать единички.

При повороте траектории направо, правый сенсор наезжает на трек и начинает показывать логический ноль. При повороте налево, ноль показывает левый сенсор.

Таким образом получаем простую систему с тремя состояниями:

  • STATE_FORWARD — нужно ехать вперёд

  • STATE_RIGHT — нужно поворачиваться направо

  • STATE_LEFT — нужно поворачиваться налево

На вход системы поступает информация с сенсоров. Получаем следующую логику переходов:

Левый Правый Целевое состояние
0 0 STATE_FORWARD
0 1 STATE_RIGHT
1 0 STATE_LEFT
1 1 STATE_FORWARD

Реализация на Arduino

LineRobot_v1.ino
// Моторы подключаются к клеммам M1+,M1-,M2+,M2-  
// Motor shield использует четыре контакта 6,5,7,4 для управления моторами 
#define SPEED_LEFT       6
#define SPEED_RIGHT      5 
#define DIR_LEFT         7
#define DIR_RIGHT        4
#define LEFT_SENSOR_PIN  8
#define RIGHT_SENSOR_PIN 9
 
// Скорость, с которой мы движемся вперёд (0-255)
#define SPEED            35
 
// Коэффициент, задающий во сколько раз нужно затормозить
// одно из колёс для поворота
#define BRAKE_K          4
 
#define STATE_FORWARD    0
#define STATE_RIGHT      1
#define STATE_LEFT       2
 
int state = STATE_FORWARD;
 
void runForward() 
{
    state = STATE_FORWARD;
 
    // Для регулировки скорости `SPEED` может принимать значения от 0 до 255,
    // чем болше, тем быстрее. 
    analogWrite(SPEED_LEFT, SPEED);
    analogWrite(SPEED_RIGHT, SPEED);
 
    // Если в DIR_LEFT или DIR_RIGHT пишем HIGH, мотор будет двигать соответствующее колесо
    // вперёд, если LOW - назад.
    digitalWrite(DIR_LEFT, HIGH);
    digitalWrite(DIR_RIGHT, HIGH);
}
 
void steerRight() 
{
    state = STATE_RIGHT;
 
    // Замедляем правое колесо относительно левого,
    // чтобы начать поворот
    analogWrite(SPEED_RIGHT, SPEED / BRAKE_K);
    analogWrite(SPEED_LEFT, SPEED);
 
    digitalWrite(DIR_LEFT, HIGH);
    digitalWrite(DIR_RIGHT, HIGH);
}
 
void steerLeft() 
{
    state = STATE_LEFT;
 
    analogWrite(SPEED_LEFT, SPEED / BRAKE_K);
    analogWrite(SPEED_RIGHT, SPEED);
 
    digitalWrite(DIR_LEFT, HIGH);
    digitalWrite(DIR_RIGHT, HIGH);
}
 
 
void setup() 
{
    // Настраивает выводы платы 4,5,6,7 на вывод сигналов 
    for(int i = 4; i <= 7; i++)
        pinMode(i, OUTPUT);
 
    // Сразу едем вперёд
    runForward();
} 
 
void loop() 
{ 
    // Наш робот ездит по белому полю с чёрным треком. В обратном случае не нужно
    // инвертировать значения с датчиков
    boolean left = !digitalRead(LEFT_SENSOR_PIN);
    boolean right = !digitalRead(RIGHT_SENSOR_PIN);
 
    // В какое состояние нужно перейти?
    int targetState;
 
    if (left == right) {
        // под сенсорами всё белое или всё чёрное
        // едем вперёд
        targetState = STATE_FORWARD;
    } else if (left) {
        // левый сенсор упёрся в трек
        // поворачиваем налево
        targetState = STATE_LEFT;
    } else {
        targetState = STATE_RIGHT;
    }
 
    if (state == targetState) {
        // мы уже делаём всё что нужно,
        // делаем измерения заново
        return;
    }
 
    switch (targetState) {
        case STATE_FORWARD:
            runForward();
            break;
 
        case STATE_RIGHT:
            steerRight();
            break;
 
        case STATE_LEFT:
            steerLeft();
            break;
    }
 
    // не позволяем сильно вилять на прямой
    delay(50);
}

Проблема инертности и её решение

Однако если выставить скорость моторов побольше, мы столкнёмся со следующей проблемой: наш робот будет вылетать с трека, не успевая отреагировать на поворот. Это связано с тем, что наши моторчики не умеют тормозить мгновенно.

В этом легко убедиться поставив следующий эксперимент: с заданной скоростью робот будет двигаться по поверхности, и в некоторый момент будет установлена нулевая скорость и измерен тормозной путь робота. Пусть робот разгоняется по монотонной поверхности и тормозится при фиксировании импровизированной стоп-линии.

Эксперимент проведём для разных скоростей. Код программы для эксперимента таков:

stopping_distance_experiment.ino
#define LEFT_SENSOR_PIN   8
#define RIGHT_SENSOR_PIN  9
#define SPEED_LEFT        6
#define SPEED_RIGHT       5 
#define DIR_LEFT          7
#define DIR_RIGHT         4
 
// Для того чтобы убедиться, что именно тормозной путь долог, а не команда остановиться 
// приходит слишком поздно, будем включать светодиод, когда отдаётся команда.
#define LED_PIN           13
 
int currSpeed = 40;
void setup()
{
    for(int i = 4; i <= 7; ++i)
        pinMode(i, OUTPUT);
 
    analogWrite(SPEED_RIGHT, currSpeed);
    digitalWrite(DIR_RIGHT, HIGH);
 
    analogWrite(SPEED_LEFT, currSpeed);
    digitalWrite(DIR_LEFT, HIGH);    
 
    pinMode(LED_PIN, OUTPUT);
}
 
void loop()
{
    if (currSpeed > 120)
        return;
 
    boolean white[] = {
        !digitalRead(LEFT_SENSOR_PIN), 
        !digitalRead(RIGHT_SENSOR_PIN)
    };
 
    if (white[0] && white[1]) {
        // едем пока не упрёмся
        return;
    }
 
    // зажигаем светодиод, останавливаем моторы
    // и наблюдаем
    digitalWrite(LED_PIN, HIGH);
    analogWrite(SPEED_RIGHT, 0);
    analogWrite(SPEED_LEFT, 0);
    delay(5000);
 
    // повторяем эксперимент, увеличивая скорость
    // на 10 пунктов
    currSpeed += 10;
    if (currSpeed > 120)
        return;
 
    digitalWrite(LED_PIN, LOW);
    analogWrite(SPEED_RIGHT, currSpeed);
    analogWrite(SPEED_LEFT, currSpeed);    
}

На той поверхности, на которой проводился эксперимент, были получены следующие результаты:

Таким образом, начиная с некоторого момента у нашего робота нет никакой возможности успеть среагировать и остаться на треке.

Что можно сделать?! После того, как сенсоры улавливают поворот, можно остановиться и вернуться назад на некоторое расстояние, зависящее от скорости перед остановкой. Однако мы можем отдать команду роботу ехать с какой-то скоростью, но не можем приказать ему проехать какое-то расстояние.

Для того, чтобы понять зависимость расстояния при заднем ходе от времени, был проведён ещё один замер:

time_distance_rate.ino
#define SPEED_LEFT      6
#define SPEED_RIGHT     5 
#define DIR_LEFT        7
#define DIR_RIGHT       4
 
void go(int speed, bool reverseLeft, bool reverseRight, int duration)
{
    analogWrite(SPEED_LEFT, speed);
    analogWrite(SPEED_RIGHT, speed);
    digitalWrite(DIR_LEFT, reverseLeft ? LOW : HIGH); 
    digitalWrite(DIR_RIGHT, reverseRight ? LOW : HIGH); 
    delay(duration); 
}
 
void setup() 
{
    for(int i = 4; i <= 7; ++i)
        pinMode(i, OUTPUT);
} 
 
void loop() 
{ 
    // Задержка 5 секунд после включения питания 
    delay(5000); 
 
    for (int i = 200; i <= 1000; i += 100) {
        // Несколько сотен мс вперёд 
        go(50, false, false, 200);
        go(0, false, false, 0);
 
        // Задержка 5 секунд
        delay(5000); 
    }
 
    // Остановка до ресета или выключения питания 
    go(0, false, false, 0);
 
    // Приехали
    while (true)
        ; 
}

На скорости 50, например, робот проделывал путь, зависящий от времени следующим образом:

Полученные две зависимости были линейно аппроксимированы, затем была выведена формула зависимости времени, которое надо двигаться назад, от скорости перед остановкой.

Обратим внимание на то, что у вас значения могут оказаться другими: из-за особенностей сборки либо из-за поверхности, поэтому в общем случае лучше провести все измерения самостоятельно.

Адаптивное поведение

Перед финальным экспериментом произведём ещё несколько поправок.

Во-первых, нам необязательно давать команду ехать назад перед каждым поворотом, как мы помним, на маленькой скорости робот прекрасно справляется и без этого. К тому же лучше ему двигаться не прямо назад, а немного поворачивая, всё-таки робот находится перед поворотом.

Во-вторых, нам стоит различать состояния робота: когда он движется по прямой, и ничто ему не мешает ускоряться; и когда робот входит в поворот. В первом случае действительно будем увеличивать скорость робота для более динамичного прохождения трека, во втором случае будем сбрасывать скорость до значения, достаточного для успешного прохождения поворота, и будем держать эту скорость ещё какое-то время.

В итоге наш код будет выглядит следующим образом:

Robot_v02.ino
// Моторы подключаются к клеммам M1+,M1-,M2+,M2-  
// Motor shield использует четыре контакта 6,5,7,4 для управления моторами 
#define SPEED_LEFT       6
#define SPEED_RIGHT      5 
#define DIR_LEFT         7
#define DIR_RIGHT        4
#define LEFT_SENSOR_PIN  8
#define RIGHT_SENSOR_PIN 9
 
// Скорость, с которой мы движемся вперёд (0-255)
#define SPEED            100
 
// Скорость прохождения сложных участков
#define SLOW_SPEED       35
 
#define BACK_SLOW_SPEED  30
#define BACK_FAST_SPEED  50
 
// Коэффициент, задающий во сколько раз нужно затормозить
// одно из колёс для поворота
#define BRAKE_K          4
 
#define STATE_FORWARD    0
#define STATE_RIGHT      1
#define STATE_LEFT       2
 
#define SPEED_STEP       2
 
#define FAST_TIME_THRESHOLD     500
 
int state = STATE_FORWARD;
int currentSpeed = SPEED;
int fastTime = 0;
 
void runForward() 
{
    state = STATE_FORWARD;
 
    fastTime += 1;
    if (fastTime < FAST_TIME_THRESHOLD) {
        currentSpeed = SLOW_SPEED;
    } else {
        currentSpeed = min(currentSpeed + SPEED_STEP, SPEED);
    }
 
    analogWrite(SPEED_LEFT, currentSpeed);
    analogWrite(SPEED_RIGHT, currentSpeed);
 
    digitalWrite(DIR_LEFT, HIGH);
    digitalWrite(DIR_RIGHT, HIGH);
}
 
void steerRight() 
{
    state = STATE_RIGHT;
    fastTime = 0;
 
    // Замедляем правое колесо относительно левого,
    // чтобы начать поворот
    analogWrite(SPEED_RIGHT, 0);
    analogWrite(SPEED_LEFT, SPEED);
 
    digitalWrite(DIR_LEFT, HIGH);
    digitalWrite(DIR_RIGHT, HIGH);
}
 
void steerLeft() 
{
    state = STATE_LEFT;
    fastTime = 0;
 
    analogWrite(SPEED_LEFT, 0);
    analogWrite(SPEED_RIGHT, SPEED);
 
    digitalWrite(DIR_LEFT, HIGH);
    digitalWrite(DIR_RIGHT, HIGH);
}
 
 
void stepBack(int duration, int state) {
    if (!duration)
        return;
 
    // В зависимости от направления поворота при движении назад будем
    // делать небольшой разворот 
    int leftSpeed = (state == STATE_RIGHT) ? BACK_SLOW_SPEED : BACK_FAST_SPEED;
    int rightSpeed = (state == STATE_LEFT) ? BACK_SLOW_SPEED : BACK_FAST_SPEED;
 
    analogWrite(SPEED_LEFT, leftSpeed);
    analogWrite(SPEED_RIGHT, rightSpeed);
 
    // реверс колёс
    digitalWrite(DIR_RIGHT, LOW);
    digitalWrite(DIR_LEFT, LOW);
 
    delay(duration);
}
 
 
void setup() 
{
    // Настраивает выводы платы 4,5,6,7 на вывод сигналов 
    for(int i = 4; i <= 7; i++)
        pinMode(i, OUTPUT);
 
    // Сразу едем вперёд
    runForward();
} 
 
void loop() 
{ 
    // Наш робот ездит по белому полю с чёрным треком. В обратном случае не нужно
    // инвертировать значения с датчиков
    boolean left = !digitalRead(LEFT_SENSOR_PIN);
    boolean right = !digitalRead(RIGHT_SENSOR_PIN);
 
    // В какое состояние нужно перейти?
    int targetState;
 
    if (left == right) {
        // под сенсорами всё белое или всё чёрное
        // едем вперёд
        targetState = STATE_FORWARD;
    } else if (left) {
        // левый сенсор упёрся в трек
        // поворачиваем налево
        targetState = STATE_LEFT;
    } else {
        targetState = STATE_RIGHT;
    }
 
    if (state == STATE_FORWARD && targetState != STATE_FORWARD) {
        int brakeTime = (currentSpeed > SLOW_SPEED) ?
            currentSpeed : 0;
        stepBack(brakeTime, targetState);
    }
 
    switch (targetState) {
        case STATE_FORWARD:
            runForward();
            break;
 
        case STATE_RIGHT:
            steerRight();
            break;
 
        case STATE_LEFT:
            steerLeft();
            break;
    }
 
}

Результат

Что дальше?

Представленный алгоритм оставляет множество возможностей для улучшения и оптимизации. Скорость поворота можно так же менять адаптивно. Можно добавить контроль заноса. Можно поиграть с расположением сенсоров и центром масс. В конце концов можно получить непобедимого на треке робота.

Нет ничего лучше, чем обставить оппонента на секунду-другую.

wiki.amperka.ru

Как сделать робота на ардуино

Теперь нам нужно запрограммировать нашу Arduino UNO, чтобы сбалансировать робота. Здесь происходит вся магия; концепция, стоящая за ней, проста. Мы должны проверить, наклоняется ли бот к передней или к задней части с помощью MPU6050, а затем, если он наклоняется к передней части, мы должны вращать колеса в прямом направлении, и если он наклоняется к задней части, мы должны вращать колеса в обратном направлении.

В то же время мы также должны контролировать скорость вращения колес, если бот слегка дезориентирован из центрального положения, колеса вращаются медленно, а скорость увеличивается, когда она больше удаляется от центрального положения. Для достижения этой логики мы используем алгоритм PID, который имеет центральное положение в качестве заданного значения и уровень дезориентации в качестве выходного.

Чтобы узнать текущее положение бота, мы используем MPU6050, который представляет собой 6-осевой акселерометр и датчик гироскопа. Чтобы получить достоверное значение положения от датчика, нам нужно использовать значение как акселерометра, так и гироскопа, поскольку значения от акселерометра имеют проблемы с шумом, а значения из гироскопа со временем дрейфуют. Таким образом, мы должны объединить оба и получить значение шага рыскания и крена нашего робота, из которого мы будем использовать только значение рыскания.

Теперь у нас есть библиотеки, добавленные в нашу среду разработки Arduino. Давайте начнем программирование для нашего Self-балансирующего робота. Как и всегда, полный код для проекта приведен в конце этой страницы, здесь я просто объясняю наиболее важные фрагменты кода. Ранее сообщалось, что код построен поверх примера кода MPU6050, мы просто собираемся оптимизировать код для нашей цели и добавить PID и технологию управления для нашего самобалансирующегося робота.

Сначала мы включаем библиотеки, которые необходимы для работы этой программы. Они включают встроенную библиотеку I2C, библиотеку PID и библиотеку MPU6050, которые мы только что загрузили.

Затем мы объявляем переменные, которые необходимы для получения данных от датчика MPU6050. Мы читаем как значения гравитационного вектора, так и значения кватерниона, а затем вычисляем значение угла и угла поворота бота. Конечный результат будет иметь массив float ypr [3].

Далее идет очень важный сегмент кода, и именно здесь вы будете тратить много времени на настройку нужного набора значений. Если ваш робот построен с очень хорошим центром тяжести, а компоненты симметрично расположены (что в большинстве случаев нет), тогда значение вашего уставки будет равно 180. Просто подключите ваш бот к серийному монитору Arduino и наклоните его до положения балансировки, прочитайте значение, отображаемое на последовательном мониторе, и это ваше заданное значение. Значение Kp, Kd и Ki должно быть настроено в соответствии с вашим ботом. Никакие два одинаковых бота не будут иметь одинаковых значений Kp, Kd и Ki, поэтому от него не уйти.

В следующей строке мы инициализируем алгоритм PID, передавая входные переменные input, output, set point, Kp, Ki и Kd. Из них мы уже установили значения заданного значения Kp, Ki и Kd в приведенном выше фрагменте кода. Значение входа будет текущим значением рыскания, которое считывается с датчика MPU6050, а значением выхода будет значение, которое рассчитывается по алгоритму PID. Таким образом, в основном алгоритм PID даст нам выходное значение, которое должно использоваться для коррекции значения Input, чтобы оно было близко к заданной точке.

Внутри функции void setup мы инициализируем MPU6050, настроив DMP (Digital Motion Processor). Это поможет нам объединить данные акселерометра с данными гироскопа и обеспечить надежное значение Yaw, Pitch and Roll. Мы не будем углубляться в это, так как это будет далеко за пределами темы. Во всяком случае, один сегмент кода, который вы должны искать в функции настройки, представляет собой значения смещения гироскопа. Каждый датчик MPU6050 имеет собственные значения смещений, вы можете использовать этот эскиз Arduino для расчета значения смещения вашего датчика и соответственно обновить следующие строки в вашей программе.

Мы также должны инициализировать контакты PWM Digital, которые мы используем для подключения наших двигателей. В нашем случае это D6, D9, D10 и D11. Таким образом, мы инициализируем эти контакты, поскольку выходные выводы делают их LOW по умолчанию.

Внутри основной функции цикла мы проверяем, готовы ли данные из MPU6050 для чтения. Если да, то мы используем его для вычисления значения PID, а затем отображаем входное и выходное значение PID на последовательном мониторе, чтобы проверить, как реагирует PID. Затем, основываясь на значении вывода, мы решаем, должен ли бот двигаться вперед или назад или стоять на месте.

Поскольку мы предполагаем, что MPU6050 вернет 180, когда бот будет вертикально. Мы получим положительные значения коррекции, когда бот падает вперед, и мы получим значения отрицательными, если бот падает назад. Поэтому мы проверяем это условие и вызываем соответствующие функции для перемещения бота вперед или назад.

Выходная переменная PID также определяет, как быстро двигатель должен вращаться. Если бот вот-вот упадет, мы сделаем небольшую коррекцию, медленно вращая колесо. Если эти незначительные корректировки работают, и все еще, если бот падает, мы увеличиваем скорость двигателя. Значение того, как быстро вращаются колеса, будет определяться алгоритмом PI. Заметим, что для функции Reverse мы умножили значение вывода с -1, чтобы мы могли преобразовать отрицательное значение в положительное.

geekhouse.tech

Робот для обучения детей программированию на Arduino / Habr

Кружки робототехники в наше время определенно пользуются успехом. Лего, ардуино, скретчи и много чего еще доступно современным детям (я уверен, многие, как и я, в этом плане завидуют нынешней детворе). Будучи преподавателем робототехники, решил поделиться некоторым материалом, который у меня накопился за пару лет работы, а именно довольно простым роботом и несколькими занятиями с ним.

Данные агрегаты используется мною на занятиях для того, чтобы объяснить детям принципы работы драйвера двигателя, датчика линии и дальномера. Дети, которых настигло изучение данного робота, уже как правило отучились год и имеют минимальные представления об Arduino, моторах и электротехнике в целом. В интернете много проектов с данными комплектующими, но разработать свою машинку меня мотивировало две вещи – хотелось использовать отсек под 4 батарейки АА и иметь возможность надежно прикрепить к роботу практически любой датчик (для этого в конструкции есть несколько дополнительных крепежных отверстий).


Управляется робот платой Arduino Uno с motor shield l293d, из датчиков я ставил дальномер HC-SR04 и два датчика линии tcrt5000 (имеет как цифровой, так и аналоговый вывод).

Корпус робота состоит из 3 деталей (не считая необязательных креплений под датчики), которые печатаются на 3D-принтере. Для сборки понадобится крепеж М3, все необходимые элементы я описал в документе, лежащем с файлами для 3D-принтера.

Программируется робот, как и в стандартной среде Arduino IDE (дети постарше), так и в программе miniBloq (для младших групп). Для стандартной среды используется библиотека AFMotor, которая необходима для работы с шилдом драйверов двигателя. В miniBloq-е для работы необходимо выбрать в разделе оборудование робота «ta-bot v1», использующего аналогичный драйвер.

Имея на борту дальномер и датчики линии, робот годится для участия в соревнованиях по многим дисциплинам, но создан был именно для обучения, занять призовые места с ним не получится.

Занятия, которые с ним можно провести:


  • Работа с драйвером двигателей. Вращение колеса в разные стороны и с разной скоростью.
  • Простые маневры. Езда по кругу, езда по восьмерке (в этих занятиях как правило приходится много раз подбирать необходимое время и скорость, чтобы получить заданную фигуру).
  • Датчик линии. Принцип работы. Передача показаний датчика в компьютер (монитор порта).
  • Езда по линии с одним датчиком линии.
  • Езда по линии с двумя датчиками линии.
  • Дальномер. Принцип работы дальномера. Передача показаний дальномера в компьютер.
  • Езда по комнате с дальномером. Робот едет вперед до встречи с препятствием, как только подъезжает к стене – поворачивает.
  • Поиск противника (как в робосумо). Два робота ставятся в круг и начинают крутиться на месте, выискивая дальномером противника.

В папке с деталями также можно найти несколько готовых занятий из вышеперечисленного списка.

habr.com

Отправить ответ

avatar
  Подписаться  
Уведомление о