Алгоритм смешивания 2-х осевого аналогового входа для управления дифференциальным приводом двигателя


9

Я ищу информацию о том, как реализовать правильное микширование двух аналоговых сигналов джойстика (ось X и Y) для управления приводом с двумя дифференциальными двигателями («бакоподобный» привод) с использованием uC (ATMega328p в моем случае, но то же самое относится и к любой uC с входами АЦП и ШИМ):

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

(направление) X: от 0 до 1023
(газ) Y: от 0 до 1023

введите описание изображения здесь

Положение покоя (направление и нейтральное положение
дроссельной заслонки) 512,512 Дроссельная заслонка вперед / направление влево 0,0
Полное движение вперед-полное вправо - 1023,0
и т. Д.

Двигатели управляются 2-мя возбудителями H-моста, по 2 PWM-вывода для каждого (вперед, назад), например, так:
Левый двигатель: от -255 до 255
Правый двигатель: от -255 до 255
(положительные значения активируют вывод PWM вперед, отрицательные активируют реверс Контакт ШИМ, 0 отключает оба)

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

a) Дроссель вперед, нейтральное направление = транспортное средство движется вперед
b) Дроссель вперед, направление налево = транспортное средство движется вперед и поворачивает влево
c) Дроссельная заслонка, направление налево = автомобиль поворачивает влево В МЕСТО, что правый двигатель полностью вперед, левый двигатель полностью задний

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

Концепция заключается в следующем:

http://www.lynxmotion.com/images/html/build123.htm


(1) Обратите внимание, что мой основной алгоритм позволяет контролировать скорость поворота на месте, когда джойстик нажимается, например, влево на% от полной шкалы. (2) Это требование, должно быть, уже много раз повторялось. У модельного сообщества должны быть ответы на это. (3) Если приемник переводит команды в скорость трека, используя обратную связь, транспортное средство будет вести себя примерно так же, как меняются условия грунта. НО, если команды переведены в мощность двигателя или напряжение привода и т. Д., Производительность автомобиля будет зависеть от состояния грунта. - предположительно 91) является предпочтительным.
Рассел МакМахон

Рассел, я много гуглил в ответе и нашел много готовых к работе контроллеров двигателей для прямого подключения к RC-приемнику, но не так много информации об алгоритме внутри.
Камил Задора

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

@ Джонни добро пожаловать в Electronics.Stackexchange! Пожалуйста, посмотрите FAQ, чтобы понять, как работает этот сайт, и если у вас есть вопрос, пожалуйста, используйте конкретную кнопку в правом верхнем углу страницы.
Клабаккио

Это сработало ???
Рассел МакМэхон

Ответы:


4

«Правильное» смешивание открыто для обсуждения :-).

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

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

Если горшки механически независимы, то оба могут быть на 100% одновременно.
Если оба имеют тип джойстика, если Yaxis = 100% и Xaxis = 0%, то добавление некоторого B обычно уменьшит A. Джойстик может быть сконструирован там, где вышеприведенное неверно, но это необычно.
Предположим, что джойстик относится к тому типу, что увеличение Y% при X = 100% приведет к уменьшению X. Можно сделать и другие предположения.

FB = передний-задний банк. Центр ноль, + Ve для поступательного движения банка

LR = левый правый горшок. Центр ноль. + Ve для банка справа.

K изначально является масштабным коэффициентом 1.
Если какой-либо результат превышает 100%, отрегулируйте K так, чтобы результат = 100%, и используйте то же значение K для другого двигателя.

  • например, если результат левого двигателя = 125 и результат правого двигателя = 80, то.
    Как 125 х 0,8 = 100, установить К = 0,8. Затем.
    Слева = 125 х 0,8 = 100%. Справа = 80 х 0,8 = 64%.

Затем:

  • Левый мотор = K x (Front_Back + Left_Right)

  • Правый мотор = K x (Front_Back - Left_Right)

Санитарные проверки:

  • LR = 0 (по центру), FB = полный вперед -> Оба двигателя работают полностью вперед.

  • LR = полный левый, FB = 0 ->
    левый двигатель работает полностью назад,
    правый двигатель работает полностью вперед.
    Автомобиль вращается против часовой стрелки.

  • FB был 100%, Lr = 0%. Добавьте 10% LR справа.
    L = FB + LR = 100% - + 10% R = FB-LR = 100% - - 10%

Если наибольшая ось <100%, масштабировать до = 100%.
Затем масштабируйте другую ось на ту же величину.


Спасибо, Рассел. Я постараюсь реализовать это на моей модели. Кстати, мой джойстик может держать полный вперед при панорамировании слева направо и наоборот, это очень похоже на это: static.sparkfun.com/images/products/09032-03-L_i_ma.jpg
Камил Задора

