Радиоуправляемый гусеничный вездеход

kavboy84
Offline
Зарегистрирован: 02.11.2016

Нашел дома вездеход Тайга. Примерно такого вида:

Решил сделать его радиоуправляемым с минимальными затратами (пока получается по затратам 600 рублей, 2 шт. 18650 у меня уже есть). 

Заказывать детали буду на алиэкспрессе.

Возникло несколько вопросов:

По передатчику.

Джойстики cмогут работать от напряжения 3.3 В, или им строго необходимо 5В? Если могут, тогда можно купить Arduino Pro mini 3.3 В Atmega168, запитать ее от 3-х АА батареек и выкинуть из схемы преобразователи напряжения MT3608 и AMS1117.

По приемнику.

1. Двигатели пока хотел оставить стоковые, это 2-шт МП-3-015 номинальное напряжение 3.6В, ток 0.5А. У регулятора двигателей L298N минимальное входное напряжение 6 В, получается его на мои двигатели нельзя ставить? Регулятор двигателя L9110S справится с этими двигателями? 

2. Из-за приемника NRF24L01, у ардуино остается только 3 пина с ШИМ, можно регулировать обороты и направление обоих двигателей с помощью регулятора двигателя L9110S и 2-мя пинами с ШИМ и 2-мя пинами без ШИМ?

 

 

 

 

 

 

 

kavboy84
Offline
Зарегистрирован: 02.11.2016
Нашел альтернативный регулятор двигателей TB6612FNG. Для управления скоростью 2-х двигателей вроде достаточно 2-х пинов с ШИМ.
Как я понял из даташитов, он по мощности схож с L298N,
но дешевле и рабочее напряжение от 2.5 В до 13.5 В. 
А управляющее напряжение 2.7-5.5 В в отличие от L298N с его 4.5-5.5 В.
Поэтому можно будет на приемник поставить Arduino Pro Mini 3.3 В и выкинуть AMS1117. 
Xumuk
Xumuk аватар
Offline
Зарегистрирован: 03.03.2016

я видел в инете делали на 3.3 вольта ардуину с джостиком, ему без разницы там только сопротивления и все

Phoenix
Phoenix аватар
Offline
Зарегистрирован: 02.11.2016

джостики - от любого напряжения, там просто стоит подстроечный резистор или переменный, как нравится. По сути работает как делитель напряжения.
Можно использовать и 1 джостик для управления машинкой, будет несколько сложнее описание кода, если делать "красиво".

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

Касательно управления ШИМ оборотами двигателя - они работают, но не так хорошо как "чистый аналог".

Скажу сразу, что при аналоговом управлении (скорость через шим) будет "мёртвая зона" - т.е. когда не будет хватать крутяшего момента что бы сдвинуть колесо с места. Так что рабочий диапазон "analogWrite" будет скорее всего где то между 150-255 . Если поднять напряжения питания - то вырастет. Но тут забегая вперёд можно "обыграть", я в своё время решал этот вопрос давая "255" на 0,3-0,5 сек, а потом уже нужную скорость. Как бы навалил что бы тронуться а потом чисто как надо ползти.

Смотреть надо сколько ваши моторчики жрут в КЗ, которое будет при блокировании вала - и надо что бы драйвер "переваривал" такой ток, а то врежитесь в препядствие и приедете на драйвер, который будет ещё 30 дней к вам ехать новый.

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

Можно использовать тормоз двигателем, это когда одновременно "полный вперёд" и "полный назад".

Мне лично не нравится понижающий приобразователь на моторах, что он выдаст 1А - терзают сомнения (два двигателя по 0,5А каждый), да и его целесообразность вовсе.

Если там внутри советские же моторчики - рекомендую сразу разобрать и выки...смазать. Даже с новья они не ахового качества увы-с.

Ещё о птичках можно немножко поэксперементировать, ATMega вполне сносно переносит пониженное напряжение (если питать на прямую от АКБ 18650) .

Можно найти комплектующие в РФ - по более-менее адекватной цене.

Okmor
Okmor аватар
Offline
Зарегистрирован: 16.10.2015

Джойстик

//Джойстик
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>

#define CE_PIN   9
#define CSN_PIN 10

#define JOYSTICK_X A0
#define JOYSTICK_Y A1
#include <Wire.h>
#include <OzOLED.h>

unsigned long CTime01;
unsigned long LTime01;
unsigned long txIntervalMillis = 10;

