Фиксиход - тележка с манипулятором и водометом

Начну с небольшой предыстории:

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


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

Начал с поиска чего либо интересного в интернет магазинах. и на разных форумах.
нашел такой вариант:


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

платформа: Wild Thumper 6WD Black 75:1 with 2 encoders


плата управления TREX controller — он же ардуино контролер.


так же для управления потребовался блютус модуль HC-06


для водомета были куплены такие детали:

2х осевой вращатель камеры


Сервопривод Tower Pro 9g SG90 две штуки:


Водяной насос (помпа)


комплект капельницы из аптеки(гибкий шланг)

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

но меня ждали ГРАБЛИ :)

1. моя ошибка — источник питания, я наивно полагал что простых батареек для теста хватит. для работы ардуино — вполне, для двигателей НЕТ!


далее из одной крайности в другую:


тяжелый свинец на 12в 7,4 амперчаса…
из за тяжелого веса и повышенной мощности, от резких стартов была сорвана шестерня в редукторе, найти нужную не удалось, пришлось заказывать с интерет магазинов мотор редуктор в сборе.



2. основная проблема, которая отняла много времени и сил — «хитрая» плата управления.
дело в том что на ней изначально есть разъем для подключения блютус модуля, и если в него включить модуль этого же производителя, то все заработает, если стороннего то нет!
все дело в том что сигнальные контакты RX и TX нужно менять местами!

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



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

на первом, полноценном этапе получилось такое чудо:



машина с 6х6 с тяжелым акумом и водометом. в качестве кнопки включения служила старая пробка :)

а тут видео как это работало:


на данный момент у меня такая тележка:

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




в качестве аккумуляторов было решено использовать «банки» от испорченного ноутбучного акума. всего 6 банок.


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


вместо старой пробки был куплен новый пакетник :)


на видео машина используется по назначению — развлекает детей на детском празднике.


а тут презентационный ролик ))


испытания проходимости


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



для управления использую смартфон, и приложение BTCA2A



подробнее о нем можно почитать: robocontroller.ru/news/btca2a_upravlenie_arduino_po_bluetooth_pri_pomoshhi_android/2013-11-16-40

проект находиться в стадии разработки, ожидаю с недели на неделю новые запчасти, а именно механизм стрельбы 6мм шариками от модели танков. буду делать пушку :)

забыл выложить скетч:
// Скетч для управления через блютус, Wild Thumper 6WD, на ардуино совместимом контролере TREX controller. реализовано движение и стрельба с водомета, захват клешней манипулятором. 
// по вопросам и предложениям писать на почту slom1@list.ru 
// новые фото и видео можно найти на www.шоуальянс.com

#include <BTCA2ALite.h>// Добавляем библиотеку блютус программы
#include <Servo.h> // Добавляем библиотеку серво