1
В настоящее время мне поручено решить ту же проблему на работе. У меня есть 2-осевой контроллер Wii Nunchuk, и он должен управлять 2 двигателями точно так, как описано в вопросе. У меня возникли проблемы с пониманием логики здесь. Что именно означает k1 / K1? Один в нижнем регистре, а другой в верхнем - они разные? Что такое + Ve?
Тал

1
Круто - спасибо за разъяснения. Мне нужно, чтобы это было написано на Python, поэтому, если я правильно понимаю, это должно быть сделано: pastebin.com/sWDakvLp . Похоже, я что-то упустил? Кажется, работает в моей тестовой среде - мне нужно подключить его к последним двигателям, которые я буду использовать, чтобы знать наверняка.
Тал

1
1) Скорость двигателя контролируется ШИМ, который принимает значения только от 0 до 100, поэтому я использовал 100 в качестве максимального значения. 2) Я использую abs для определения необходимости масштабирования (как вы сказали) и для получения scale_factor. Если я получу масштабный коэффициент, например, 0,8, и использую его для отрицательного числа, -125 * 0,8 = -100. Направление сохраняется. Я думаю, что это работает, если я что-то упустил. У меня до сих пор не было возможности опробовать его на последних двигателях - мой начальник будет строить испытательную платформу с подключенными двигателями, на которой я смогу провести испытания.
Тал

1
Я не был уверен, сработает ли мой код, поэтому я установил срок действия предыдущей ссылки на вставку через неделю. Поскольку это, кажется, работает, вот более постоянная ссылка с несколькими комментариями, если кто-нибудь снова столкнется с проблемой: pastebin.com/EKguJ1KP . Я бы добавил это в ответ, но, видимо, мне не хватает представителя, чтобы опубликовать ответ. Весь код основан на ответе Рассела МакМэхона - ему заслужили благодарность - спасибо Расселу.
Tal

5

Вот решение, которое не требует сложных цепочек if / else, не уменьшает мощность при движении вперед или вращении на месте и обеспечивает плавные кривые и переходы от движения к вращению.

Идея проста. Предположим, что значения (x, y) джойстика являются декартовыми координатами на квадратной плоскости. Теперь представьте меньшую квадратную плоскость, повернутую на 45º внутри.

пример самолета

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

Есть много способов сделать преобразование. Мой любимый метод:

  1. Преобразовать начальные (x, y) координаты в полярные координаты.
  2. Поверните их на 45 градусов.
  3. Преобразовать полярные координаты обратно в декартову.
  4. Измените новые координаты на -1.0 / + 1.0.
  5. Зафиксируйте новые значения -1.0 / + 1.0.

Предполагается, что начальные (x, y) координаты находятся в диапазоне -1.0 / + 1.0. Сторона внутреннего квадрата всегда будет равна l * sqrt(2)/2, поэтому шаг 4 примерно умножает значения на sqrt(2).

Вот пример реализации Python.

import math

def steering(x, y):
    # convert to polar
    r = math.hypot(x, y)
    t = math.atan2(y, x)

    # rotate by 45 degrees
    t += math.pi / 4

    # back to cartesian
    left = r * math.cos(t)
    right = r * math.sin(t)

    # rescale the new coords
    left = left * math.sqrt(2)
    right = right * math.sqrt(2)

    # clamp to -1/+1
    left = max(-1, min(left, 1))
    right = max(-1, min(right, 1))

    return left, right

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


0

Ниже приведен пример реализации алгоритма микширования, описанного ответом Рассела МакМахона:

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

//Atmega328p based Arduino code (should work withouth modifications with Atmega168/88), tested on RBBB Arduino clone by Modern Device:
const byte joysticYA = A0; //Analog Jostick Y axis
const byte joysticXA = A1; //Analog Jostick X axis

const byte controllerFA = 10; //PWM FORWARD PIN for OSMC Controller A (left motor)
const byte controllerRA = 9;  //PWM REVERSE PIN for OSMC Controller A (left motor)
const byte controllerFB = 6;  //PWM FORWARD PIN for OSMC Controller B (right motor)
const byte controllerRB = 5;  //PWM REVERSE PIN for OSMC Controller B (right motor)
const byte disablePin = 2; //OSMC disable, pull LOW to enable motor controller

int analogTmp = 0; //temporary variable to store 
int throttle, direction = 0; //throttle (Y axis) and direction (X axis) 

int leftMotor,leftMotorScaled = 0; //left Motor helper variables
float leftMotorScale = 0;

int rightMotor,rightMotorScaled = 0; //right Motor helper variables
float rightMotorScale = 0;

float maxMotorScale = 0; //holds the mixed output scaling factor

int deadZone = 10; //jostick dead zone 

