плавный старт\торможение коллекторных моторов в тяжелом роботе.

SLOM
Offline
Зарегистрирован: 06.11.2014

Добрый день товарищи. 

пытался найти по поиску, нужную тему но увы ничего ненашел. 

 

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

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

 

сейчас у меня вот такой скетч: 

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

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

 

// Скетч для управления через блютус, Wild Thumper 6WD, на ардуино совместимом контролере TREX controller. реализовано движение и стрельба с водомета. 


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

Servo myservoH; // Горизонтальная серва углы от 0 до 180 (центровка 89)
Servo myservoV; // Вертикальная серва углы от 1 до 45
const int H_SERVO_PIN = 7; // Горизонтальная серва подключена к пину 7
const int V_SERVO_PIN = 8; //Пин вертикального сервопривода 8
const float H_L_ANGLE = 180; // Максимальные угл поворота башни налево
const float H_R_ANGLE = 0; // Максимальные угл поворота башни направо
const float H_DEF_ANGLE = 89; // Дефолтный угол (центровка)
const float V_U_ANGLE = 45; // Максимальные угл поворота башни вверх
const float V_D_ANGLE = 0; // Максимальные угл поворота башни вниз
const float V_DEF_ANGLE = 15; // Дефолтный угол (центровка)
//Размер шага V_STEP и H_STEP побираем экспериментально для достижения нужной скорости поворота серв
const float V_STEP = 0.012; // Шаг - знаение отвечающее за скорость вращения по вертикали.
const float H_STEP = 0.012; // Шаг - знаение отвечающее за скорость вращения по горизонтали
float curVAngle = V_DEF_ANGLE; //Переменная текущего угла верт. сервы
float curHAngle = H_DEF_ANGLE; //Переменная текущего угла гор. сервы
bool moveServoVUp = false; //Флаг движения верт. сервы вверх
bool moveServoVDown = false; //Флаг движения верт. сервы вниз
bool moveServoHLeft = false; //Флаг движения гор. сервы влево
bool moveServoHRight = false; //Флаг движения гор. сервы вправо

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

// Задаем скорости для движения
int Speed = 80; // Текущая максимальная скорость
int TSpeed = 150; // Скорость медленного мотора при повороте
int RLSpeed = 200; // Скорость танкоаого разворота



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

#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);
    myservoH.write(curHAngle);
    myservoV.write(curVAngle);
    
    
    //Светодиод
    pinMode(13, OUTPUT); // Инициализируем пин светодиода
    digitalWrite(13, HIGH); // Светодиод выключен
}

void loop(){
    
    btca2aLite.ReadCommand(); // Считывание принятых команд (кодов кнопок)
    //Вызываем функцию управление сервами
    performServo();
    
    
    
    //--------— Движение Вперед —-------------
    if (btca2aLite.ButtonPressed(KEYCODE_DPAD_UP)) // Едет вперед если нажат курсор ВПЕРЕД
    {
        if (btca2aLite.ButtonPressed(KEYCODE_DPAD_RIGHT)){ // Поворот направо при нажатии курсора ВПЕРЕД и ВЛЕВО
            digitalWrite (Dir_L, HIGH);
            analogWrite (Pwm_L, TSpeed);
            digitalWrite (Dir_R, HIGH);
            analogWrite (Pwm_R, Speed);
        }
        if (btca2aLite.ButtonPressed(KEYCODE_DPAD_LEFT)){ // Поворот налево при нажатии курсора ВПЕРЕД и ВПРАВО
            digitalWrite (Dir_L, HIGH);
            analogWrite (Pwm_L, Speed);
            digitalWrite (Dir_R, HIGH);
            analogWrite (Pwm_R, TSpeed);
        }
        digitalWrite (Dir_L, HIGH);
        analogWrite (Pwm_L, Speed);
        digitalWrite (Dir_R, HIGH);
        analogWrite (Pwm_R, Speed);
    }
    
    //-------— Движение Назад —-------------
    if (btca2aLite.ButtonPressed(KEYCODE_DPAD_DOWN)) // Едет назад если нажат курсор НАЗАД
    {
        if (btca2aLite.ButtonPressed(KEYCODE_DPAD_RIGHT)){ // Поворот налево при нажатии курсора НАЗАД и ВЛЕВО
            digitalWrite (Dir_L, LOW);
            analogWrite (Pwm_L, TSpeed);
            digitalWrite (Dir_R, LOW);
            analogWrite (Pwm_R, Speed);
        }
        if (btca2aLite.ButtonPressed(KEYCODE_DPAD_LEFT)){ // Поворот направо при нажатии курсора НАЗАД и ВПРАВО
            digitalWrite (Dir_L, LOW);
            analogWrite (Pwm_L, Speed);
            digitalWrite (Dir_R, LOW);
            analogWrite (Pwm_R, TSpeed);
        }
        digitalWrite (Dir_L, LOW);
        analogWrite (Pwm_L, Speed);
        digitalWrite (Dir_R, LOW);
        analogWrite (Pwm_R, Speed);
    }
    
    //-------— Движение Влево (Танковый разворот) —-------------
    if (btca2aLite.ButtonPressed(KEYCODE_DPAD_LEFT )) // разворот на месте в лево
    {
        digitalWrite (Dir_L, LOW);
        analogWrite (Pwm_L, RLSpeed);
        digitalWrite (Dir_R, HIGH);
        analogWrite (Pwm_R, RLSpeed);
    }
    
    //-------— Движение Вправо (Танковый разворот) —-------------
    if (btca2aLite.ButtonPressed(KEYCODE_DPAD_RIGHT)) // разворот на месте в право
    {
        digitalWrite (Dir_L, HIGH);
        analogWrite (Pwm_L, RLSpeed);
        digitalWrite (Dir_R, LOW);
        analogWrite (Pwm_R, RLSpeed);
    }
    
  
    
    
    //---------- Переключение скоростей —-------------


   if(btca2aLite.Button(KEYCODE_BUTTON_START)) // ТУРБО режимпри нажатии кнопки START
   {
   Speed = 200;
   }
   if(btca2aLite.Button(KEYCODE_BUTTON_R2)) // 4-я Скорость при нажатии кнопки R2
   {
   Speed = 150;
   }
   if(btca2aLite.Button(KEYCODE_BUTTON_R1)) // 3-я Скорость при нажатии кнопки R1
   {
   Speed = 120;
   }
   if(btca2aLite.Button(KEYCODE_BUTTON_L2)) // 2-я Скорость при нажатии кнопки L2
   {
   Speed = 90;
   }
   if(btca2aLite.Button(KEYCODE_BUTTON_L1)) // 1-я Скорость при нажатии кнопки L2
   {
   Speed = 70;
   }
    
    //-------— включение насоса —-------------
   if (btca2aLite.ButtonPressed(KEYCODE_BUTTON_SELECT))
    { 
     digitalWrite (SHOT, HIGH);
     }
    //-------— выключение насоса происходит автоматически после отпускания кнопки—------------- 
   if(btca2aLite.ButtonReleased(KEYCODE_BUTTON_SELECT))
    {
   digitalWrite (SHOT, LOW);
    } 
    
    
    //--------— Повороты серв при нажатии кнопок —-------------
    
    if(btca2aLite.Button(KEYCODE_BUTTON_X)) // servoV вниз
    {
        moveServoVDown = true;
              
    }
    if(btca2aLite.Button(KEYCODE_BUTTON_A)) // servoH движется к 0
    {
        moveServoHRight = true;
    }
    if(btca2aLite.Button(KEYCODE_BUTTON_B)) // servoV вверх
    {
        moveServoVUp = true;
              
    }
    
    if(btca2aLite.Button(KEYCODE_BUTTON_Y)) // servoH движется к 180
    {
        moveServoHLeft = 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;
}
    
    
    //----------------— Стоп —---------------------
    
    // Если не нажата ни одна кнопка курсора происходит остановка, скорость 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 (moveServoVUp || moveServoVDown)
    {
        myservoV.write(curVAngle);
    }
    //Если было движение по горизонтали
    if (moveServoHLeft || moveServoHRight)
    {
        myservoH.write(curHAngle);
    }
}

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

 

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

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

