Мой колесный аппарат на Ардуино Мега

arduinonovice
Offline
Зарегистрирован: 02.02.2016

Попробую сначала на шурупах. Пока сервоприводы не пришли с Алиэкспресс, так что я не уверен что так можно.

zhenious
Offline
Зарегистрирован: 03.07.2014

arduinonovice пишет:

Подскажите как колеса от конструктора с отверстием около 5 мм насадить на сервопривод?

http://ru.aliexpress.com/item/Practical-SG90-9g-Mini-Micro-Servo-For-RC-...

https://market.yandex.ru/product/11865474?hid=10470548&show-uid=54435858...

В таких конструкторах бывают П-образные скобы.

С помощью длинного болта крепите колесо к ушкам скобы.

Торец скобы - к серве.

zhenious
Offline
Зарегистрирован: 03.07.2014

jeka_tm пишет:

самый простой это взять крестик(качалка) от сервы и на термоклей приклеить к колесу

да, в моем случае так и делал, приклеил редуктор с колесом к крестику.

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Поздравляю. Здорово получилось. Делаем что-то подобное, но на базе Лего деталек, причем вперемежку обычное Лего и Техник.

Какова предельная скорость движения вашего бота на таких моторах? Сантиметров 60 в сек. сможет проехать?

zhenious
Offline
Зарегистрирован: 03.07.2014

не измерял, в моих испытаниях 20 - 30 см/с наверно было

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Спасибо, это радует. :)

Планируем попасть на отборочный тур соревнований "Hello, Robot! Arduino". Смотрел видео с предыдущих, там было много конструкций на платформе с такими редукторами и колесами .. вот и стало интересно кто может оказаться в конкурентах.

zhenious
Offline
Зарегистрирован: 03.07.2014

Вторая версия колесного аппарата. Почти вся элементная база с первой версии. Основное отличие - это конструкция. Теперь платформа вырезана лазером из фанеры, также другие колеса с двигателями. Пока здесь только ардуина, светодиод и приемник на 433МГц. В дальнейшем постараюсь перенести все датчики с первой версии.

 

Испытание ультразвуковых датчиков прошло успешно. Аппарат едет назад, вперед и останавливается. 

видео https://vk.com/video-73778892_456239018

zhenious
Offline
Зарегистрирован: 03.07.2014

Последнее фото с установленными ультразвуковыми и инфракрасными датчиками:

Последний скетч:

#include <KemaUS.h>
#include <KemaIR.h>
#include <KemaState.h>
#include <KemaDrive.h>
#include <KemaLED.h>
#include <KemaMem.h>
#include <VirtualWire.h>  //pin 11

  KemaDrive myDrive;
  KemaLED myLED(8,9,12);
  KemaState curState;
  KemaState prevState;
  KemaUS ultraSonic(22,23,24,25);  
  KemaIR myIR(30,31);
  KemaMem myMem;
  
  long prevTime = 0;
  long deltaTime = 0;
  int incomingByte = 0;
  boolean rfCtrl = true; 
  boolean past = false;
  char passRfCtrl[4] = {'k', 'e', 'm', 'a'};
  char act = '?';
  byte disallow = B00000000; // 0 - back. 1 - stop. 2 - forward.
  int speedInd = 0;
  
void setup()
{
    myLED.led('B');
  Serial.begin(9600);
    
    vw_set_ptt_inverted(true); // Required for DR3100
    vw_setup(2000);	 // Bits per sec
    vw_rx_start();  
    
}