const uint64_t pipe = {0xF0F0F0F0E1LL};
unsigned long distance_sm=0;  // Эта переменная для сбора обратного сообщения о
int EHOArray[10];
RF24 radio(CE_PIN, CSN_PIN); 
    //CE/SS - Выбор ведомого на шине SPI из нескольких устройств.
    //SCN - выбор режима приема/передача , фактически тот же CE.
    
int joystick[8];
int XnulPos;
int YnulPos;

void setup()
{
  Serial.begin(9600);
  radio.begin();
  delay(100);
  radio.enableDynamicPayloads();
  radio.openReadingPipe(1,pipe);
  radio.openWritingPipe(pipe); //Открывем трубу для отправки
  radio.startListening();

  pinMode(2 , INPUT_PULLUP) ; //вогонь
  pinMode(3 , INPUT_PULLUP) ; //вправо
  pinMode(4 , INPUT_PULLUP) ;
  pinMode(5 , INPUT_PULLUP) ; // влыво
  pinMode(6 , INPUT_PULLUP) ;
  pinMode(7 , INPUT_PULLUP) ;

  

 
  pinMode(A2, OUTPUT);
  digitalWrite(A2, HIGH);

 XnulPos = analogRead(JOYSTICK_X);
 YnulPos = analogRead(JOYSTICK_Y);

  pinMode(A2, OUTPUT);
  pinMode(A3, OUTPUT);
  digitalWrite(A2, LOW);
  digitalWrite(A3, HIGH);
  delay(100);
  OzOled.init();  //initialze Oscar OLED display
  OzOled.printString("Hello Illya"); //Print the String 
  
 }


void loop()   
{
  
  if ( radio.available() ) {
       radio.read( &EHOArray,sizeof(EHOArray) );
       Serial.println(String(EHOArray[0])+" | "+(EHOArray[1])+" | "+(EHOArray[2])+" | "+(EHOArray[3])+" | "+(EHOArray[4])+" | "+(EHOArray[5])+" | "+(EHOArray[6])+" | "+(EHOArray[7])+" | "+(EHOArray[8])+" | "+(EHOArray[9])+" | ");
      };
   
    CTime01 = millis();
    if (CTime01 >= (LTime01 +100))
    {
       //Serial.println(joystick[1]); 
       JoystickRead();
       radio.stopListening();  //Перестаем слушать
       radio.write( joystick, sizeof(joystick) ); // Отправляем ответ
       radio.startListening();  
       LTime01 = CTime01; 

    }
    
}




void JoystickRead ( )
{
  joystick[0] = !digitalRead(2) ; //вогонь
  joystick[1] = !digitalRead(3) ; //вправо
  joystick[2] = !digitalRead(4) ;
  joystick[3] = !digitalRead(5) ; // влыво
  joystick[4] = !digitalRead(6) ;
  joystick[5] = !digitalRead(7) ;

  joystick[6] = analogRead(JOYSTICK_X); //A0
  joystick[6] = constrain(map(joystick[6],0,XnulPos*2,-255,255),-255,255); 
  
  joystick[7] = analogRead(JOYSTICK_Y); //A1
  joystick[7] = constrain(map(joystick[7],0,YnulPos*2,-255,255),-255,255);
  
}




 

Okmor
Okmor аватар
Offline
Зарегистрирован: 16.10.2015

Танк

//Танк
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <Servo.h>
#include <IRremote.h> 


                //0       --------------------------
                //1       --------------------------
                //2        Gереривання Ультразвук.Echo
                //3        Інфрачервоний діод +
#define Trig      4       //Ультразвук.Trig 
#define LSp       5       //Ліва швидкість
#define RSp       6       //Права швидкість
#define RECV_PIN  7       //Пін інфрачервоного датчика
#define Mosfet    8       //Живлення ультразвуку
#define PinTower  9       //ШІМ серво башти
#define PinEHO    10      //ШІМ серво локатора
                //11        nRF24L01.MOSI
                //12        nRF24L01.MISO
                


#define LBk       A5
#define RBk       A4
#define LFr       A3
#define RFr       A2
#define CSN_PIN   A1 // nRF24L01.CSN
#define CE_PIN    A0 // nRF24L01.CE
                //D13   nRF24L01.SCK