void setup()  { 

  //initialization of pins  
  Serial.begin(19200);
  pinMode(controllerFA, OUTPUT);
  pinMode(controllerRA, OUTPUT);
  pinMode(controllerFB, OUTPUT);
  pinMode(controllerRB, OUTPUT);  

  pinMode(disablePin, OUTPUT);
  digitalWrite(disablePin, LOW);
} 

void loop()  { 
  //aquire the analog input for Y  and rescale the 0..1023 range to -255..255 range
  analogTmp = analogRead(joysticYA);
  throttle = (512-analogTmp)/2;

  delayMicroseconds(100);
  //...and  the same for X axis
  analogTmp = analogRead(joysticXA);
  direction = -(512-analogTmp)/2;

  //mix throttle and direction
  leftMotor = throttle+direction;
  rightMotor = throttle-direction;

  //print the initial mix results
  Serial.print("LIN:"); Serial.print( leftMotor, DEC);
  Serial.print(", RIN:"); Serial.print( rightMotor, DEC);

  //calculate the scale of the results in comparision base 8 bit PWM resolution
  leftMotorScale =  leftMotor/255.0;
  leftMotorScale = abs(leftMotorScale);
  rightMotorScale =  rightMotor/255.0;
  rightMotorScale = abs(rightMotorScale);

  Serial.print("| LSCALE:"); Serial.print( leftMotorScale,2);
  Serial.print(", RSCALE:"); Serial.print( rightMotorScale,2);

  //choose the max scale value if it is above 1
  maxMotorScale = max(leftMotorScale,rightMotorScale);
  maxMotorScale = max(1,maxMotorScale);

  //and apply it to the mixed values
  leftMotorScaled = constrain(leftMotor/maxMotorScale,-255,255);
  rightMotorScaled = constrain(rightMotor/maxMotorScale,-255,255);

  Serial.print("| LOUT:"); Serial.print( leftMotorScaled);
  Serial.print(", ROUT:"); Serial.print( rightMotorScaled);

  Serial.print(" |");

  //apply the results to appropriate uC PWM outputs for the LEFT motor:
  if(abs(leftMotorScaled)>deadZone)
  {

    if (leftMotorScaled > 0)
    {
      Serial.print("F");
      Serial.print(abs(leftMotorScaled),DEC);

      analogWrite(controllerRA,0);
      analogWrite(controllerFA,abs(leftMotorScaled));            
    }
    else 
    {
      Serial.print("R");
      Serial.print(abs(leftMotorScaled),DEC);

      analogWrite(controllerFA,0);
      analogWrite(controllerRA,abs(leftMotorScaled));  
    }
  }  
  else 
  {
  Serial.print("IDLE");
  analogWrite(controllerFA,0);
  analogWrite(controllerRA,0);
  } 

  //apply the results to appropriate uC PWM outputs for the RIGHT motor:  
  if(abs(rightMotorScaled)>deadZone)
  {

    if (rightMotorScaled > 0)
    {
      Serial.print("F");
      Serial.print(abs(rightMotorScaled),DEC);

      analogWrite(controllerRB,0);
      analogWrite(controllerFB,abs(rightMotorScaled));            
    }
    else 
    {
      Serial.print("R");
      Serial.print(abs(rightMotorScaled),DEC);

      analogWrite(controllerFB,0);
      analogWrite(controllerRB,abs(rightMotorScaled));  
    }
  }  
  else 
  {
  Serial.print("IDLE");
  analogWrite(controllerFB,0);
  analogWrite(controllerRB,0);
  } 

  Serial.println("");

  //To do: throttle change limiting, to avoid radical changes of direction for large DC motors

  delay(10);

}

Интересно, что этот код выглядит так, как будто он подает 2 аналоговых контакта на 2 разных контроллера мотора. Я постараюсь адаптировать код и изменить его для моих настроек. Arduino Uno + 1 плата саблезубого драйвера. 1 джойстик на аналоговый контакт A0 (x) контакт A1 (y), считывающий и передающий значения на контакт 10 и 3 ШИМ, идущий к S1 и S2 саблезубого пика. Я думаю, что я близко, но я путаюсь в том, как настроить DIP-переключатель на плате Sabertooth. Сейчас я пытаюсь настроить переключатель для получения аналогового входа, переключатель 4 все еще находится в положении для дифференциального привода, но позже переведу его в независимый режим для дальнейшего тестирования. Я думаю, что это ориг

@ user20514 Добро пожаловать в electronics.stackexchange! Как вы могли заметить, это не форум, а сайт вопросов и ответов, поэтому пространство для ответов не предназначено для обсуждения. Пожалуйста, будьте свободны задавать новый вопрос, если у вас есть что спросить, или используйте комментарии, чтобы (действительно) комментировать существующие вопросы и ответы.
Клабаккио

1
@Kamil - видео показывается как частное. Это все еще доступно? youtube.com/watch?v=sGpgWDIVsoE
Рассел МакМэхон

@RussellMcMahon активирован :)
Камил Задора
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.