Pull to refresh

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

DIY
Начитавшись в интернете и в том числе на хабре о создании разнообразных роботов, я решил сделать своего. Тем более, что у меня давно без дела валяется 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);

}


Видео




Заключение


За один вечер реально построить простейшего робота. Конечно же есть недоделки, например сенсор стоит повесить на сервомотор и провода следует привести в нормальный вид. Надеюсь вам понравится такой робот.
Tags:
Hubs:
Total votes 78: ↑74 and ↓4 +70
Views 16K
Comments Comments 41

Please pay attention