// Ультразвук та ехо
Servo myservoEHO;
int PrAngleEHO = 0;
int AngleEHO = 0;
int EHOArray[10];
uint32_t message = 12345;
unsigned long impulseTime=0; 
unsigned long impulseSTime=0;
unsigned long distance_sm=0;


//Пушка
IRsend irsend;
IRrecv irrecv(RECV_PIN);
decode_results results;
Servo myservoTower;
int AngleTower = 0;


//Передатчик
const uint64_t pipe = {0xF0F0F0F0E1LL};
RF24 radio(CE_PIN, CSN_PIN); 
int joystick[8];



//Всякі таймери
unsigned long CTime01;
unsigned long LTime01;
unsigned long CTime02;
unsigned long LTime02;
unsigned long LTime03;






void setup()   
{
  pinMode(Mosfet, OUTPUT);  digitalWrite(Mosfet, HIGH); 
  delay(300);
  Serial.begin(9600); 
  radio.begin(); // будет следующей необходимой командой - пора начинать!
  delay(300);  
  radio.enableDynamicPayloads();
  radio.openReadingPipe(1,pipe);
  radio.openWritingPipe(pipe); //Открывем трубу для отправки
  radio.startListening();

  pinMode(LSp, OUTPUT);
  pinMode(RSp, OUTPUT);

  pinMode(RFr, OUTPUT);
  pinMode(LFr, OUTPUT); 

  pinMode(RBk, OUTPUT);
  pinMode(LBk, OUTPUT);

  myservoEHO.attach(PinEHO);
  myservoEHO.write(90);
  myservoTower.attach(PinTower);
  myservoEHO.write(80);
  AngleTower = 80;
  pinMode(Trig, OUTPUT); //инициируем как выход 
  irrecv.enableIRIn(); // Start the receiver
 
  
}


void loop()  
{

    
    if (irrecv.decode(&results)) {
        if (results.value==2704) {
          pinMode(3, OUTPUT);  digitalWrite(3, HIGH);   delay(1000);   digitalWrite(3, LOW);   pinMode(3, INPUT);}
          irrecv.resume(); // Receive the next value
        };

  if ((!LTime03==0) && (LTime03-millis()>5)) {  digitalWrite(Mosfet, HIGH); LTime03=0  ;};    //Костиль таймера
  if ( radio.available() ) {
       radio.read( joystick, sizeof(joystick) );
       MotorDrive(joystick[6], joystick[7]); 
       RotateTower(joystick[3], joystick[1]);
       if (!joystick[0]==HIGH) {  irsend.sendSony(0xa90, 12); };
       irrecv.enableIRIn(); 
      };
   
    CTime02 = millis();
    if (CTime02 >= (LTime02 +100))
    {
      // Serial.println("----------write------------"); 
       radio.stopListening();  //Перестаем слушать
       radio.write(&EHOArray, sizeof(EHOArray));
       //radio.write(&distance_sm, sizeof(distance_sm));
       radio.startListening(); 
       
       LTime02 = CTime02; 
       message++;
    }
  NextStepEHO();

  
  }

 void RotateTower(int Rleft, int Rright)
 {
    
   if (Rleft == 0 )   {  AngleTower = AngleTower+5 ; };
   if (Rright == 0 )   {  AngleTower = AngleTower-5 ; };
   
   AngleTower = constrain(AngleTower,10,170);
   //Serial.println(String(Rleft)+"  "+String(Rright)+"  "+String(AngleTower));
   myservoTower.write(AngleTower);
  
  //int AngleTower = 0;
 ;
 }

 void MotorDrive ( int X, int Y )
 {

     int LSpeed = DeadZone(constrain(Y+X, -255, 255),-5,5);
     int RSpeed = DeadZone(constrain(Y-X, -255, 255),-5,5);

     analogWrite(LSp, abs(LSpeed));
     analogWrite(RSp, abs(RSpeed));
     MotorFrBk (LSpeed, LFr, LBk );
     MotorFrBk (RSpeed, RFr, RBk );

  }

void MotorFrBk (int Speed, int PinFr, int PinBk ) // Вперед / назад
{
    switch (constrain(Speed, -1, 1)) {
    case  1:   {digitalWrite(PinFr, HIGH); digitalWrite(PinBk, LOW); break;}
    case -1:   {digitalWrite(PinFr, LOW); digitalWrite(PinBk, HIGH); break;}
    default:   {digitalWrite(PinFr, LOW); digitalWrite(PinBk, LOW);} 
    }
}