зарании благодарю! 

bwn
Offline
Зарегистрирован: 25.08.2014

Что то подсказывает, что секунда вам не поможет, особенно при смене направления движения. Сперва система должна остановится, а потом включить реверс, никому ведь в голову не приходит даже при низкой скорости автомобиля резко врубить заднюю. И передачи все таки последовательно переключаем, а не с 5-й трогаемся (здесь нам правда мощность двигла не дает).

Скорее вам надо ваять электронный аналог коробки передач - турбо режим начнется не раньше, чем пройдет все предыдущие состояния (задержку подобрать). Для большей плавности - переменную Speed увеличивать до заданного значения в цикле, аналогично снижать. Задняя передача только после снижения Speed до 0. Как то так. (Можно еще стальной редуктор, тады движки станут расходной частью))) )

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

полный привод? все колеса от одного мотора?

SLOM
Offline
Зарегистрирован: 06.11.2014

bwn

да примерно так и нужно, чтобы не рвать шестерни. 

jeka_tm

полный привод с независимым мотор редуктором на каждом колесе, но питание идет от одного 2х канального регулятора, он же мозги системы:

 

моторы вот такие 

http://www.parkflyer.ru/102764/product/537646/

 

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

вообщем нужна помощь :)

 

 

Snubist
Offline
Зарегистрирован: 18.02.2013

Особо не разбирался, но можно попробовать вот так:

// Скетч для управления через блютус, Wild Thumper 6WD, на ардуино совместимом контролере TREX controller. реализовано движение и стрельба с водомета. 


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

Servo myservoH; // Горизонтальная серва углы от 0 до 180 (центровка 89)
Servo myservoV; // Вертикальная серва углы от 1 до 45
const int H_SERVO_PIN = 7; // Горизонтальная серва подключена к пину 7
const int V_SERVO_PIN = 8; //Пин вертикального сервопривода 8
const float H_L_ANGLE = 180; // Максимальные угл поворота башни налево
const float H_R_ANGLE = 0; // Максимальные угл поворота башни направо
const float H_DEF_ANGLE = 89; // Дефолтный угол (центровка)
const float V_U_ANGLE = 45; // Максимальные угл поворота башни вверх
const float V_D_ANGLE = 0; // Максимальные угл поворота башни вниз
const float V_DEF_ANGLE = 15; // Дефолтный угол (центровка)
//Размер шага V_STEP и H_STEP побираем экспериментально для достижения нужной скорости поворота серв
const float V_STEP = 0.012; // Шаг - знаение отвечающее за скорость вращения по вертикали.
const float H_STEP = 0.012; // Шаг - знаение отвечающее за скорость вращения по горизонтали
float curVAngle = V_DEF_ANGLE; //Переменная текущего угла верт. сервы
float curHAngle = H_DEF_ANGLE; //Переменная текущего угла гор. сервы
bool moveServoVUp = false; //Флаг движения верт. сервы вверх
bool moveServoVDown = false; //Флаг движения верт. сервы вниз
bool moveServoHLeft = false; //Флаг движения гор. сервы влево
bool moveServoHRight = false; //Флаг движения гор. сервы вправо

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

// Задаем скорости для движения
int Speed = 80; // Заданная максимальная скорость
int TSpeed = 150; // Заданная Скорость медленного мотора при повороте
int RLSpeed = 200; // Заданная Скорость танкоаого разворота

int CurrentSpeed = 0; // Текущая скорость
int CurrentTSpeed = 0; // ТекущаяСкорость медленного мотора при повороте
int CurrentRLSpeed = 0; // Текущая Скорость танкоаого разворота
int interval=50; //Время ускорения


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

#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);
    myservoH.write(curHAngle);
    myservoV.write(curVAngle);
    
    
    //Светодиод
    pinMode(13, OUTPUT); // Инициализируем пин светодиода
    digitalWrite(13, HIGH); // Светодиод выключен
}

