Простейший робот-черепашка на arduino

    Начитавшись в интернете и в том числе на хабре о создании разнообразных роботов, я решил сделать своего. Тем более, что у меня давно без дела валяется arduino.

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





    Задумка



    Мне хотелось собрать дешевую и простую в изготовлении платформу для моей ардуины.

    Я попытался использовать свой радиоуправляемый джип, но мощности motorshield'а не хватало для нормального движения(я даже случайно спалил драйвер двигателя).Был необходим h-мост, состоящий из 4х транзисторов. Разбираться в схеме игрушки было лень(да и ломать не хотелось), а для пайки своего надо было рыться в закромах родины и искать транзисторы.

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

    Проектирование



    Путешествуя по интернету я часто натыкался на beam-роботов, которые не имели ни колес, ни гусениц, а главное не имели редукторов.
    Весь секрет состоял в моторах, которые были расположены под углом к полу. Робот стоял прямо на валах.

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

    Постройка


    Рама

    Из алюминевого листа вырезал держатель моторов, прикрепил его к раме из конструктора и привинтил держатель arduino. Вроде ничего сложного, дремель, отвертка и максимум 15 минут времени.

    Электроника


    Как упомянул выше, arduino управляет моторами через motorshield, питание у них раздельное, чтобы не спалить микропроцессор. Позже я добавил кнопку выключения. К платам подключен ультразвуковой дальномер SRF05. Он умеет работать в 2х режимах, подробно останавливаться не буду, скажу лишь, что в 1ом режиме необходимо задействовать 2 контакта(один тригер на посылку звука, второй прием данных), а 2ой соответственно 1, за что и был выбран. Для сенсора был спаян переходник, включающий сенсор во второй режим(заземляет один контакт).

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


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

    Алгоритм следующий:
    1) повращаться вокруг своей оси и найти максимальную дистанцию
    2) повернуться по направлению к максимальной дистанции
    3.1) если смогли повернуться едем прямо до некоторого момента
    3.2) если не смогли едем вперед
    4.1) если застряли(едем вперед, а расстояние не меняется) отъезжаем назад и возращаемся к пункту 1
    4.2) если доехали до стенки, останавливаемся и возвращаемся к пункту 1

    Исходник:
    #include <AFMotor.h>
    
    #define MaxRange 23  // Как близко подъезжать к препятствиям
    #define MaxTries 3   // Сколько раз пытаться найти максимум
    
    
    int srfPin = 16;     // Pin for SRF05
    int ledPin = 2;      //
    AF_DCMotor motorL(2);
    AF_DCMotor motorR(1);
    
    boolean isInRange(int value,int leftBorder,int rightBorder){
     return (value>leftBorder && value<rightBorder);
    }
    //Забрать показания сенсора
    int getDistance(){
      delay(50);
      int duration=0; //сюда кладем время ответа
      pinMode(srfPin, OUTPUT);
      digitalWrite(srfPin, LOW);           // заземляем контакт, перед посылкой 
      delayMicroseconds(2);
      digitalWrite(srfPin, HIGH);          // Посылаем 10микросекундный сигнал начала измерений
      delayMicroseconds(10);
      digitalWrite(srfPin, LOW);           // Опять заземляем перед приемом ответа
      pinMode(srfPin, INPUT);
      duration = pulseIn(srfPin, HIGH);    // Считаем время ответного сигнала
      return duration/58; //возвращаем дистанцию в сантиметрах
      
    }
    //Функции движения
    void goForward(){
        motorL.setSpeed(255);
        motorR.setSpeed(255);
        motorL.run(FORWARD);
        motorR.run(FORWARD);
    }
    void goBackward(){
        motorL.setSpeed(255);
        motorR.setSpeed(255);
        motorL.run(BACKWARD);
        motorR.run(BACKWARD);
    }
    void turnLeft(){
        motorL.setSpeed(255);
        motorR.setSpeed(255);
        motorL.run(BACKWARD);
        motorR.run(FORWARD);
    }
    void turnRight(){
        motorL.setSpeed(255);
        motorR.setSpeed(255);
        motorL.run(FORWARD);
        motorR.run(BACKWARD);
    }
    void stopMovement(){
      motorL.run(RELEASE);
      motorR.run(RELEASE);
    }
    // функция поиска максимума вокруг
    int getMaxDistanseAround(){
    
      unsigned long timeStart=millis();
      int maxFound=0;
      // выбор направления поворота случаен
      if(random(100)<50){turnLeft();}else{turnRight();}
    
      // крутимся некоторое время и ищем максимум
      while(millis()-timeStart<3000){
       int curDistance=getDistance();
       if( curDistance > maxFound ){
        maxFound=curDistance;    
       }
      }
    
      return maxFound;  
    }
    // функция возвращения на максимум
    boolean turnToDistance(int distance){
      unsigned long timeStart=millis();
    
      // опять случайное направление
      if(random(100)<50){turnLeft();}else{turnRight();}
      
      // крутимся некоторое время
      while(millis()-timeStart<3000){
       // учитывая погрешность сравниваем текущее растояние перед роботом
        // и то, на которое надо выровняться
       if( isInRange(getDistance(),distance-5,distance+5)){
        // Пишем в usb сообщение об удаче
        Serial.print("Turned to ");
        Serial.println(getDistance());
    
        // немного отступаем(так видно что нашли дистанцию)
        goBackward();
        delay(200);
        stopMovement();
    
        blinkLed();
        return true;// возвращаем 1, т.к. сумели выполнить задачу
       }
      }
      Serial.println("distance not found");
      return false;// возвращаем ложь в случае неудачи
    }
    
    //это тестовая функция, узнаем какая скорость у робота
    float getMySpeed(){
      int secToMeas=2;
     float firstDistance=getDistance();
    
     goForward();
        
     delay(secToMeas*1000);
     stopMovement();
     float newDistance=getDistance();
     
     return (firstDistance-getDistance())/secToMeas/100;
    }
    //моргаем светодиодом
    void blinkLed(){
      digitalWrite(ledPin, HIGH);  
      delay(1000);              
      digitalWrite(ledPin, LOW);  
    }
    
    float mySpeedSm=0;//скорость в см/c
    float mySpeedM=0;// и в м/c
    
    void setup() {
      Serial.begin(9600);           // set up Serial library at 9600 bps
    
    // т.к. на этот пин ничего не подключено мы получаем шум 
     // в качестве зерна генератора
      randomSeed(analogRead(0));
    
    // иницилизируем сенсор и моторы, делаем проверку
      pinMode(ledPin, OUTPUT);
      
      Serial.println("Testing systems");
    
      blinkLed();
    
      // настраиваем сенсор
      getDistance();
      if(getDistance()>0){
      Serial.println("Ultrasonic sensor ready");    
      }
      delay(1000/4);
    
      // настраиваем моторы
      motorL.setSpeed(255);
      motorR.setSpeed(255);
      stopMovement();
    
      blinkLed();  
      delay(1000/3);
    
      Serial.println("Getting averange speed"); 
      blinkLed();
    
      mySpeedSm=getMySpeed();
      mySpeedM=mySpeedSm/100;
    
      blinkLed();
      blinkLed();
      blinkLed();
    }
    int tries=MaxTries;
    
    // основной цикл работы робота
    void loop(){
      
      // ищем максимум вокруг
      int maxDist=getMaxDistanseAround();
      Serial.print("Found max distance");
      Serial.println(maxDist);
      delay(500);
    
      // пробуем повернуться на него 
      if(turnToDistance(maxDist)){
        tries=MaxTries;// обнуляем счетчик попыток
        int lastDistance=getDistance();
        // едем до некого растояния вперед
        while(lastDistance>MaxRange){
         goForward();
         delay(500);
         // Проверка застряли или нет
         int newDist=getDistance();
         if(isInRange(newDist,lastDistance-2,lastDistance+2)){
           goBackward();
           delay(1000);
           lastDistance=0;
         }
         else{
          lastDistance=newDist; 
         }
        }
      }else{
        // в случае невозможности выхода на максимальную
         // уменьшаем счетчик попыток
        tries--;
        if(tries==0){// если попыток не осталось пробуем поехать хоть куда-нибудь
          if(getDistance()>MaxRange*2){
            goForward();
            delay(1000);
          }
          else{
            goBackward();
            delay(1000);
          }
        }
      }
      stopMovement();
      delay(500);
    
    }
    


    Видео




    Заключение


    За один вечер реально построить простейшего робота. Конечно же есть недоделки, например сенсор стоит повесить на сервомотор и провода следует привести в нормальный вид. Надеюсь вам понравится такой робот.
    Поделиться публикацией
    Похожие публикации
    Ой, у вас баннер убежал!

    Ну. И что?
    Реклама
    Комментарии 41
      +25
      Поначалу думал, что будет ужасно медленно. Ваш результат немного шокировал.
        0
        я тоже был удивлен скоростями и это при весе робота в 400 грамм
          0
          www.youtube.com/watch?v=A4hzCcFikm0&context=C3788b37ADOEgsToPDskL6Ayj1i13rEjlgIMggdyHs

          если не хочется смотреть все 3 минуты, можно промотать до 2:20 — там забег на скорость вроде
            0
            А поверхности не царапает? Думаю если он на провод наткнется то 2 дырки в линолеуме точно будут…
              0
              У меня натыкался, ничего линолиуму не было. На валах двигателя не шкурка ведь. В любом случае в агоритма выше есть откат назад в случае застревания.
              0
              В таких соревнованиях роботы более технологичные, нежели мой. Судя по сообщениям на робофоруме, доходит до использования прижимных приспособлений — отсасывается воздухз под роботом, хотя это может быть мифом.
            0
            Аналогично сразу подумал, пока не увидел видео! Офигенная скорость! Аж захотелось что-то подобное сделать самому! Спасибо автору!
              +1
              Удачи, будут вопросы, обращайся, если будут вопросы.

              Я думаю начать писать уроки по создданию роботов. Не уверен, что смогу, но попытаться стоит.
            +4
            Так как для меня это сложновато, мне кажется это волшебством.
              +4
              Ловкость рук и никакого мошенничества. Так только сначала кажется, что сложно, надо просто попробовать и все получится.
              +5
                +4
                Одному мне кажется, что он похож скорее на муху?
                  +1
                  Наверное из-за характерного звука.
                  +2
                  а он пол не царапает?
                    +1
                    У меня линолиум, следов нет, специально проверял. Кафель точно не тронет, а про паркет не могу ничего сказать.
                    Должен отметить, что ездит он только по ровной поверхности, любая достаточно глубокая трещина в линолиуме и он в ловушке.
                      +2
                      А вот если натянуть на валы трубочки или кембрики, проходимость возрастет.
                        0
                        Так и делают чаще всего, но он не так часто застревает
                        +1
                        Скорость орбота как раз из-за линолиума большая, на паркете будет меньще сцепление и меньше скорость.
                          0
                          Значит он на паркете будет буксовать и выпиливать за собой борозды?
                            0
                            я подозреваю, что выпиливать не будет, но ехать будет медленнее. К сожалению проверить негде.
                      0
                      "… но мощности motorshield'а не хватало для нормального движения(я даже случайно спалил драйвер двигателя).Был необходим h-мост..."

                      Странно. Насколько я знаю, в мотор шильде стоит толи L298n, толи L293, которые и представляют из себя сдвоенные транзисторные мосты, рассчитанные на немалые токи. Как вы их спалить умудрились?
                        0
                        там стоит L293. Спалил коротким замыканием, аккумулятор от авиамодели силовой и расчитан на большие токи.

                        Не хватает её для большой модели, я даже видео снимал:

                        Аккумулятор полностью заряжен.
                          0
                          Хм. Опять же странно. У L293 есть ноги для подключения ограничивающего резистора (Rsense). Неужели разработчики моторшилда не поставили его в соответствии с максимальным током, который держит драйвер?
                            0
                            Может быть, вы путаете с L298? У L298 на схеме подключения Rs (Rsense) — это измерительный резистор. Напряжение, которое падает на этом резисторе, может контролироваться дополнительным регулятором тока, аппаратным или программным.

                            В моторшилде (схема) от dfrobot драйвер L298 используется без контура регулирования/ограничения тока.
                              0
                              Кстати, это типичная проблема недорогих шилдиков на L298 — вот все там есть, например стоит 7805 чтоб типа запитать цифровую часть от источника питания двигателя, причем выбирается перемычкой, использовать внешние 5v или стабилизировать на месте. А вот подумать о том, что заблокированный двигатель — сгорает, у них ума не хватило. Ну хоть бы просто перемычки поставили, чтобы их можно было снять и внешние резисторы навесить, уж если они испугались, что нужно мощные ставить и на них падение будет, даже если они не используются.
                            0
                            Ссылка на видео не вставилась, извините
                          0
                          А он не царапает пол «ногами»? :-)
                            0
                            Чуть выше ответил
                            0
                            попытался скомпилировать Ваш скетч, чтобы узнать сколько он занимает памяти, но arduino ide выдала ошибку

                            sketch_dec30a.cpp: In function 'void setup()':
                            sketch_dec30a:150: error: 'motorL' was not declared in this scope
                            sketch_dec30a:151: error: 'motorR' was not declared in this scope

                            библиотека AFMotor.h видимо сторонняя и в стандартном наборе arduino ide ее нет?
                              0
                              да, так и есть это для adafruit motorshield. На сколько я помню, качал отсюда
                                0
                                Вес программы: Binary sketch size: 6062 bytes (of a 30720 byte maximum)
                                +11
                                Ну не знаю, моя черепаха так быстро не бегает.
                                  +2
                                  А питание у вашей от чего?
                              • НЛО прилетело и опубликовало эту надпись здесь
                                  +1
                                  Ага, были бы ВАЗы без колес, но с торчащими ШРУСами и полуосями из земли :)
                                    +1
                                    А сейчас как?
                                      +1
                                      А сейчас оно с каким–то подобием колес.
                                  0
                                  А еще обвесы будут?
                                  Пылесос бы ему еще прибацать) и пусть бегает по комнате…
                                    0
                                    Макимум сервопривод-шею, все-таки шасси не очень мощное, перегружать не стоит
                                    0
                                    Замечательная зверюшка! За вечер бы я такое не осилил, а за день вполне. Это огромный плюс вашего роботёнка. Можно собрать целый зоопарк. Я бы и дочь приобщил — пусть дизайном озаботится. Где-то шкурку, где-то панцирь.
                                    Кажется пошла работа мысли… заразили…

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

                                    Самое читаемое