Servo myservoH; // Горизонтальная серва углы от 0 до 180 (центровка 89)
Servo myservoV; // Вертикальная серва углы от 1 до 45
Servo myservoZ; // серва Клешня
Servo myservoR; // серва рука клешни
const int Z_SERVO_PIN = 5; // добовляем пин захвата
const int R_SERVO_PIN = 6; // добовляем пин руки манипулятора
const int H_SERVO_PIN = 7; // Горизонтальная серва подключена к пину 7
const int V_SERVO_PIN = 8; //Пин вертикального сервопривода 8
const float Z_L_ANGLE = 116; // Максимальные угл поворота башни налево
const float Z_R_ANGLE = 45; // Максимальные угл поворота башни направо
const float Z_DEF_ANGLE = 50; // Дефолтный угол (центровка)
const float R_L_ANGLE = 170; // Максимальные угл поднятия руки
const float R_R_ANGLE = 3; // Максимальные угл наклона руки
const float R_DEF_ANGLE = 160; // Дефолтный угол руки
const float H_L_ANGLE = 180; // Максимальные угл поворота башни налево
const float H_R_ANGLE = 0; // Максимальные угл поворота башни направо
const float H_DEF_ANGLE = 84; // Дефолтный угол (центровка)
const float V_U_ANGLE = 175; // Максимальные угл поворота башни вверх
const float V_D_ANGLE = 125; // Максимальные угл поворота башни вниз
const float V_DEF_ANGLE = 160; // Дефолтный угол (центровка)
//Размер шага V_STEP и H_STEP побираем экспериментально для достижения нужной скорости поворота серв
const float V_STEP = 0.012; // Шаг - знаение отвечающее за скорость вращения по вертикали.
const float H_STEP = 0.012; // Шаг - знаение отвечающее за скорость вращения по горизонтали
const float Z_STEP = 0.012; // шаг захвата
const float R_STEP = 0.012; // шаг руки
float curVAngle = V_DEF_ANGLE; //Переменная текущего угла верт. сервы
float curHAngle = H_DEF_ANGLE; //Переменная текущего угла гор. сервы
float curZAngle = Z_DEF_ANGLE; //
float curRAngle = R_DEF_ANGLE; //
bool moveServoVUp = false; //Флаг движения верт. сервы вверх
bool moveServoVDown = false; //Флаг движения верт. сервы вниз
bool moveServoHLeft = false; //Флаг движения гор. сервы влево
bool moveServoHRight = false; //Флаг движения гор. сервы вправо
bool moveServoZLeft = false; //Флаг движения гор. сервы влево
bool moveServoZRight = false; //Флаг движения гор. сервы вправо
bool moveServoRLeft = false; //Флаг движения гор. сервы влево
bool moveServoRRight = false; //Флаг движения гор. сервы вправо

btca2aLite btca2aLite; // Конструктор btca2aLite


// задаем пины для левого мотора
#define Dir_L 2
#define Pwm_L 3
#define Brake_L 4
// задаем пины для правого мотора
#define Dir_R 10
#define Pwm_R 11
#define Brake_R 9

// Задаем скорости для движения
byte MaxSpeed = 230; // Максимальная скорость
byte MinSpeed = 90;  // Минимальная скорость

int forw_back = 0;
int righ_left = 0;

byte step_fb = 5;     // Шаг изменения скорости движения вперед - назад
byte step_stop = 10;  // Шаг изменения скорости остановки
byte step_rl =  10;    // Шаг изменения скорости движения вправо - влево
byte step_dir = 10;   // Шаг изменения скорости выравнивания



#define SHOT  12 // пин для водомета

enum States
{
    WAITING,
    READING,
    RUNNING,
    ERROR,
    TIMEOUT
};

States state;
States onWait();
States onRead();
States onRun();
States onError();

States onTimeout();

void performServo(); // добовляем сервы


void setup(){
    Serial.begin(9600); // Скорость BT и порта должна быть 9600
    //Моторы
    pinMode (Pwm_L, OUTPUT);
    pinMode (Dir_L, OUTPUT);
    pinMode (Brake_L, OUTPUT);
    
    pinMode (Pwm_R, OUTPUT);
    pinMode (Dir_R, OUTPUT);
    pinMode (Brake_R, OUTPUT);
    
    digitalWrite (Pwm_L, LOW);
    digitalWrite (Pwm_R, LOW);
    
    digitalWrite (Brake_L, LOW);
    digitalWrite (Brake_R, LOW);
  
 pinMode(SHOT, OUTPUT); // задаем выход для стрельбы водой
    
    // устанавливаем пин как вывод управления сервой
    myservoH.attach(H_SERVO_PIN);
    myservoV.attach(V_SERVO_PIN);
    myservoZ.attach(Z_SERVO_PIN);
    myservoR.attach(R_SERVO_PIN);
    myservoH.write(curHAngle);
    myservoV.write(curVAngle);
    myservoZ.write(curZAngle);
    myservoR.write(curRAngle);
    
    //Светодиод
    pinMode(13, OUTPUT); // Инициализируем пин светодиода
    digitalWrite(13, HIGH); // Светодиод выключен
}