void loop(){
    
    btca2aLite.ReadCommand(); // Считывание принятых команд (кодов кнопок)
    //Вызываем функцию управление сервами
    performServo();
    unsigned long currentMillis = millis();
  
    //проверяем не прошел ли нужный интервал, если прошел то
    if(currentMillis - previousMillis > interval) 
      {
      // сохраняем время последнего переключения
      previousMillis = currentMillis;
      if (CurrentTSpeed < TSpeed) CurrentTSpeed++;
      if (CurrentTSpeed > TSpeed) CurrentTSpeed--;
      if (CurrentSpeed < Speed) CurrentSpeed++;
      if (CurrentSpeed > Speed) CurrentSpeed--;
      if (CurrentSpeed < RLSpeed) CurrentRLSpeed++;
      if (CurrentSpeed > RLSpeed) CurrentRLSpeed--;
    
      }

    
    
    //--------— Движение Вперед —-------------
    if (btca2aLite.ButtonPressed(KEYCODE_DPAD_UP)) // Едет вперед если нажат курсор ВПЕРЕД
    {
        if (btca2aLite.ButtonPressed(KEYCODE_DPAD_RIGHT)){ // Поворот направо при нажатии курсора ВПЕРЕД и ВЛЕВО
            digitalWrite (Dir_L, HIGH);
            analogWrite (Pwm_L, CurrentTSpeed);
            digitalWrite (Dir_R, HIGH);
            analogWrite (Pwm_R, CurrentSpeed);
        }
        if (btca2aLite.ButtonPressed(KEYCODE_DPAD_LEFT)){ // Поворот налево при нажатии курсора ВПЕРЕД и ВПРАВО
            digitalWrite (Dir_L, HIGH);
            analogWrite (Pwm_L, CurrentSpeed);
            digitalWrite (Dir_R, HIGH);
            analogWrite (Pwm_R, CurrentTSpeed);
        }
        digitalWrite (Dir_L, HIGH);
        analogWrite (Pwm_L, CurrentSpeed);
        digitalWrite (Dir_R, HIGH);
        analogWrite (Pwm_R, CurrentSpeed);
    }
    
    //-------— Движение Назад —-------------
    if (btca2aLite.ButtonPressed(KEYCODE_DPAD_DOWN)) // Едет назад если нажат курсор НАЗАД
    {
        if (btca2aLite.ButtonPressed(KEYCODE_DPAD_RIGHT)){ // Поворот налево при нажатии курсора НАЗАД и ВЛЕВО
            digitalWrite (Dir_L, LOW);
            analogWrite (Pwm_L, CurrentTSpeed);
            digitalWrite (Dir_R, LOW);
            analogWrite (Pwm_R, CurrentSpeed);
        }
        if (btca2aLite.ButtonPressed(KEYCODE_DPAD_LEFT)){ // Поворот направо при нажатии курсора НАЗАД и ВПРАВО
            digitalWrite (Dir_L, LOW);
            analogWrite (Pwm_L, CurrentSpeed);
            digitalWrite (Dir_R, LOW);
            analogWrite (Pwm_R, CurrentTSpeed);
        }
        digitalWrite (Dir_L, LOW);
        analogWrite (Pwm_L, CurrentSpeed);
        digitalWrite (Dir_R, LOW);
        analogWrite (Pwm_R, CurrentSpeed);
    }
    
    //-------— Движение Влево (Танковый разворот) —-------------
    if (btca2aLite.ButtonPressed(KEYCODE_DPAD_LEFT )) // разворот на месте в лево
    {
        digitalWrite (Dir_L, LOW);
        analogWrite (Pwm_L, CurrentRLSpeed);
        digitalWrite (Dir_R, HIGH);
        analogWrite (Pwm_R, CurrentRLSpeed);
    }
    
    //-------— Движение Вправо (Танковый разворот) —-------------
    if (btca2aLite.ButtonPressed(KEYCODE_DPAD_RIGHT)) // разворот на месте в право
    {
        digitalWrite (Dir_L, HIGH);
        analogWrite (Pwm_L, CurrentRLSpeed);
        digitalWrite (Dir_R, LOW);
        analogWrite (Pwm_R, CurrentRLSpeed);
    }
    
  
    
    
    //---------- Переключение скоростей —-------------


   if(btca2aLite.Button(KEYCODE_BUTTON_START)) // ТУРБО режимпри нажатии кнопки START
   {
   Speed = 200;
   }
   if(btca2aLite.Button(KEYCODE_BUTTON_R2)) // 4-я Скорость при нажатии кнопки R2
   {
   Speed = 150;
   }
   if(btca2aLite.Button(KEYCODE_BUTTON_R1)) // 3-я Скорость при нажатии кнопки R1
   {
   Speed = 120;
   }
   if(btca2aLite.Button(KEYCODE_BUTTON_L2)) // 2-я Скорость при нажатии кнопки L2
   {
   Speed = 90;
   }
   if(btca2aLite.Button(KEYCODE_BUTTON_L1)) // 1-я Скорость при нажатии кнопки L2
   {
   Speed = 70;
   }
    
    //-------— включение насоса —-------------
   if (btca2aLite.ButtonPressed(KEYCODE_BUTTON_SELECT))
    { 
     digitalWrite (SHOT, HIGH);
     }
    //-------— выключение насоса происходит автоматически после отпускания кнопки—------------- 
   if(btca2aLite.ButtonReleased(KEYCODE_BUTTON_SELECT))
    {
   digitalWrite (SHOT, LOW);
    } 
    
    
    //--------— Повороты серв при нажатии кнопок —-------------
    
    if(btca2aLite.Button(KEYCODE_BUTTON_X)) // servoV вниз
    {
        moveServoVDown = true;
              
    }
    if(btca2aLite.Button(KEYCODE_BUTTON_A)) // servoH движется к 0
    {
        moveServoHRight = true;
    }
    if(btca2aLite.Button(KEYCODE_BUTTON_B)) // servoV вверх
    {
        moveServoVUp = true;
              
    }
    
    if(btca2aLite.Button(KEYCODE_BUTTON_Y)) // servoH движется к 180
    {
        moveServoHLeft = 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;
}
    
    
    //----------------— Стоп —---------------------
    
    // Если не нажата ни одна кнопка курсора происходит остановка, скорость 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 (moveServoVUp || moveServoVDown)
    {
        myservoV.write(curVAngle);
    }
    //Если было движение по горизонтали
    if (moveServoHLeft || moveServoHRight)
    {
        myservoH.write(curHAngle);
    }
}

Значение interval в строке 37 , нужно подобрать, чем больше интервал тем меньше ускорение.

SLOM
Offline
Зарегистрирован: 06.11.2014

 

спасибо за столь оперативное участие!