void loop()
{
   if(rfCtrl)
     myLED.led('W');
   disallow = B00000000;
   prevTime = millis();
   uint8_t buf[VW_MAX_MESSAGE_LEN];
   uint8_t buflen = VW_MAX_MESSAGE_LEN;
      
  // ---------------------------------------------------- Sensor Section
  curState.setEchoR(ultraSonic.pingR());
  curState.setEchoL(ultraSonic.pingL());
  curState.setIRL(myIR.pingL());
  curState.setIRR(myIR.pingR());
     
  //----------------------------------------------------- RF control
    if (vw_get_message(buf, &buflen)) // Non-blocking
    {
	int i;
        char letter;
        boolean getSignal = false;
        for (i = 0; i < buflen-1; i++)
	{
	    letter = buf[i];
            if(letter != passRfCtrl[i])	 
                break;
            getSignal = true;    
	}
        letter = buf[buflen-1];
        if((getSignal)&&(letter == 'M'))
        {
            rfCtrl = !rfCtrl;
            //Serial.println("M"); 
           // Serial.println(rfCtrl);
        }
	if((rfCtrl)&&(getSignal))
        {
            
            //Serial.println(letter);
            switch (letter)
            {
              case 'S':
              curState.setAct('S'); 
              curState.setSpeed(0); 
              act = 'S';
              break;
              case 'B':
              curState.setAct('B');
              curState.setSpeed(curState.speed()-1); 
              act = 'B';
              break;
              case 'F':
              curState.setAct('F');    
              curState.setSpeed(curState.speed()+1);
              act = 'F';
              break;
              case 'R':
              curState.setAct('R');
              curState.setTurnAng(curState.turnAng() + 10);
              act = 'R';
              break;
              case 'L':
              curState.setAct('L');
              curState.setTurnAng(curState.turnAng() - 10);
              act = 'L';
              break;
              case 'W':
              curState.setAct('W');
              curState.setTurnAng(0);
              act = 'W';
              break;
              case 'P':
              past = true;
              break;
              
            }
           
        }
                  
    }   
  // ---------------------------------------------------- Smart Section
    if(past)
    {
       if(myMem.isNext())
       {
           curState.setSpeed(-myMem.getSpeed());
           curState.setTurnAng(myMem.getAngel());
           rfCtrl = false;
          // Serial.println(curState.turnAng());          
       }
       else
       {
          past = false;
          rfCtrl = true;
       }
    }
  
    curState.setLed('G');
    if((curState.echoR() < 300) && (curState.echoL() < 300)) //stop
    {
      if((curState.echoR() != 0) && (curState.echoL() != 0)) //forward
      {
          bitSet(disallow, 2); 
          curState.setLed('Y');
      }    
    }

    if((curState.irL() == 1)||(curState.irR() == 1)) //stop
    {
      bitSet(disallow, 2);
      curState.setLed('Y');
    }
    
    if((curState.echoR() < 150) && (curState.echoL() < 150)) //back
    {
      if((curState.echoR() != 0) && (curState.echoL() != 0)) //forward
      {
        bitSet(disallow, 1);
        curState.setLed('R');
      }  
    }
   
     if (Serial.available() > 0)
  {
     incomingByte = Serial.read();
     Serial.println("command");
     if (incomingByte == 52)
     {
       curState.setAct('L');
       curState.setTurnAng(curState.turnAng() - 10);
       act = 'L';
       Serial.println("left");
     }
     if (incomingByte == 53)
     {
        curState.setAct('W');
        curState.setTurnAng(0);
        act = 'W';
        Serial.println("stop");
     }
     if (incomingByte == 54)
     {
          curState.setAct('R');
          curState.setTurnAng(curState.turnAng() + 10);
          act = 'R';
          Serial.println("right");
     }

  }
  // ---------------------------------------------------- Drive Section
    if(past)
    {
       if(curState.speed() != prevState.speed()) 
          myDrive.move(curState.speed());
       if(curState.turnAng() != prevState.turnAng()) 
          myDrive.turn(curState.turnAng(), curState.speed());
  
    }
    if(rfCtrl)
    {
            switch (act)
            {
              case 'S':
                myDrive.stop();
              break;
              case 'B':
                myDrive.move(curState.speed());
              break;
              case 'F':
                myDrive.move(curState.speed());
             break;
              case 'R':
                myDrive.turn(curState.turnAng(), curState.speed());
              break;
              case 'L':
                myDrive.turn(curState.turnAng(), curState.speed()); 
               break;
            }
  
   }   
   else
   {
     if(!past)
     {
      if(!bitRead(disallow, 2))
         curState.setSpeed(1);
      else
      {
         if(!bitRead(disallow, 1))
              curState.setSpeed(0);
         else
         {
            if(!bitRead(disallow, 0))  
                curState.setSpeed(-1);     
            else
                curState.setSpeed(0);       
         }     
      } 
      myDrive.move(curState.speed());  
     }  
   }   
     
  // ---------------------------------------------------- Memory Section
  if(!past)
  {
      myMem.push(curState.speed(), curState.turnAng());
     
  }
  
  // --------------------------------------------------- Final Section
  act = '?';
  prevState = curState;
  deltaTime = millis() -  prevTime;
  if(past)
     myLED.led('B'); 
  else
     myLED.led(curState.led()); 
  if((deltaTime < 100)&&(deltaTime > 0))
       delay(100 - deltaTime);
  
  
}