void loop(){
    
    btca2aLite.ReadCommand(); // Считывание принятых команд (кодов кнопок)
    //Вызываем функцию управление сервами
    performServo();
    
 //этот код для меня темный лес, мне его дали для плавного старта и торможения моторов. если ехать вперед и резко нажать кнопку назад, машина продолжит ехать вперед, плавно остановиться и только потом поедет назад, это спасает редуктора от разрушения. 
 //если ктото знает что тут к чему, прокоментируйте пожалуйста, чтоб я тоже понимал :)
  static unsigned long pre_millis = 0;
  if(millis()-pre_millis > 50)
  {
    pre_millis = millis();
    
    if(btca2aLite.ButtonPressed(KEYCODE_DPAD_UP)) 
    {
      forw_back += step_fb;
      if(forw_back > 0 && forw_back < MinSpeed) forw_back = MinSpeed;
    }
    else if(btca2aLite.ButtonPressed(KEYCODE_DPAD_DOWN)) 
    {
      forw_back -= step_fb;
      if(forw_back < 0 && forw_back > MinSpeed*-1) forw_back = MinSpeed*-1;
    }
    else 
    {
      if(forw_back < 0) forw_back += step_stop;
      else if(forw_back > 0) forw_back -= step_stop;
      if(abs(forw_back) < MinSpeed) forw_back = 0;
    }
    forw_back = constrain(forw_back, MaxSpeed*-1, MaxSpeed);


    if(btca2aLite.ButtonPressed(KEYCODE_DPAD_RIGHT)) 
    {
      righ_left += step_rl;
      if(righ_left > 0 && righ_left < MinSpeed) righ_left = MinSpeed;
    }
    else if(btca2aLite.ButtonPressed(KEYCODE_DPAD_LEFT)) 
    {
      righ_left -= step_rl;
      if(righ_left < 0 && righ_left > MinSpeed*-1) righ_left = MinSpeed*-1;
    }
    else 
    {
      if(righ_left < 0) righ_left += step_dir;
      else if(righ_left > 0) righ_left -= step_dir;
      if(abs(righ_left) < MinSpeed) righ_left = 0;
    }
    righ_left = constrain(righ_left, MaxSpeed*-1, MaxSpeed);


    int pwm_l = forw_back + righ_left;
    int pwm_r = forw_back - righ_left;
    pwm_l = constrain(pwm_l, MaxSpeed*-1, MaxSpeed);
    pwm_r = constrain(pwm_r, MaxSpeed*-1, MaxSpeed);

    digitalWrite(Dir_L, (pwm_l<0)?0:1);
    digitalWrite(Dir_R, (pwm_r<0)?0:1);
    analogWrite(Pwm_L, abs(pwm_l));
    analogWrite(Pwm_R, abs(pwm_r));
  }
        
  //дальше идут кнопки управления
    
    //-------— включение насоса —-------------
   if (btca2aLite.ButtonPressed(KEYCODE_BUTTON_SELECT))
    { 
     digitalWrite (SHOT, HIGH);
     }
    //-------— выключение насоса происходит автоматически после отпускания кнопки—------------- 
   if(btca2aLite.ButtonReleased(KEYCODE_BUTTON_SELECT))
    {
   digitalWrite (SHOT, LOW);
    } 
    
        if(btca2aLite.Button(KEYCODE_BUTTON_START)) // алгоритм автоматического хватания предметов
    {
       
      // машина делает шаг вперед
      digitalWrite (Dir_L, HIGH); 
      analogWrite (Pwm_L, 150); 
      digitalWrite (Dir_R, HIGH); 
      analogWrite (Pwm_R, 150); 
      delay (100);
      // потом стоп
      analogWrite (Pwm_L, 0); 
      analogWrite (Pwm_R, 0); 
      delay (500);

      
       myservoZ.write(45);; // Клешня разжимается 
        myservoR.write(3);; // рука клешни опускаем 
        delay(2000); /* ждем 2 секунды, */
         myservoZ.write(116);; // Клешня сжимаем
         delay(1000); /* ждем 1 секунду, */
          myservoR.write(170);; // рука клешни поднимаем
           delay(600); /* ждем  */
           myservoZ.write(45);; // Клешня разжимаем
    } 
    
    
    //--------— Повороты серв при нажатии кнопок —-------------
    
    if(btca2aLite.Button(KEYCODE_BUTTON_X)) // поворот водомета вниз
    {
        moveServoVDown = true;
              
    }
    if(btca2aLite.Button(KEYCODE_BUTTON_A)) // поворот водомета направо
    {
        moveServoHRight = true;
    }
    if(btca2aLite.Button(KEYCODE_BUTTON_B)) // поворот водомета вверх
    {
        moveServoVUp = true;
              
    }
    
    if(btca2aLite.Button(KEYCODE_BUTTON_Y)) // поворот водомета налево
    {
        moveServoHLeft = true;
    }
    
        if(btca2aLite.Button(KEYCODE_BUTTON_R1)) // зхахват сжать
    {
        moveServoZLeft = true;
    }
    if(btca2aLite.Button(KEYCODE_BUTTON_R2)) // захват разжать 
    {
        moveServoZRight = true;
    }
    
    
           if(btca2aLite.Button(KEYCODE_BUTTON_L1)) // рука клешни вниз
    {
        moveServoRLeft = true;
    }
    if(btca2aLite.Button(KEYCODE_BUTTON_L2)) // рука клешни вверх
    {
        moveServoRRight = true;
    } 
    
    
//--------— чтобы сервы не продолжали движения при отжатых кнопках —-------------    
if(btca2aLite.ButtonReleased(KEYCODE_BUTTON_X))
{
moveServoVDown = false;
}
if(btca2aLite.ButtonReleased(KEYCODE_BUTTON_B))
{
moveServoVUp = false;
}

if(btca2aLite.ButtonReleased(KEYCODE_BUTTON_A))
{
moveServoHRight = false;
}
if(btca2aLite.ButtonReleased(KEYCODE_BUTTON_Y))
{
moveServoHLeft = false;
}
 
 if(btca2aLite.ButtonReleased(KEYCODE_BUTTON_R2))
{
moveServoZRight = false;
}
if(btca2aLite.ButtonReleased(KEYCODE_BUTTON_R1))
{
moveServoZLeft = false;
}   
    
 if(btca2aLite.ButtonReleased(KEYCODE_BUTTON_L2))
{
moveServoRRight = false;
}
if(btca2aLite.ButtonReleased(KEYCODE_BUTTON_L1))
{
moveServoRLeft = false;
}       
    
    
    //----------------— Стоп —---------------------
    
    // Если не нажата ни одна кнопка курсора происходит остановка, скорость 0 для каждого мотора
    if (btca2aLite.ButtonReleased(KEYCODE_DPAD_UP) && btca2aLite.ButtonReleased(KEYCODE_DPAD_DOWN) && btca2aLite.ButtonReleased(KEYCODE_DPAD_LEFT) && btca2aLite.ButtonReleased(KEYCODE_DPAD_RIGHT)){
        analogWrite (Pwm_L, 0);
        analogWrite (Pwm_R, 0);
    }
}