но при компиляции ругаеться на строчку    :(

    if(currentMillis - previousMillis > interval) 

 

oiyo
Offline
Зарегистрирован: 27.01.2014

Просто Snubist забыл задекларировать  переменную previousMillis в области описания переменных.

SLOM
Offline
Зарегистрирован: 06.11.2014

добавил 

int previousMillis; в код:

int CurrentSpeed = 0; // Текущая скорость
int CurrentTSpeed = 0; // ТекущаяСкорость медленного мотора при повороте
int CurrentRLSpeed = 0; // Текущая Скорость танкоаого разворота
int interval=1000; //Время ускорения
int previousMillis;

стало компилить. 

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

SLOM
Offline
Зарегистрирован: 06.11.2014

oiyo пишет:

Просто Snubist забыл задекларировать  переменную previousMillis в области описания переменных.

 

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

oiyo
Offline
Зарегистрирован: 27.01.2014

переменную для значений функции millis надо объявлять как long, а не int.

Прочитать про типы переменных можно здесь.

Вот так, например. 









unsigned long previousMillis = 0;

 

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

мне кажется нужно что то вроде этого делать

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

SLOM
Offline
Зарегистрирован: 06.11.2014

сделал

unsigned long currentMillis = 0;
unsigned long previousMillis;

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

может при форсаже плавно начать ехать а может и на 1й скорости лихо  стартануть. 

может это из за определений интервала?  может както сделать чтоб при нажатии на кнопку начальная скорость была 60шим  а потом при удержании кнопки продолжала плавно расти до установленного максимума в течении 1-2х сек. интервал при этом задавать там же где задаеться скорость нажимая кнопки. 

//---------- Переключение скоростей —-------------


   if(btca2aLite.Button(KEYCODE_BUTTON_START)) // ТУРБО режимпри нажатии кнопки START
   {
   Speed = 200;
   }
   if(btca2aLite.Button(KEYCODE_BUTTON_R2)) // 4-я Скорость при нажатии кнопки R2
   {
   Speed = 150;
   }
   if(btca2aLite.Button(KEYCODE_BUTTON_R1)) // 3-я Скорость при нажатии кнопки R1
   {
   Speed = 120;
   }
   if(btca2aLite.Button(KEYCODE_BUTTON_L2)) // 2-я Скорость при нажатии кнопки L2
   {
   Speed = 90;
   }
   if(btca2aLite.Button(KEYCODE_BUTTON_L1)) // 1-я Скорость при нажатии кнопки L2
   {
   Speed = 70;
   }

 

чем выше значение скорости тем дольше устанавливать время этого разгона, например для скорости 70шим время разгона 0,5 сек 

для шим=120 время 2 сек а для турбо режима 4 сек 

и при отпускании кнопки делать паузу в пол сек с плавным снижением шим. 

 

только как мою теорию перенести на практику? :)

SLOM
Offline
Зарегистрирован: 06.11.2014

jeka_tm пишет:

мне кажется нужно что то вроде этого делать

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

 

вот только как это реализовать в коде? ((

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

а если и правда пид регулятор подцепить

Snubist
Offline
Зарегистрирован: 18.02.2013

Извините что накосячил, писал на коленках что называется.

SLOM пишет:

чем выше значение скорости тем дольше устанавливать время этого разгона, например для скорости 70шим время разгона 0,5 сек 

для шим=120 время 2 сек а для турбо режима 4 сек 

и при отпускании кнопки делать паузу в пол сек с плавным снижением шим. 

только как мою теорию перенести на практику? :)

ну можно переменную Интервал задать функцией от скорости, например:

interval=Speed*10;

Это самая простая линейная функция, а можно и экспоненту приплести:)

А начальный шим указать в функциях


//---------- Переключение скоростей —-------------


   if(btca2aLite.Button(KEYCODE_BUTTON_START)) // ТУРБО режимпри нажатии кнопки START
   {
   Speed = 200;
   if (CurrentSpeed<60)CurrentSpeed=60;
   }
   if(btca2aLite.Button(KEYCODE_BUTTON_R2)) // 4-я Скорость при нажатии кнопки R2
   {
   Speed = 150;
   if (CurrentSpeed<60)CurrentSpeed=60;
   }

   if(btca2aLite.Button(KEYCODE_BUTTON_R1)) // 3-я Скорость при нажатии кнопки R1 
   { 
   Speed = 120;
   if (CurrentSpeed<60)CurrentSpeed=60;
   } 
   if(btca2aLite.Button(KEYCODE_BUTTON_L2)) // 2-я Скорость при нажатии кнопки L2 
   { 
   Speed = 90;
   if (CurrentSpeed<60)CurrentSpeed=60;
   } 
   if(btca2aLite.Button(KEYCODE_BUTTON_L1)) // 1-я Скорость при нажатии кнопки L2 
   { 
   Speed = 70; 
   CurrentSpeed=60; 
   }

 

 

 

Snubist
Offline
Зарегистрирован: 18.02.2013

Snubist пишет:

ну можно переменную Интервал задать функцией от скорости, например:

interval=Speed*10;

Это самая простая линейная функция, а можно и экспоненту приплести:)

или так

if (Speed==70)interval=700;
if (Speed==120)interval=2000;
if (Speed==150)interval=3000;
if (Speed==200)interval=4000;

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

interval=abs(Speed-CurrentSpeed)*10;

 

SLOM
Offline
Зарегистрирован: 06.11.2014

Snubist пишет:

ь интервал в зависимости от разности текущей и необходимой скорости, что то типа:

interval=abs(Speed-CurrentSpeed)*10;

 

а как мы узнаем текущую скорость? 

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

и во всеъ этих случаях при рывках мощьности страдают редуктора. поэтому нужно плавненько. 

 

сейчас буду пробовать ваш код, правда пока незнаю что куда засунуть, буду методом тыка прикручивать :)

 

 

прикрутил вот так


// Скетч для управления через блютус, Wild Thumper 6WD, на ардуино совместимом контролере TREX controller. реализовано движение и стрельба с водомета. 


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