void NextStepEHO()
{ CTime01 = millis();
  if (CTime01 >= (LTime01 +300))
  {

    
      {// Запуск виміру дистанції
      impulseSTime = 0; impulseTime = 0;       
      digitalWrite(Trig, HIGH);  delayMicroseconds(10);  digitalWrite(Trig, LOW); // Запуск ехо 
      attachInterrupt(0, Interrupt, RISING ); //Ставимо переривання на 2гу ногу
      };
     PrAngleEHO = AngleEHO;
     ++AngleEHO;  //Закінчили і перескакуємо на наступний крок.  
     if ( AngleEHO>17 ) {AngleEHO = 0 ;};
     LTime01 = CTime01;
  };
  
  if ((CTime01 >= (LTime01 +50)) && !(PrAngleEHO == AngleEHO)) // Поворот та відправку пакету вимірів робимо з запізненням
  {    
   
   {// Розрахунок попередньої дистанції
      distance_sm = impulseTime/58; 
      if (impulseTime < 100)  {
          LTime03 = millis();
          digitalWrite(Mosfet, LOW);
          distance_sm = 0;
      } else
      EHOArray[AngleToPoint(PrAngleEHO)] = distance_sm;
    };
   myservoEHO.write(20+AngleToPoint(AngleEHO)*10); //*******************************
  // myservoTower.write(20+AngleToPoint(AngleEHO)*10); //*******************************
   PrAngleEHO = AngleEHO;
  }
  
}

int AngleToPoint(int Angle)
{ int result ;
  if ( Angle<=9) {result=Angle ;} else {result=18-Angle;};
  return result;
}

void Interrupt ()
{ 
  if (impulseSTime == 0) 
                    {impulseSTime = micros();
                     attachInterrupt(0, Interrupt, FALLING );
                    }
     else           {impulseTime = micros()-impulseSTime ;
                     detachInterrupt(0);
                    }
                    
}



int DeadZone (int Val, int MinVal, int MaxVal) // Мертва зона
   { 
    if ((Val >= MinVal) && (Val <= MaxVal) )  return 0;  else return Val; 
   }

   
   

       
  

 

Okmor
Okmor аватар
Offline
Зарегистрирован: 16.10.2015

Вот мой немного сырой код.

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

Разработка работает на стандартном шильде джойстика.

NRF я запитал от 3,3В Arduino NANO без согласования уровней.

Ультразвуковой датчик постоянно зависает (есть такая болезнь), потому его время от времени надо перегружать через мосфэт транзистор. Ультразвуковой датчик реализован на прываниях. От стандартной библиотеки я отказался ввиду ее тормознутости.

Проект не доделанный. Я хотел на дисплее джойстика рисовать карту, но руки не доходят.

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

Okmor
Okmor аватар
Offline
Зарегистрирован: 16.10.2015

И еще.

Преобразователь DC-DC UP моторы не потянул. Драйвер моторов я запитал напрямую от двух аккумуляторов 3,7+3,7=7,4В.

Okmor
Okmor аватар
Offline
Зарегистрирован: 16.10.2015

Шасси я брал здесь, но теперь взял бы дешевле на барахолте игрушек.

Okmor
Okmor аватар
Offline
Зарегистрирован: 16.10.2015

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

kavboy84
Offline
Зарегистрирован: 02.11.2016

Okmor пишет:

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

Если использовать эту плату с ams1117, то конденсаторы уже на nrf24 припаивать не нужно?

Какой вы драйвер двигателя использовали? Такой вроде неплохой TB6612FNG

 

 

 

 

Okmor
Okmor аватар
Offline
Зарегистрирован: 16.10.2015

kavboy84 пишет:

Если использовать эту плату с ams1117, то конденсаторы уже на nrf24 припаивать не нужно?

Какой вы драйвер двигателя использовали? Такой вроде неплохой TB6612FNG

1. Конденсаторы по питанию обязательно припаять на сам передатчик NRF, эсли его будете втыкать через панельку. Я припаял поверх платы 220мФ. Зачем вам эта плата? да и с ней все равно адо конденсаторы.

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

stc-alex
Offline
Зарегистрирован: 06.11.2016

