Algoritmo para misturar entrada analógica de 2 eixos para controlar um acionamento diferencial do motor


9

Estou procurando informações sobre como implementar a mistura adequada de 2 sinais analógicos do joystick (eixo X e Y) para controlar um acionamento de motor diferencial duplo (acionamento "tipo tanque") usando um uC (ATMega328p no meu caso, mas o mesmo deve se aplicar a uC com entradas ADC e saídas PWM):

Eu tenho um stick analógico, que fornece 2 valores analógicos:

(direção) X: 0 a 1023
(acelerador) Y: 0 a 1023

insira a descrição da imagem aqui

A posição de repouso é (direção e ponto morto do acelerador) 512.512 O
acelerador para frente / direção esquerda é 0,0 O
total para frente e para a direita é 1023,0
etc.

Os motores são controlados por 2 drivers de ponte H, 2 pinos PWM para cada (Avanço, retrocesso), assim:
Motor Esquerdo: -255 a 255
Motor Direito: -255 a 255
(valores positivos permitem pino PWM dianteiro, negativo permitem reversão Pino PWM, 0 desativa ambos)

O objetivo é misturar sinais analógicos do joystick para obter a seguinte resposta:

a) Acelerador para frente, direção neutra = veículo avançando
b) Acelerador para frente, direção esquerda = veículo movendo-se para frente e virando à esquerda
c) Acelerador para frente, direção esquerda = veículo girando à esquerda EM LOCAL que está com o motor direito à frente, com o motor esquerdo à ré

... e da mesma forma para outras combinações. Obviamente, a saída deve ser "analógica", isto é, deve permitir uma transição gradual, por exemplo, da opção a) para b) até c).

O conceito é:

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


(1) Observe que meu algoritmo básico permite o controle de velocidade da 'mudança no lugar' quando o joystick é pressionado, por exemplo, deixado em% da escala completa. (2) Esse requisito deve ter sido resolvido muitas vezes até agora. A comunidade modelo deve ter respostas para isso. (3) Se o receptor converter os comandos em velocidade da via usando feedback, o veículo se comportará da mesma forma que as condições do solo. MAS, se os comandos forem traduzidos em potência do motor ou tensão de operação, etc., o desempenho do veículo variará de acordo com as condições do solo. - presumivelmente 91) é preferível.
Russell McMahon

Russell, pesquisei bastante no analisador e encontrei muitos controladores de motor prontos para conectar-se diretamente ao receptor RC, mas não havia muita informação sobre o algoritmo interno.
Kamil Zadora

dia bom! renho um primo que está tentando paralisia infantil e a construção de uma cadeira de rodas, sua programação funcionou bem, mas a tensão de saída é muito baixa! Ajude-me! Estou usando um arduino uno.

@Johnny bem-vindo à Electronics.Stackexchange! Consulte as Perguntas frequentes para entender como este site funciona e, se você tiver alguma dúvida, use o botão específico no canto superior direito da página.
Clabacchio

Funcionou ???
Russell McMahon

Respostas:


4

A mistura "adequada" está aberta ao debate :-).

Uma questão é que você precisa tomar decisões sobre a rapidez com que uma faixa se move sob sinais puros de um único pote e o que fazer quando os sinais do outro pote forem incluídos. Por exemplo, se você empurrar o potenciômetro FB (Forward-Backward totalmente para a frente e se ambos os motores funcionarem a toda velocidade), como você lida com a adição de uma pequena quantidade de potenciômetro LR (Esquerda-Direita) sendo adicionada. Para obter rotação, é necessário que uma pista seja mais rápida que a outra, portanto, se você já estiver trabalhando na velocidade máxima para a frente em ambos os motores, deverá diminuir uma ou outra velocidade da pista para poder girar. teria acelerado uma ou outra faixa para alcançar o mesmo resultado.

Então, tudo o que disse, aqui está uma solução simples e inicial da minha cabeça, que parece um bom começo.

Se os vasos são mecanicamente independentes, ambos podem ser 100% simultaneamente.
Se ambos estiverem em um arranjo do tipo joystick, se Yaxis = 100% e Xaxis = 0%, adicionar um pouco de B geralmente reduzirá A. Um joystick pode ser construído onde o que foi dito acima não é verdadeiro, mas isso é incomum.
Suponha que o joystick seja do tipo que aumentar Y% quando X = 100% reduzirá X. Outras suposições podem ser feitas.

FB = vaso frontal-traseiro. Centro zero, + Ve para avançar o pote

LR = Pote esquerdo e direito. Centro zero. + Ve para pote à direita.

K é um fator de escala inicialmente 1.
Se algum resultado exceder 100%, ajuste K para que o resultado seja igual a 100% e use o mesmo valor de K para outro motor também.

  • por exemplo, se resultado do motor esquerdo = 125 e resultado do motor direito = 80 então.
    Como 125 x 0,8 = 100, defina K = 0,8. Então.
    Esquerda = 125 x 0,8 = 100%. Direita = 80 x 0,8 = 64%.

Então:

  • Motor esquerdo = K x (Front_Back + Left_Right)

  • Motor direito = K x (Front_Back - Left_Right)

Verificações de sanidade:

  • LR = 0 (centralizado), FB = aceleração total -> Ambos os motores funcionam totalmente para a frente.

  • LR = totalmente à esquerda, FB = 0 -> O
    motor esquerdo funciona totalmente para trás,
    o motor direito funciona totalmente para a frente.
    O veículo gira no sentido anti-horário.

  • O CE foi de 100%, Lr = 0%. Adicione 10% da LR à direita.
    L = FB + LR = 100% - + 10% R = FB-LR = 100% - - 10%