Servo myservoH; // Горизонтальная серва углы от 0 до 180 (центровка 89)
Servo myservoV; // Вертикальная серва углы от 1 до 45
const int H_SERVO_PIN = 7; // Горизонтальная серва подключена к пину 7
const int V_SERVO_PIN = 8; //Пин вертикального сервопривода 8
const float H_L_ANGLE = 180; // Максимальные угл поворота башни налево
const float H_R_ANGLE = 0; // Максимальные угл поворота башни направо
const float H_DEF_ANGLE = 89; // Дефолтный угол (центровка)
const float V_U_ANGLE = 45; // Максимальные угл поворота башни вверх
const float V_D_ANGLE = 0; // Максимальные угл поворота башни вниз
const float V_DEF_ANGLE = 15; // Дефолтный угол (центровка)
//Размер шага V_STEP и H_STEP побираем экспериментально для достижения нужной скорости поворота серв
const float V_STEP = 0.012; // Шаг - знаение отвечающее за скорость вращения по вертикали.
const float H_STEP = 0.012; // Шаг - знаение отвечающее за скорость вращения по горизонтали
float curVAngle = V_DEF_ANGLE; //Переменная текущего угла верт. сервы
float curHAngle = H_DEF_ANGLE; //Переменная текущего угла гор. сервы
bool moveServoVUp = false; //Флаг движения верт. сервы вверх
bool moveServoVDown = false; //Флаг движения верт. сервы вниз
bool moveServoHLeft = false; //Флаг движения гор. сервы влево
bool moveServoHRight = false; //Флаг движения гор. сервы вправо

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

// Задаем скорости для движения
int Speed = 80; // Заданная максимальная скорость
int TSpeed = 150; // Заданная Скорость медленного мотора при повороте
int RLSpeed = 200; // Заданная Скорость танкоаого разворота

int CurrentSpeed = 50; // Текущая скорость
int CurrentTSpeed = 50; // ТекущаяСкорость медленного мотора при повороте
int CurrentRLSpeed = 50; // Текущая Скорость танкоаого разворота
int interval=100; //Время ускорения


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

#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);
    myservoH.write(curHAngle);
    myservoV.write(curVAngle);
    
    
    //Светодиод
    pinMode(13, OUTPUT); // Инициализируем пин светодиода
    digitalWrite(13, HIGH); // Светодиод выключен
}

void loop(){
    
    btca2aLite.ReadCommand(); // Считывание принятых команд (кодов кнопок)
    //Вызываем функцию управление сервами
    performServo();
    

    unsigned long previousMillis;
    unsigned long currentMillis = millis();
  
    //проверяем не прошел ли нужный интервал, если прошел то
    
      if (Speed==70)interval=700;
      if (Speed==120)interval=2000;
      if (Speed==150)interval=3000;
      if (Speed==200)interval=4000;
    
    if(currentMillis - previousMillis > interval) 
      {
      // сохраняем время последнего переключения
      previousMillis = currentMillis;
      if (CurrentTSpeed < TSpeed) CurrentTSpeed++;
      if (CurrentTSpeed > TSpeed) CurrentTSpeed--;
      if (CurrentSpeed < Speed) CurrentSpeed++;
      if (CurrentSpeed > Speed) CurrentSpeed--;
      if (CurrentSpeed < RLSpeed) CurrentRLSpeed++;
      if (CurrentSpeed > RLSpeed) CurrentRLSpeed--;
      
   
      }

    
    
    //--------— Движение Вперед —-------------
    if (btca2aLite.ButtonPressed(KEYCODE_DPAD_UP)) // Едет вперед если нажат курсор ВПЕРЕД
    {
        if (btca2aLite.ButtonPressed(KEYCODE_DPAD_RIGHT)){ // Поворот направо при нажатии курсора ВПЕРЕД и ВЛЕВО
            digitalWrite (Dir_L, HIGH);
            analogWrite (Pwm_L, CurrentTSpeed);
            digitalWrite (Dir_R, HIGH);
            analogWrite (Pwm_R, CurrentSpeed);
        }
        if (btca2aLite.ButtonPressed(KEYCODE_DPAD_LEFT)){ // Поворот налево при нажатии курсора ВПЕРЕД и ВПРАВО
            digitalWrite (Dir_L, HIGH);
            analogWrite (Pwm_L, CurrentSpeed);
            digitalWrite (Dir_R, HIGH);
            analogWrite (Pwm_R, CurrentTSpeed);
        }
        digitalWrite (Dir_L, HIGH);
        analogWrite (Pwm_L, CurrentSpeed);
        digitalWrite (Dir_R, HIGH);
        analogWrite (Pwm_R, CurrentSpeed);
    }
    
    //-------— Движение Назад —-------------
    if (btca2aLite.ButtonPressed(KEYCODE_DPAD_DOWN)) // Едет назад если нажат курсор НАЗАД
    {
        if (btca2aLite.ButtonPressed(KEYCODE_DPAD_RIGHT)){ // Поворот налево при нажатии курсора НАЗАД и ВЛЕВО
            digitalWrite (Dir_L, LOW);
            analogWrite (Pwm_L, CurrentTSpeed);
            digitalWrite (Dir_R, LOW);
            analogWrite (Pwm_R, CurrentSpeed);
        }
        if (btca2aLite.ButtonPressed(KEYCODE_DPAD_LEFT)){ // Поворот направо при нажатии курсора НАЗАД и ВПРАВО
            digitalWrite (Dir_L, LOW);
            analogWrite (Pwm_L, CurrentSpeed);
            digitalWrite (Dir_R, LOW);
            analogWrite (Pwm_R, CurrentTSpeed);
        }
        digitalWrite (Dir_L, LOW);
        analogWrite (Pwm_L, CurrentSpeed);
        digitalWrite (Dir_R, LOW);
        analogWrite (Pwm_R, CurrentSpeed);
    }
    
    //-------— Движение Влево (Танковый разворот) —-------------
    if (btca2aLite.ButtonPressed(KEYCODE_DPAD_LEFT )) // разворот на месте в лево
    {
        digitalWrite (Dir_L, LOW);
        analogWrite (Pwm_L, CurrentRLSpeed);
        digitalWrite (Dir_R, HIGH);
        analogWrite (Pwm_R, CurrentRLSpeed);
    }
    
    //-------— Движение Вправо (Танковый разворот) —-------------
    if (btca2aLite.ButtonPressed(KEYCODE_DPAD_RIGHT)) // разворот на месте в право
    {
        digitalWrite (Dir_L, HIGH);
        analogWrite (Pwm_L, CurrentRLSpeed);
        digitalWrite (Dir_R, LOW);
        analogWrite (Pwm_R, CurrentRLSpeed);
    }
    
  
    
    
  //---------- Переключение скоростей —-------------


   if(btca2aLite.Button(KEYCODE_BUTTON_START)) // ТУРБО режимпри нажатии кнопки START
   {
   Speed = 200;
   if (CurrentSpeed<60)CurrentSpeed=60;
   }
   if(btca2aLite.Button(KEYCODE_BUTTON_R2)) // 4-я Скорость при нажатии кнопки R2
   {
   Speed = 150;
   if (CurrentSpeed<60)CurrentSpeed=60;
   }

   if(btca2aLite.Button(KEYCODE_BUTTON_R1)) // 3-я Скорость при нажатии кнопки R1 
   { 
   Speed = 120;
   if (CurrentSpeed<60)CurrentSpeed=60;
   } 
   if(btca2aLite.Button(KEYCODE_BUTTON_L2)) // 2-я Скорость при нажатии кнопки L2 
   { 
   Speed = 90;
   if (CurrentSpeed<60)CurrentSpeed=60;
   } 
   if(btca2aLite.Button(KEYCODE_BUTTON_L1)) // 1-я Скорость при нажатии кнопки L2 
   { 
   Speed = 70; 
   CurrentSpeed=60; 
   }


    
    //-------— включение насоса —-------------
   if (btca2aLite.ButtonPressed(KEYCODE_BUTTON_SELECT))
    { 
     digitalWrite (SHOT, HIGH);
     }
    //-------— выключение насоса происходит автоматически после отпускания кнопки—------------- 
   if(btca2aLite.ButtonReleased(KEYCODE_BUTTON_SELECT))
    {
   digitalWrite (SHOT, LOW);
    } 
    
    
    //--------— Повороты серв при нажатии кнопок —-------------
    
    if(btca2aLite.Button(KEYCODE_BUTTON_X)) // servoV вниз
    {
        moveServoVDown = true;
              
    }
    if(btca2aLite.Button(KEYCODE_BUTTON_A)) // servoH движется к 0
    {
        moveServoHRight = true;
    }
    if(btca2aLite.Button(KEYCODE_BUTTON_B)) // servoV вверх
    {
        moveServoVUp = true;
              
    }
    
    if(btca2aLite.Button(KEYCODE_BUTTON_Y)) // servoH движется к 180
    {
        moveServoHLeft = 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;
}
    
    
    //----------------— Стоп —---------------------
    
    // Если не нажата ни одна кнопка курсора происходит остановка, скорость 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 (moveServoVUp || moveServoVDown)
    {
        myservoV.write(curVAngle);
    }
    //Если было движение по горизонтали
    if (moveServoHLeft || moveServoHRight)
    {
        myservoH.write(curHAngle);
    }
}