//Функция управления сервоприводами (вызывается в теле loop на каждой итерации)
//Выполняет изменения положения серв на подобранный шаг согласно установленным флагам движения
//Флаги устанавливаются согласно поступившим символам управления сервами
void performServo()
{
    //Установлен флаг движения вверх и текущий угол не максимальный
    if (moveServoVUp && curVAngle + V_STEP <= V_U_ANGLE)
    {
        //К текущему верт. углу прибавляем шаг
        curVAngle += V_STEP;
    }
    //Установлен флаг движения вниз и текущий угол не минимален
    else if (moveServoVDown && curVAngle - V_STEP >= V_D_ANGLE)
    {
        //От текущего верт. угла отнимаем шаг
        curVAngle -= V_STEP;
    }
    //Установлен флаг движения влево и текущий угол не максимален
    if (moveServoHLeft && curHAngle + H_STEP <= H_L_ANGLE)
    {
        //К текущему гор. углу прибавляем гор. шаг
        curHAngle += H_STEP;
    }
    //Установлен флаг движения вправо и текущий угол не минимален
    else if (moveServoHRight && curHAngle - H_STEP >= H_R_ANGLE)
    {
        //От текущего угла отнимаем гор. шаг
        curHAngle -= H_STEP;
    }
    
    //Установлен 
    if (moveServoZLeft && curZAngle + Z_STEP <= Z_L_ANGLE)
    {
        //К текущему гор. углу прибавляем гор. шаг
        curZAngle += Z_STEP;
    }
    //Установлен флаг движения вправо и текущий угол не минимален
    else if (moveServoZRight && curZAngle - Z_STEP >= Z_R_ANGLE)
    {
        //От текущего угла отнимаем гор. шаг
        curZAngle -= Z_STEP;
    }
    
    
        //Установлен 
    if (moveServoRLeft && curRAngle + R_STEP <= R_L_ANGLE)
    {
        //К текущему гор. углу прибавляем гор. шаг
        curRAngle += R_STEP;
    }
    //Установлен флаг движения вправо и текущий угол не минимален
    else if (moveServoRRight && curRAngle - R_STEP >= R_R_ANGLE)
    {
        //От текущего угла отнимаем гор. шаг
        curRAngle -= R_STEP;
    }
    
    //Если было движние по вертикали
    if (moveServoVUp || moveServoVDown)
    {
        myservoV.write(curVAngle);
    }
    //Если было движение по горизонтали
    if (moveServoHLeft || moveServoHRight)
    {
        myservoH.write(curHAngle);
    }
    
    if (moveServoZLeft || moveServoZRight)
    {
        myservoZ.write(curZAngle);
    }
    
        if (moveServoRLeft || moveServoRRight)
    {
        myservoR.write(curRAngle);
    }
}