Ссылки на библиотеки, схемы и т. д. в теме моей группы: https://vk.com/topic-73778892_35223613

zhenious
Offline
Зарегистрирован: 03.07.2014

Пульт управления. 

Состав пульта: Ардуино Нано, джойстик, клавиатура на 5 кнопок, передатчик 433МГц.

Питание от Li-ion аккумулятора на 9В.

 

Текущий скетч для пульта:

 #include <VirtualWire.h>
 
       int VRx;
       int VRy;
       int SW;
       int adc_key_val [5] = {1, 140, 300, 490, 710};
       int key = -1;
       unsigned long curTime;
       char act, prevAct;
       char *msg = "kema";
void setup() {                

  Serial.begin(9600);  
   vw_set_ptt_inverted(true); // Required for DR3100
   vw_setup(2000);	 // Bits per sec

}

// the loop routine runs over and over again forever:
void loop()
{
       
       VRx = analogRead(0);
       
       if(VRx < 200) 
       {
          act = 'L';
          msg = "kemaL";
          curTime = millis();
       }   
       if(VRx > 800) 
       {
          act = 'R';
          msg = "kemaR";
          curTime = millis();
       }
       VRy = analogRead(1);
       //Serial.println(VRy);
       if(VRy < 200) 
       {
          act = 'F';
          msg = "kemaF";
          curTime = millis();
       }   
       if(VRy > 800) 
       {
          act = 'B';
          msg = "kemaB";
          curTime = millis();
       }
       
       key = get_key (analogRead (3));
       switch (key)
       {
          case 0: 
            act = 'M';
            msg = "kemaM";
            curTime = millis();
          break;
          case 1: 
          
          break;
          case 2: 
             
          break;
          case 3: 
            act = 'P';
            msg = "kemaP";
            curTime = millis();
          break;
          case 4: 
            act = 'S';
            msg = "kemaS";
            curTime = millis();
          break;
      }
                
       if(prevAct != act)  
       {     
           //Serial.println(act);  
           vw_send((uint8_t *)msg, strlen(msg));
           vw_wait_tx(); 
       }    
       if(( millis() - curTime) > 500)
            act = '?';
      
       prevAct = act;
       delay(200);
}

int get_key (unsigned int input)
{
   int k;
   int delta;
   if(input != 1023)
       Serial.println(input);
   for (k = 0; k < 5; k++)
   {
      delta = input - adc_key_val [k];
      if (abs(delta) < 40)
             return k;
       
   }
   if (k >= 5) k = -1; // No valid key pressed
   return k;
}

 

zhenious
Offline
Зарегистрирован: 03.07.2014

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

Видео https://vk.com/video-73778892_456239019

zhenious
Offline
Зарегистрирован: 03.07.2014

Добавил простой класс для работы с датчиками столкновения:

KemaCrash.cpp:

#include "Arduino.h"
#include "KemaCrash.h"

KemaCrash::KemaCrash(int crashL, int crashR)
{
 	_crashL = crashL;
	_crashR = crashR;
  pinMode(_crashL, INPUT);  
  pinMode(_crashR, INPUT);
 
}

int KemaCrash::pingL()
{
	  return digitalRead(_crashL);
}

int KemaCrash::pingR()
{
	  return digitalRead(_crashR);
}

KemaCrash.h:

#ifndef KemaCrash_h
#define KemaCrash_h

#include "Arduino.h"

class KemaCrash
{
  public:
    KemaCrash(int crashL, int crashR);
	int pingL();
	int pingR();
  private:
    int _crashL;
	int _crashR;
};

#endif

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Я бы организовал классы так. Полный скетч здесь  https://yadi.sk/d/d85yc6tx3EzPQg

Головной файл выкладываю.

/*Class_KemaCrash.ino  
*/
// датчики
#include "Cl_KemaCrash.h"
const byte KemaCrashLeft_pin = 2;
Cl_KemaCrash KemaCrashLeft(KemaCrashLeft_pin);
void Do_KemaCrashLeft() {
  Serial.println("Stop");
}
const byte KemaCrashRight_pin = 3;
Cl_KemaCrash KemaCrashRight(KemaCrashRight_pin);
void Do_KemaCrashRight() {
  Serial.println("Stop");
}
void setup() {
  Serial.begin(9600);
  // датчики
  KemaCrashLeft.setup();
  KemaCrashRight.setup();
}

void loop() {
  // датчики
  KemaCrashLeft.loop (& Do_KemaCrashLeft);
  KemaCrashRight.loop(& Do_KemaCrashRight);

}

Вы же делаете машинку для Реального времени. Так пусть сами датчики и командуют остановку в опасных ситуациях.

zhenious
Offline
Зарегистрирован: 03.07.2014

Хорошо сделано, не спорю. 

Но изначально у меня была концепция такая, что датчики не должны командовать, это не их дело. 

Командовать должен "мозг" , а датчики лишь давать показания, когда их об этом попросят.

В моем случае опрос датчиков в основном скетче идет 10 раз в секунду, этого хватает в данном проекте. 

zhenious
Offline
Зарегистрирован: 03.07.2014

Установил новые моторы. В связи с этим появилось несколько изменений:

1. Добавил дополнительно 2 аккумулятора (их стало 8 шт.), чтобы напряжение было 9В.

2. Блок с аккумуляторами закрепил под днищем колесного робота.

3. Так как редукторы малооборотистые, то достаточно стало 2-х скоростей.

Изменения в скетче и классе KemaDrive для Ардуино будут позже.

Схемы, скетчи и ссылки на детали в теме: https://vk.com/topic-73778892_35223613

jeka_tm
jeka_tm аватар
Offline
Зарегистрирован: 19.05.2013

и сколько ты его уже делаешь? еще с идеи, набросков, рисунков и т.д.

zhenious
Offline
Зарегистрирован: 03.07.2014

с весны 2014-го, но почти с 2-х летним перерывом)

то была 1я версия, а текущая версия с конца 2016 г

jeka_tm
jeka_tm аватар
Offline
Зарегистрирован: 19.05.2013

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

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Блин.. озадачили. Одни мы с сыном чтоли практически за неделю вот это наклепали, причем "из говна и палок", а оно ещё и лучший результат на России показало? :)

jeka_tm
jeka_tm аватар
Offline
Зарегистрирован: 19.05.2013

а что ты хотел, один делает несколько лет, а двое за неделю))

zhenious
Offline
Зарегистрирован: 03.07.2014

научил своего робота поворачивать)

Оставил две скорости, мощности моторов достаточно, чтобы колесный робот поворачивался:

https://youtu.be/dissl3xMw9Y

jeka_tm
jeka_tm аватар
Offline
Зарегистрирован: 19.05.2013

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