ничего не изменилось, работает как в самом начале, никаких замедлений нет (

SLOM
Offline
Зарегистрирован: 06.11.2014

jeka_tm пишет:

а если и правда пид регулятор подцепить

 

это что и как? 

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

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

играясь с коэффициентами можно добиться нужной работы

посмотри картинки поймешь

https://www.google.ru/search?q=%D0%BF%D0%B8%D0%B4+%D1%80%D0%B5%D0%B3%D1%...

SLOM
Offline
Зарегистрирован: 06.11.2014

jeka_tm

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

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

это программная штука. даже библиотека есть

https://www.google.ru/webhp?sourceid=chrome-instant&ion=1&espv=2&ie=UTF-...

а если например на мотор повесить датчик что ардуина значала как крутится мотор, то будет автоматическая регулировка

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

SLOM
Offline
Зарегистрирован: 06.11.2014

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

из доступных 

2 ушли на сервы для головы водяной "пушки" 

1 на насос

еще 2 уйдут на сервы для манипулятора 

есть одна свободная но я хотел ее на фары или чтото еще. 

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

http://zelectro.cc/Z-PCF8574T_I2C_module

 

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

 

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

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

ты не понял. либо либо

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

SLOM
Offline
Зарегистрирован: 06.11.2014

jeka_tm пишет:

ты не понял. либо либо

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

 

вот програмная штука то что надо, только как ее применить, есть какието примеры реаллизации? 

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

а скачать примеры посмотреть не судьба?

SLOM
Offline
Зарегистрирован: 06.11.2014

я ненашел :(

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

Проблема решается только комплексно, к сожалению ....

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

Datak
Offline
Зарегистрирован: 09.10.2014

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

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

А если уж такая нехватка ног - почему бы не поручить часть работы какому-нибудь отдельному ардуино-мини. И программирование упростится, и дополнительные ноги появятся.

oiyo
Offline
Зарегистрирован: 27.01.2014

Похоже, что автору будет проще заказать металлические шестерни :) Или перейти на ремённую передачу или гидромуфту, которые будут демпфировать резкие старт/торможение. Короче, надо АКПП или вариатор ставить :)

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

да лучше конечно. но если нет так нет

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

art100
Offline
Зарегистрирован: 09.03.2014

Ключевое слово ENABLE PIN. Смотрим типовую схему включения.Даю вероятность 90% L298 хотя это не важно может и А3997 А4889. Режим рекуперирования,- то есть торможения. Это снятие импульсов ШИМ с мотора. Лишняя энергия шунтирующими диодами уходит в емкость по питанию.

1 молотим импульсами ШИМ-а машина летит.

2 1 секунда или подбираем время когда драйвер мотора со снятым ENABLE сжирает енергию то есть тормозит.

3 выбираем направление движения.

3 плавно накачиваем ШИМ-ом драйвер мотора.

4 молотим импульсами ШИМ-а машина летит.

Как вы поняли решение Аппаратно-програмное.

Мне хватило подобрать ШИМ-ам только 2 скорости. Высчитывать время и снимать ENABLE для торможения не пришлось на 7 килограммах по квартире.

На моих 7 кг по ровному полу хватило 2 скорости, хотя резервировал больше. У меня по факту на резком развороте максимум но действующий всего 0.5 секунды 255 - рывок. Прямой ход подобрал 80

//#define SPEED1 0
//#define SPEED2 80
//#define SPEED3 100
//#define SPEED3 150
//#define SPEED4 255
//int speedtmp0=  0;// for PWM  for stop reserv
int speedtmp1=  0;// for PWM  for right left
int speedtmp2= 80;// for PWM  for reverse1 forward1
//int speedtmp3=100;// for PWM  for forward1
int speedtmp4=150;// for PWM  for forward1
int speedtmp5=255;// for PWM  for right left
int tlefrig1 =  100;// for motors left right
//int tlefrig2 =  900;// for motors left right
int treverse1= 1000;// for motors reverse
//int tforward1=10000;// for motors forvard
//int turntime = 100;//900; //Time the robot spends turning (miliseconds)