я игрок WoT и создал в железе!!! копию ПТ САУ Ferdinand .... все сделано - корпус - дюраль 8см,ходовая - вся точена из стали,капролона и т.п. , гусеницы - цепи ГРМ от двигателя ВАЗ -06, -07...  двигателя - мощные BLDC от коники- проявочных фотомашин... а вот с контроллером ж...па - че поставить даж не знаю, чтоб по воздуху им управлять....  есть курсовая камера и приемный монитор.... это работает - видео идет 1-км стабильно. а вот управление.....   я не могу (просто не укладывается в голове) освоить программирование....  пока все работает со старинного ,еще совкового, конструктора - контроллера на БИС кр19ххВИ5 ....

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

 

кстати есть масса ШД и драйверов разных на токи от1.5 до 7-и А...  если кому надо пишите отошлю...  все выковыряно из банкоматов....  моторы от типа NEMA22 до NEMA57 и больше.

kavboy84
Offline
Зарегистрирован: 02.11.2016

Phoenix пишет:

Смотреть надо сколько ваши моторчики жрут в КЗ, которое будет при блокировании вала - и надо что бы драйвер "переваривал" такой ток, а то врежитесь в препядствие и приедете на драйвер, который будет ещё 30 дней к вам ехать новый.
 

Подскажите, как с помощью простого мультиметра померить стартовый ток и ток при блокировке вала?

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

Стартовый практически никак, но он в целом равен току при блокировке вала. Последний измеряется просто: блокируете вал и подаете напругу через токоизмерялку, смотрите - радуетесь или наоборот. Прежде чем измерять сильно рекомендую померять сопротивление якоря через контакты мотора и покрутив плавно вал туда-сюда для поиска оптимального контакта щеток. После чего делите предполагаемое напряжение питания на это сопротивление и считаете ожидаемый пусковой ток и ток КЗ.

Xumuk
Xumuk аватар
Offline
Зарегистрирован: 03.03.2016

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

Phoenix
Phoenix аватар
Offline
Зарегистрирован: 02.11.2016

kavboy84 пишет:

Phoenix пишет:

Смотреть надо сколько ваши моторчики жрут в КЗ, которое будет при блокировании вала - и надо что бы драйвер "переваривал" такой ток, а то врежитесь в препядствие и приедете на драйвер, который будет ещё 30 дней к вам ехать новый.
 

Подскажите, как с помощью простого мультиметра померить стартовый ток и ток при блокировке вала?

Собственно поддержу уже данный ответ. Лучше всего произвести математические расчёты, измерив сопротивление обмотки мотора, затем зная напряжение питания - вычислить максимальный ток. Иметь про запас хотя бы 20% от ширины канала.

Если более "на коленках" или популярно ответить, лень считать.

Берём мультиметр, переводим в режим измерения тока (в пределах 2А постоянного), перетыкиваем красный щуп, в гнездо с ограничением тока (обычно помечено что не более 10А ).

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

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

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

Если более 600 мА - l293 - не подходит
Если показания более 1А - ваш текущий драйвер двигателя не подходит.
Если больше 2А - l298 не походит.

К примеру замерил  МП-3-003 - потребление до 1,5А при 3,7В - но у вас другая модель, отличия не знаю.

Пусковой ток - такой же как и при блокировке, но его длительность мала, и может быть в пределах допустимого импульса да драйвере. К примеру l293 даёт постоянный ток до 600 мА, а импульс может пережить до 1А. Тут вопрос в том что когда вырешите залезть на вездеходе туда, куда он не сможет залезть, или тащить слишком тяжёлое - просто колёса не смогут прокрутиться и будет блокировка вала.

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

Если шасси китайское или от современных игрушек, то там стоят типовые 130-DC motor, с редукторами от 80:1 до 140:1 и если там гнезда под 4 батарейки (6в), то с большой долей вероятности, что пусковой ток там в районе 1-2А при ходовом потреблении в 0.4-0.6А. Если шасси с ещё советскими МПхх, МДПхх и т.д., то они все были 0.5А ходового тока с около 1А пускового и у них невысокая скорость ХХ - что-то в районе 6-10тыс. об/мин., против 12-20тыс для 130-го мотора.

Так, на память из детства. :)

P.S. Правильнее поменять на 130 мотор. И меньше и лучше.

Ну вот примерно так:

Р/У модель танка Т-34 от "Звезды", масштаб 1:35. Радиоуправление 27Мгц снято с какой-то китайской машинки, купленной в году так 2008 рублей за 250 ..