Se o maior eixo for <100%, dimensione até = 100%.
Escale outro eixo na mesma quantidade.


Obrigado Russell - vou tentar implementar isso na configuração do meu modelo. BTW, meu joystick é capaz de se manter totalmente à frente enquanto faz o movimento panorâmico da esquerda para a direita e, ao contrário, é muito semelhante a este: static.sparkfun.com/images/products/09032-03-L_i_ma.jpg
Kamil Zadora

11
Atualmente, estou encarregado de resolver o mesmo problema no trabalho. Eu tenho um controlador de 2 eixos wii nunchuk, e ele precisa controlar 2 motores exatamente como descrito na pergunta. Estou com problemas para entender a lógica aqui. A que exatamente se refere k1 / K1? Um é minúsculo e o outro é maiúsculo - eles são diferentes? O que é o + Ve?
21816 Tal Tal

11
Legal - obrigado pelo esclarecimento. Eu precisava disso escrito em Python, por isso, se entendi corretamente, deve fazê-lo: pastebin.com/sWDakvLp . Parece que estou perdendo alguma coisa? Parece funcionar no meu ambiente de teste - vou precisar conectá-lo aos motores finais que vou usar para ter certeza.
Tal

11
1) A velocidade do motor é controlada pelo PWM, que aceita apenas valores de 0 a 100, e é por isso que usei 100 como valor máximo. 2) Uso abs para descobrir se é necessário dimensionar (como você disse) e obter o fator de escala. Se eu terminar com um fator de escala de 0,8, por exemplo, e usá-lo em um número negativo, -125 * 0,8 = -100. A direção é mantida. Eu acho que funciona, a menos que esteja faltando alguma coisa. Ainda não tive a chance de experimentá-lo nos motores finais - meu chefe estará construindo uma plataforma de teste com motores acoplados nos quais poderei testar.
25416 Tal

11
Como não tinha certeza se meu código funcionaria, defini o link pastebin anterior para expirar após uma semana. Como parece funcionar, aqui está um link mais permanente com mais alguns comentários, se alguém encontrar o problema novamente: pastebin.com/EKguJ1KP . Eu colocaria isso em uma resposta, mas aparentemente não tenho representante suficiente para postar uma resposta. Todo o código é baseado na resposta de Russel McMahon - o crédito é para ele - graças a Russel.
Tal

5

Aqui está uma solução que não requer cadeias complicadas if / else, não reduz a potência ao avançar totalmente ou girar no lugar, e permite curvas e transições suaves de passar para girar.

A ideia é simples. Suponha que os valores do joystick (x, y) sejam coordenadas cartesianas em um plano quadrado. Agora imagine um plano quadrado menor girado 45º dentro dele.

exemplo de plano

As coordenadas do joystick fornecem um ponto no quadrado maior e o mesmo ponto sobreposto no quadrado menor fornece os valores do motor. Você só precisa converter as coordenadas de um quadrado para o outro, limitando os novos valores (x, y) aos lados do quadrado menor.

Existem muitas maneiras de fazer a conversão. Meu método favorito é:

  1. Converta as coordenadas iniciais (x, y) em coordenadas polares.
  2. Gire-os em 45 graus.
  3. Converta as coordenadas polares de volta em cartesiano.
  4. Faça uma nova escala das novas coordenadas para -1.0 / + 1.0.
  5. Prenda os novos valores a -1,0 / + 1,0.

Isso pressupõe que as coordenadas iniciais (x, y) estejam no intervalo -1,0 / + 1,0. O lado do quadrado interno sempre será igual a l * sqrt(2)/2, portanto, a etapa 4 é apenas multiplicar os valores por sqrt(2).

Aqui está um exemplo de implementação 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

A ideia original desse método - com um método de transformação muito mais complicado - veio deste artigo .


0

Abaixo está um exemplo de implementação de algoritmo de mistura, conforme descrito pela resposta de Russel McMahon:

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);

}

Interessante, esse código parece alimentar 2 pinos analógicos em 2 controladores de motor diferentes. Vou tentar adaptar o código e modificar para minhas configurações. Arduino Uno + 1 placa de driver Sabertooth. 1 joystick para o pino analógico A0 (x) pinoA1 (y) lendo e passando valores para os pinos 10 e 3 do PWM, indo para S1 e S2 de Sabertooth. Acho que estou perto, mas estou ficando confuso sobre como configurar o dipswitch na placa Sabertooth. Por enquanto, estou iniciando a configuração do comutador para receber entrada analógica, o comutador 4 ainda está na posição de acionamento diferencial, mas o colocará novamente no modo independente posteriormente para testes adicionais. Eu acho que este orig

@ user20514 bem-vindo ao electronics.stackexchange! Como você pode notar, este não é um fórum, mas um site de perguntas e respostas; portanto, o espaço das respostas não é para discussão. Seja livre para fazer uma nova pergunta, se você tiver algo a perguntar, ou use comentários para (de fato) comentar sobre perguntas e respostas existentes.
clabacchio

11
@Kamil - O vídeo é mostrado como privado. Ainda está disponível? youtube.com/watch?v=sGpgWDIVsoE
Russell McMahon

@RussellMcMahon reativado :)
Kamil Zadora
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.