Успехов в торможении :)

 

SLOM
Offline
Зарегистрирован: 06.11.2014

oiyo пишет:

Похоже, что автору будет проще заказать металлические шестерни :) Или перейти на ремённую передачу или гидромуфту, которые будут демпфировать резкие старт/торможение. Короче, надо АКПП или вариатор ставить :)

 

в редукторе все шестерни из каленой стали! 

вы предлагаете перейти на алмазные шестерни? :)

 

ременная передача? это как? у меня 6 мотор редукторов на каждое колесо по одному, куда ремни сувать? 

акп и прочее, это вообще )))

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

для того чтобы этого избежать нужно сделать плавный старт и стоп. 

если шим 200 то при зажатии кнопки давать вначале 60 и плавно в тесении 3х сек доводить до 200, потом при нажатии отпускании кнопки блокировать на 1 сек команды с других кнопок управления моторами и снижать в течении этой 1й сек шим с 200 до 0 или не трогать щим просто делать паузу в управлении на 1 сек, этого обычно хватает чтобы машина сама остановилась, редуктора быстро останавливают машину, лучше тормозов ))

 

SLOM
Offline
Зарегистрирован: 06.11.2014

 

art100

классная телега у вас, даже кота возить может :)

но я пока новичек в этом деле, и не очень понял что именно мне нужно сделать. 

и ваш код несовсем понятен, куда это вставлять? а можно глянуть ваш полный скетч управления? или может подскажите куда в мой это вставить? 

 

 

 

 

 

omusman
Offline
Зарегистрирован: 21.09.2014

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

Обороты двигателя?                                                                                                                                                        Скорость ?                                                                                                                                                                       Вес?

Сообщите...

SLOM
Offline
Зарегистрирован: 06.11.2014

передаточное число 1:75 

обороты вроде 133

скорость незнаю. 3-5 км час

 

 

omusman
Offline
Зарегистрирован: 21.09.2014

Обороты двигателя в реж ХХ?  , Возможно у вас неправильно выбран модуль зуба, на такие колеса  М=3-4, возможно большее межцентровое расстояние  чем необходимо , обязательно делать на чпу или координатном станке...

omusman
Offline
Зарегистрирован: 21.09.2014

обороты колеса 133*75=9975 об мин! понижать нужно до 70 об\мин мах. на колесе, вес агрегата приличный.

omusman
Offline
Зарегистрирован: 21.09.2014

скорость прим. можно посчитать- длина окружности колеса * кол-во обор в мин * 60= м/час... , а вообще плохо что не знаете...

SLOM
Offline
Зарегистрирован: 06.11.2014

Товарищи мне нужно програмное решение, нужна помощь в реализации того что уже выше описано. 

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

я думал в теме по программированию, можно найти помощь программистов, а тут сплошные механики :) 

SLOM
Offline
Зарегистрирован: 06.11.2014

помогите пожалуйста подправить мой скетч, чтобы работало, это все что пока нужно :)

maksim
Offline
Зарегистрирован: 12.02.2012
// задаем пины для левого мотора
#define Dir_L 2
#define Pwm_L 3
// задаем пины для правого мотора
#define Dir_R 10
#define Pwm_R 11


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

int forw_back = 0;
int righ_left = 0;

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



void loop(){

  
  /////
  static unsigned long pre_millis = 0;
  if(millis()-pre_millis > 100)
  {
    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));
  }
  
  ////
}

 

SLOM
Offline
Зарегистрирован: 06.11.2014

Максим, спасибо большое, вроде как работает. 

только пришлось поудалять старое, в том числе переключатель скоростей, ну он теперь впринцыпе и не нужен, можно сказать теперь АКП :) 

 

вопрос а что задают 

int forw_back = 0;
int righ_left = 0;
 
и если вас незатруднит, немогли бы вы, еще немного времени потратить и написать более подробные коментарии что для чего, как оно работает, чтоб на будущее я это уже знал и никого не мучал вопросами...
спасибо! 
sten8606
Offline
Зарегистрирован: 28.08.2015

Добрый день. Прошу помощи, думаю для знающего человека задача не сложная, но я к сожалению в программировании почти "0". Нужно реализовать плавный старт и стоп для детской машинки (большая, ребенок в нее садится). Сейчас там все жестко, рвет с места с пробуксовкой, думаю редуктору это не хорошо. Есть Arduino nano, и модуль IBT-2. Как реализовать плавный пуск, до уровня установсленного переменным резистором при нажатии кнопки, т.е. кнопку нажал - на пин пошел высокий уровень, двигатель разгоняется до установленного значения переменным резистором.

SLOM
Offline
Зарегистрирован: 06.11.2014

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

но я смотрю вы к этому подготовились. 

я сам тоже 0 в програмировании, но вот мне люди помогли таким кодом, может он поможет вам: 

 

#include <PS2X_lib.h>  //for v1.6
#include <Servo.h>
PS2X ps2x;
int PS2 = 0; 
Servo LXservo;
Servo LYservo;


// задаем пины для левого мотора
#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 = 200; // Максимальная скорость
byte MinSpeed = 90;  // Минимальная скорость

int forw_back = 0;
int righ_left = 0;

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

byte xL;
byte yL;
byte xR;
byte yR;

float deltaAnglLR = 0.0002;  // настройка - от времени лупа и сервы
float startAnglLR = 50.0;
float deltaAnglUD = 0.0002;  // настройка - от времени лупа и сервы
float startAnglUD = 90.0;
Servo servoLR;
Servo servoUD;


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

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

States onTimeout();

int mass[4];      //здесь будем хранить значения для скоростей и направлений
                  //mass[0]   лев.напр.
                  //mass[1]   лев.скор.
                  //mass[2]   прав.напр.
                  //mass[3]   прав.скор.
                 
void setup(){
  // LXservo.attach(12);
  // LYservo.attach(13);
  
  servoLR.attach( 12 );
  servoUD.attach( 13 );
  
  PS2 = ps2x.config_gamepad(8,6,7,5, true, true);   //Настройка выводов: (clock, command, attention, data, true, true)

  //Моторы
    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);

}