новое видео:


временно снял водомет, и установил пушку, стреляет 6мм шариками
и прикрутил приехавшую из Китая пушку…
правда это была не совсем пушка, а механизм стрельбы 6мм шариками от модельных танком Henlong, чтобы не покупать целый танк за 3000-5000 я купил запасть за 550руб.
почему я не купил гирбокс от страйкбола?
на то 2 причины:
1. сильно мощное, может кого то покалечить…
2. цена в 10 раз выше :)

есть недостаток у этого механизма — низкая скорострельность, на видео особенно низкая т.к питаю от 3х в, хотя можно 6 — 9

images.sevstar.net/viewer.php?file=59094243184497828873.jpg
images.sevstar.net/viewer.php?file=87142517578332600977.jpg
images.sevstar.net/viewer.php?file=68702878424694602806.jpg
images.sevstar.net/viewer.php?file=61506990518273702824.jpg
images.sevstar.net/viewer.php?file=67439761693001393174.jpg

ствол и уплотнительная резинка в комплект механизма не входят!
поэтому чтобы стрелять пришлось купить детский пистолет и позаимствовать у него ствол и резинку.
images.sevstar.net/viewer.php?file=15374563575590298148.jpg

на фото нет новых доработок, добавил лазерный прицел и дымогенератор с подсветкой для пущего эффекта…
  • 0
  • 10 марта 2015, 20:19
  • SLOM

Комментарии (2)

RSS свернуть / развернуть
+
0
Классная платформа, а водомет лучше поставить от ваз 2108-2115 с бачка омывателя ветрового стекла цена примерно 100-150 р. зато производительность гораздо лучше, тогда будет водяная пушка а не брызгалка ;)
avatar

Maxsimus

  • 11 мая 2015, 15:43
+
0
спасибо за свовет, возможно так и сделаю, а пока снял водомет, поставил пушку, а потом и пушку снял и отлаживаю подключение к джойстику

http://www.youtube.com/watch?v=M3YJXgwfJlw



в перспективе установка пушки и водомета, и клешня само собой :)
avatar

SLOM

  • 11 мая 2015, 19:54

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