ROS chefbot – controlo dos motores

O controlo dos motores no chefbot é efectuado pela interação dos seguintes nodes:

twist_to_motors.py, que subscreve o tópico cmd_vel, e publica os tópicos left e right target velocities

pid_velocity.py, com duas instâncias, left e right, que subscrevem os tópicos das respectivas target velocities, e posição dos encoders, e publicam os tópicos com a velocidade (pwm) a aplicar aos motores.

launchpad_node, que subscreve os tópicos com a velocidade a aplicar nos motores, left e right, e publica a posição dos respectivos

O launchpad_node é o responsável pela comunicação com o software que é executado no microcontrolador. No meu caso um Arduino mega.

O Microcontrolador cumpre as seguintes tarefas:

  • Comunicar com computador (launchpad_node).
  • Ler a posição dos encoders associados aos motores
  • Actuar na direção e velocidade dos motores (via ponte h)

O loop do programa a correr no arduino é o seguinte

Read_From_Serial();
Update_Time();
Update_Encoders();
Update_Ultra_Sonic();
Update_Motors();
Update_MPU6050();

As funções relevantes para o controlo dos motores são as seguintes

  • Read_From_Serial()
  • Update_Encoders()
  • Update_Motors()

Existe ainda outro node relacionado com o assunto, o teleop.

Leitura dos encoders no chefbot

Os encoders dos motores esquerdo e direito são do tipo quadrature e cada um tem dois pinos de output.

O microcontrolador tem para cada encoder uma função associada a um pino  com capacidade de interromper o programa e chamar a função que processa o estado dos dois pinos e actualiza uma variável com a posição do encoder.

A posição do encoder é comunicada no loop pela função Update_Encoders().

O launchpad_node, recebe as posições dos  encoders e publica os valores nos respectivos tópicos.

Os tópicos com a posição dos encoders são subscritos pelas respectivas instâncias do node pid_velocity.py, que fecha o circuito ao calcular o valor adequado da potência a enviar aos motores, face a velocidade real calculada com base na posição dos encoders e a velocidade desejada, que recebe pela subscrição dos respectivos tópicos.

Direcção e velocidade dos motores no chefbot

A direção e velocidade dos motores no chefbot são calculadas no computador e após a sua comunicação, aplicadas nos motores pelo microcontrolador através de uma ponte H.

Existem portanto dois dispositivos intervenientes no processo de controlo da direção e velocidade dos motores no chefbot.

No computador tem relevo os nodes twist_to_motors.py e e em em especial as duas instâncias do node pid_velocity.py.

No microcontrolador tem especial relevo as funções  moveLeftMotor() e moveRightMotor(), que funcionam da mesma forma, ao usar o sinal do valor do pwm para definir a direção, e o seu valor absoluto como potência.

Cálculo da direção e velocidade dos motores no chefbot

O cálculo da direção e velocidade dos motores no chefbot é efectuado no computador pelo node twist_to_motors.py e os dois nodes pid_velocity.py.

Numa primeira fase, no computador, o node twist_to_motors.py recebe no tópico adequado uma mensagem com a indicação da velocidade linear e velocidade angular, desejada, calcula  a velocidade de cada roda e publica-as no respectivo tópico.

Numa segunda fase, os dois nodes pid_velocity.py, recebem as mensagens com a velocidade desejada para cada uma das rodas, e a posição dos encoders.

Controlo PID da velocidade no chefbot

Os nodes que efectuam o controlo PID da velocidade no chefbot são duas instâncias do script pid_velocity.py que o valor da potência a aplicar nos motores em função da velocidade desejada e efectiva.

O forma como o node implementa o controlo da velocidade parece implicar um fluxo contínuo de mensagens nos tópicos que definem as velocidades desejadas para cada roda (o output do node twist_to_motors.py).

spin

while not rospy.is_shutdown():
self.spinOnce()
self.r.sleep()

spinOnce

# only do the loop if we've recently recieved a target velocity message
while not rospy.is_shutdown() and self.ticks_since_target < self.timeout_ticks:
self.calcVelocity()
self.doPid()
self.pub_motor.publish(self.motor)
self.r.sleep()
self.ticks_since_target += 1
if self.ticks_since_target == self.timeout_ticks:
self.pub_motor.publish(0)

 

Aplicação da direção e velocidade dos motores no chefbot

A aplicação de uma nova velocidade e direção nos motores acontece após a recepção da mensagem durante a execução da função Read_From_Serial() que indica a velocidade dos motores, os respectivos valores são guardados na seguinte função:

void Set_Speed() {
motor_left_speed = Messenger_Handler.readLong();
motor_right_speed = Messenger_Handler.readLong();

Os valores são usados pela seguinte função:

void Update_Motors() {
moveRightMotor(motor_right_speed);
moveLeftMotor(motor_left_speed);

Por último, os valores são aplicados na ponte h da seguinte forma:

void moveLeftMotor(float leftServoValue) {
if (leftServoValue > 0) {
digitalWrite(A_2,LOW);
digitalWrite(B_2,HIGH);
analogWrite(PWM_2,leftServoValue);
} else if(leftServoValue < 0) {
digitalWrite(A_2,HIGH);
digitalWrite(B_2,LOW);
analogWrite(PWM_2,abs(leftServoValue));
} else if(leftServoValue == 0) {
digitalWrite(A_2,HIGH);
digitalWrite(B_2,HIGH);
}

Se o valor da velocidade for maior que zero, o motor roda para a frente com a velocidade indicada,

Se o valor da velocidade for menor que zero, o motor roda para traz com o valor absoluto da velocidade indicada,

Se o valor da velocidade for igual a zero, o motor para.