void loop(){
  
  
 
  
  
    int x;
        int y;
  
   
    
    
// управление башней вправо-влево
    xL = ps2x.Analog( PSS_RX );                             Serial.println( xL, DEC );
    if( xL < 127 )
      {
        x = xL - 127;
        startAnglLR = startAnglLR - x * x * deltaAnglLR;    Serial.println( startAnglLR );
        if( startAnglLR < 0 ) startAnglLR = 0;
      }
    if( xL > 127 )
      {
        x = xL - 128;
        startAnglLR = startAnglLR + x * x * deltaAnglLR;    Serial.println( startAnglLR );   Serial.println( ' ' );
        if( startAnglLR > 110 ) startAnglLR = 110;
         if( startAnglLR < 55 ) startAnglLR = 55;
      }
    if( ps2x.Button( PSB_R3 ) )    // по кнопке джойстика - в исходное
      {
        startAnglLR = 50.0;
      }
    servoLR.write( startAnglLR );
// управление стволом пушки вверх-вниз
    yL = ps2x.Analog( PSS_RY );                             Serial.println( yL, DEC );
    if( xL < 127 )
      {
        y = yL - 127;
        startAnglUD = startAnglUD - y * y * deltaAnglUD;    Serial.println( startAnglUD );
        if( startAnglUD < 0 ) startAnglUD = 0;
      }
    if( yL > 127 )
      {
        y = yL - 128;
        startAnglUD = startAnglUD + y * y * deltaAnglUD;    Serial.println( startAnglUD );   Serial.println( ' ' );
        if( startAnglUD > 170 ) startAnglUD = 170;
          if( startAnglUD < 90 ) startAnglUD = 90;
      }
    if( ps2x.Button( PSB_R3 ) )    // по кнопке джойстика - в исходное
      {
        startAnglUD = 120.0;
      }
    servoUD.write( startAnglUD );
  
  
   if( ps2x.Button( PSB_TRIANGLE ) )    // по кнопке джойстика - рука опустить
      {
        startAnglUD = 70.0;
      }
  
   if( ps2x.Button( PSB_CROSS ) )    // по кнопке джойстика - рука поднять
      {
        startAnglUD = 170.0;
      }
  
  
    if( ps2x.Button( PSB_SQUARE ) )    // по кнопке джойстика - клешня разжать
      {
         startAnglLR = 55;
      }
  
   if( ps2x.Button( PSB_CIRCLE ) )    // по кнопке джойстика - клешня сжать
      {
         startAnglLR = 110.0;
      }
  
  
  //этот код для меня темный лес, мне его дали для плавного старта и торможения моторов. если ехать вперед и резко нажать кнопку назад, машина продолжит ехать вперед, плавно остановиться и только потом поедет назад, это спасает редуктора от разрушения. 
 //если ктото знает что тут к чему, прокоментируйте пожалуйста, чтоб я тоже понимал :)
  static unsigned long pre_millis = 0;
  if(millis()-pre_millis > 50)
  {
    pre_millis = millis();
    
     if(ps2x.Button(PSB_PAD_UP))
    {
      forw_back += step_fb;
      if(forw_back > 0 && forw_back < MinSpeed) forw_back = MinSpeed;
    }
    else  if(ps2x.Button(PSB_PAD_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(ps2x.Button(PSB_PAD_RIGHT))
    {
      righ_left += step_rl;
      if(righ_left > 0 && righ_left < MinSpeed) righ_left = MinSpeed;
    }
    else if(ps2x.Button(PSB_PAD_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));
  }
  
  
  
  
  
  LXservo.write(map(ps2x.Analog(PSS_LX), 255, 0, 0, 180)); ; 
 delay(50); 
  ps2x.read_gamepad(false, 0);
  
  LYservo.write(map(ps2x.Analog(PSS_LY), 0, 255, 0, 90)); ; 
 delay(50); 
  ps2x.read_gamepad(false, 0);
  
  
   // dir_pwm(ps2x.Analog(PSS_RY),2);   //обрабатываем правый джойстик
  //digitalWrite(R_dir, mass[2]);
  //analogWrite(R_pwm, mass[3]);
}    

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

управление у меня с джойстика сони плейстейшин. 

в вашем случае это тоже возможно сделать. 

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

 

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

Олег М.
Олег М. аватар
Offline
Зарегистрирован: 22.11.2015

Всем привет!

Внимательно просмотрел ветку и возник единственный вопрос: кто-нибудь пытался программно или технически ограничить максимальный ТОК двигателя?
В самом общем виде по простой формуле МОМЕНТ на валу, который и ломает шестерни редуктора, зависит от тока ТАК:

,
где M - момент, I - ток.
То есть, момент М пропорционален потребляемому току I.
Сопротивление обмоток двигунов очень маленькое, внутреннее сопротивление акков тоже.
Пусковой ток (и момент силы на валу) может достигать дурных значений.
Поэтому, ИМХО, нужно ограничить ток паспортным значением.

На мой взгляд, возможны три варианта ограничения тока:
1. Программным способом  используя датчик тока.
2. Отдельным стабилизатором (ограничителем) тока.
3. Катушкой индуктивности в цепи питания моторов.

Как то так.

sten8606
Offline
Зарегистрирован: 28.08.2015

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

SLOM
Offline
Зарегистрирован: 06.11.2014

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

 sten8606может вам просто шуруповерт поставить, там и мотор помощьнее и уже резистор на педаль газа есть?  и шуруповерты стоят недорого...

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

sten8606
Offline
Зарегистрирован: 28.08.2015

))) у меня 2 мотора, ардуино и драйвер стоят 11уе. Нет никакого смысла колхозить с шуруповертами.

Олег М.
Олег М. аватар
Offline
Зарегистрирован: 22.11.2015

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

Олег М.
Олег М. аватар
Offline
Зарегистрирован: 22.11.2015

sten8606 пишет:
В моем случае, для детской машинки это очень круто, с этим отлично справляется, плавное увеличение длительности импульсов. Например аккумуляторный шуруповерт, прекрасно регулируется шим, и хорошо работает, большего не надо.

То, что круто для маленькой детской машинки не покатит для большой "взрослой" чисто даже из-за масштабного эффекта.
Возьми, например, увеличь все размеры машины вдвое. Ее масса в самом общем случае вырастет в 2*2*2 = 8 раз, моменты инерции вырастут в 2*2 = 4 раза.
То есть, инерционные параметры растут гораздо быстрее размеров.
Сравни полет комара-шмеля-пцыцы и самолета.
Или сравни бои боксеров мухачей и тяжей.