Site icon AranaCorp

Controlar um controlador serial Maestro com Arduino

Quando se pretende controlar vários servomotores e são necessárias muitas entradas/saídas livres para operar o seu robô (para controlar o Hexana, por exemplo), é interessante usar um controlador serial de servomotor, como o Mini Maestro da Pololu.

Pré-requisitos: Programar com o Arduino, Comunicar com o seu Arduino, Controlar um servomotor com o Arduino

Material

Introdução ao controlador serial Maestro

Quando utilizamos vários servomotores, especialmente quando o número de servomotores excede o número de saídas da placa eletrônica, é necessário usar um controlador de servomotor externo ao microcontrolador principal. Há vários tipos diferentes, e alguns permitem pilotar até 32 servomotores ao mesmo tempo.

Vamos apresentar aqui a placa Maestro da Pololu. Ela existe em diferentes formatos, com 6, 12, 18 ou 24 saídas para servomotor.

Com esta solução, a placa principal (a placa master Arduino ou Raspberry Pi) dá ordens ao controlador (placa slave) através de uma porta serial, que transmite as ordens e fornece energia aos servomotores.

Isso permite :

As informações completas sobre o condutor serial Mini Maestro podem ser encontradas no site da Pololu.

Configuração e teste prévio do controlador serial Maestro

Para configurar o controlador serial Maestro, basta fazer o download do software e dos drivers para Windows (ou para Linux). Os procedimentos de instalação para Windows e para Linux estão disponíveis em inglês nos respectivos links.

Uma vez instalado o software Maestro Control Center e os drivers, conecte o controlador Maestro ao PC com o cabo USB.

Quando o controlador é ligado, o seu número de identificação aparece no canto superior esquerdo. As configurações podem ser acessadas pela aba “Serial Settings” (configurações seriais).

Utilize o software para testar o controlador serial Maestro e os servomotores, na aba “Status”. Não se esqueça de ligar uma fonte de alimentação ao bloco terminal do Mini Maestro, pois do contrário o servomotor não se moverá.

Os servomotores podem ter diferentes configurações de funcionamento. As configurações das saídas do controlador serial podem ser alteradas na aba “Channel Settings” (Configurações de Canal). Teste as configurações que se adaptam ao seu servomotor.

Esquema de ligação

A placa Arduino aceita uma tensão de alimentação entre 7 e 12V e pode ser alimentada pela entrada USB do computador. A lógica do controlador serial é alimentada pela saída de 5V do Arduino, e os servomotores são alimentados por uma bateria. Pode ser necessário acrescentar um regulador de tensão, caso a tensão de alimentação seja diferente da tensão nominal dos servomotores (por exemplo: um Lipo 2S fornece 7,4V enquanto a tensão nominal de um servomotor SG90 é de 5V).

Os terminais 2(Rx) e 3(Tx) da placa Arduino são ligados aos terminais TX e RX da placa Maestro, respectivamente.

O esquema de ligação pode ser facilmente transposto para os controladores seriais Mini Maestro 6, 12 e 18 canais.

Código básico para pilotar um controlador serial Maestro

Para pilotar o controlador serial com uma placa Arduino, é preciso enviar uma sequência de comandos através de uma porta serial. O programa a seguir permite enviar um comando de posição para os diferentes canais de um Mini Maestro utilizando o monitor serial da IDE do Arduino.

Antes de tudo, inicializamos a porta serial utilizada para comunicar com a placa Maestro.

#include <Maestro.h>
Maestro maestro(2,3);

Depois, adicionamos uma função para receber os dados enviados pelo monitor serial.

void readSerialPort(){
 while (Serial.available()) {
   delay(10);  
   if (Serial.available() >0) {
     char c = Serial.read();  //gets one byte from serial buffer
     msg += c;
   }
 }
}

Por razões práticas, enviamos apenas um comando através do monitor. Criamos então uma função para separar o ID do servomotor do valor da posição utilizando o caractere separador “x”.

void convertMsgToCmd(){
   if (msg.length() >0) {
     Serial.println(msg);
     sep = msg.indexOf('x');     
     m1 = msg.substring(0, sep); //get servo id
     m2 = msg.substring(sep+1, msg.length()); //get servo pos
     
     servoId=-1;
     servoPos=-1; 
    
     char carray1[6]; //magic needed to convert string to a number
     m1.toCharArray(carray1, sizeof(carray1));
     servoId = atoi(carray1);
     
     char carray2[6];
     m2.toCharArray(carray2, sizeof(carray2));
     servoPos = atoi(carray2);
      
     msg="";
 }
}

Finalmente, enviamos estes dados para a placa Maestro utilizando o protocolo Pololu, que nada mais é que um sequência de bytes contendo a seleção do protocolo, o ID da placa Maestro, a seleção do comando e o valor da posição.

void setTarget(unsigned char servo, unsigned int target){
  /* envoie la séquence de commande au contrôleur série Maestro pour actionner le servomoteur*/
  const int deviceId = 0x0C; //controller ID 12
  const int startByte = 0xAA; // Protocol selection
  const int targetCmd = 0x04; // Command ID
  
  maestro.write(startByte); //start byte
  maestro.write(deviceId); //device id
  maestro.write(targetCmd); //command number
  maestro.write(servo); //servo number
  maestro.write(target & 0x7F); // Send first 4bits
  maestro.write((target >> 7) & 0x7F); // Send last 4bits
  delay(3);
}

Tudo isso junto resulta no seguinte código:

/*----------------------------------------------------------------------------------------
 Ce programme permet de piloter différents servomoteurs à l'aide du moniteur série.
 Tapez YxZZZZ dans le terminal
 Y entre 0 et 5 pour Mini Maestro 6 voies (selon Maestro)
 ZZZZ entre 4000 et 8000 (selon servomoteur)

 Ex: Tapez 0x6000 dans le moniteur série

  Materiel:
  - 1x servomoteur ou plus
  - 1x Mini Maestro
  - 1x Arduino
  
 Auteur: Xavier Wiedmer
 http://www.aranacorp.com
 
----------------------------------------------------------------------------------------*/
#include "SoftwareSerial.h"
SoftwareSerial maestro(2,3);

String msg, m1, m2;
int sep, servoId=-1, servoPos=-1;


void setup() {
 Serial.begin(9600);
 pinMode(2, INPUT);
 pinMode(3, OUTPUT);
 maestro.begin(9600);
 Serial.println(F("Waiting for command (YxZZZZ): "));
}

void loop() {

 readSerialPort();
 convertMsgToCmd();
 
    //Apply command to servo
    if (servoId>=0 && servoPos>=0 && servoId<18 && servoPos>=500 && servoPos<=10000) {
     
       setTarget(servoId, servoPos);
       Serial.print(F("Command "));
       Serial.print(servoPos);
       Serial.print( F(" sent "));
       Serial.print(F("to servo "));
       Serial.println(servoId);
   
   servoId=-1;
   servoPos=-1;
   Serial.println(F("Waiting for command ... "));
 }
}

void setTarget(unsigned char servo, unsigned int target){
  /* envoie la séquence de commande au contrôleur série Maestro pour actionner le servomoteur*/
  const int deviceId = 0x0C; //controller ID 12
  const int startByte = 0xAA; // Protocol selection
  const int targetCmd = 0x04; // Command ID
  
  maestro.write(startByte); //start byte
  maestro.write(deviceId); //device id
  maestro.write(targetCmd); //command number
  maestro.write(servo); //servo number
  maestro.write(target & 0x7F); // Send first 4bits
  maestro.write((target >> 7) & 0x7F); // Send last 4bits
  delay(3);
}

void readSerialPort(){
  /*Permet de lire une commande provenant du terminal Arduino*/
 while (Serial.available()) {
   delay(10);  
   if (Serial.available() >0) {
     char c = Serial.read();  //gets one byte from serial buffer
     msg += c;
   }
 }
}

void convertMsgToCmd(){
  /*convertit le message provenant du terminal en commande à envoyer au contrôleur série*/
   if (msg.length() >0) {
     Serial.println(msg);
     sep = msg.indexOf('x');
     // expect a string like 0x0021 containing the two servo positions      
     m1 = msg.substring(0, sep); //get servo id
     m2 = msg.substring(sep+1, msg.length()); //get servo pos
     
     servoId=-1;
     servoPos=-1; 
    
     char carray1[6]; //magic needed to convert string to a number
     m1.toCharArray(carray1, sizeof(carray1));
     servoId = atoi(carray1);
     
     char carray2[6];
     m2.toCharArray(carray2, sizeof(carray2));
     servoPos = atoi(carray2);
      
     msg="";
 }
}

Biblioteca para pilotar um controlador serial Maestro

Se for utilizar controladores seriais Maestro em diferentes projetos, é prático codificar as regras de comunicação numa biblioteca. Desta forma, pode reutilizar a biblioteca sem copiar e colar e tornar o seu código mais leve. Pode escrever a sua própria biblioteca ou usar a biblioteca criada por Ryan Mulligan no Github.

Para criar uma biblioteca, criamos dois arquivos .cpp e .h que copiamos para a pasta Documents\Arduino\libraries\Maestro.

O arquivo Maestro.h

/*****************************************************************\
* Library header : Maestro.h
* Author : X.Wiedmer
* Version : v00
* Date : 05/03/2015
* Revision : 
*   v01 - 05/03/2015
* Description :
* Library to setup Maestro board
* www.aranacorp.com
\*****************************************************************/

#ifndef Maestro_h
#define Maestro_h
// Libraries
#include "Arduino.h"
#include "SoftwareSerial.h" 

/******************************************************************\
* CLASS DESCRIPTION
\******************************************************************/
class Maestro
{
  public:
    Maestro(int pinRx, int pinTx);
	 //~Maestro();
    void setTarget(unsigned char servo, unsigned int target);
    void stop(unsigned char servo);
    void begin(unsigned int baudrate);
    
  private:
    int _pinRx;
    int _pinTx;
    int _id;
    SoftwareSerial *_maestroSerial;
};

#endif

O arquivo Maestro.cpp

/*****************************************************************\
* Library : Maestro.cpp
* Author : X.Wiedmer
* Version : v00
* Date : 05/03/2015
* Revision : 
* 	v01 - 05/03/2015
* Description :
* Library to setup Maestro board
* www.aranacorp.com
\*****************************************************************/

//Libraries
#include "Arduino.h"
#include "Maestro.h"
#include "SoftwareSerial.h"

// Parameters
#define DELAY_WRITE 3
//set up maestro configuration
#define deviceId 0x0C //12
#define startByte 0xAA //
// Command list
#define targetCmd 0x04 //


/******************************************************************\
* PRIVATE FUNCTION: Constructor
*
* PARAMETERS:
* ~ void
*
* DESCRIPTIONS:
* object constructor 
\******************************************************************/
Maestro::Maestro(int pinRx, int pinTx)
{
  pinMode(pinRx, INPUT);
  pinMode(pinTx, OUTPUT);
  _pinRx = pinRx;
  _pinTx = pinTx;
  _maestroSerial = new SoftwareSerial(pinRx,pinTx);
}

/******************************************************************\
* PRIVATE FUNCTION: begin
*
* PARAMETERS:
* ~ baudrate (serial port speed)
*
* DESCRIPTIONS:
* Initialize serial port 
\******************************************************************/
void Maestro::begin(unsigned int baudrate)
{
  _maestroSerial->begin(baudrate);
}
/******************************************************************\
* PRIVATE FUNCTION: setTarget
*
* PARAMETERS:
* ~ servo ID number, target specified with integer
*
* DESCRIPTIONS:
* Send sequence of command so that the maestro board send the right
* pwm value to set servo to the desired position
\******************************************************************/
void Maestro::setTarget(unsigned char servo, unsigned int target)
{
  _maestroSerial->write(startByte); //start byte
  _maestroSerial->write(deviceId) ; //device id
  _maestroSerial->write(targetCmd); //command number
  _maestroSerial->write(servo); //servo number
  _maestroSerial->write(target & 0x7F); // Send first 4bits
  _maestroSerial->write((target >> 7) & 0x7F); // Send last 4bits
  delay(DELAY_WRITE);
}

/******************************************************************\
* PRIVATE FUNCTION: stop
*
* PARAMETERS:
* ~ servo ID number
*
* DESCRIPTIONS:
* Send sequence of command so that the maestro send nothing to the
* the servo
\******************************************************************/
void Maestro::stop(unsigned char servo)
{
  _maestroSerial->write(startByte); //start byte
  _maestroSerial->write(deviceId) ; //device id
  _maestroSerial->write(targetCmd); //command number
  _maestroSerial->write(servo); //servo number
  _maestroSerial->write((byte)0x00); // Send first 4bits
  _maestroSerial->write((byte)0x00); // Send last 4bits
  delay(DELAY_WRITE);
}

O programa fica assim:

/*----------------------------------------------------------------------------------------
 Ce programme permet de piloter différents servomoteurs à l'aide du moniteur série.
 Tapez YxZZZZ dans le terminal
 Y entre 0 et 5 pour Mini Maestro 6 voies (selon Maestro)
 ZZZZ entre 4000 et 8000 (selon servomoteur)

 Ex: Tapez 0x6000 dans le moniteur série

  Materiel:
  - 1 servomoteur ou plus
  - 1x Mini Maestro
  - 1x Arduino
  
 Auteur: Xavier Wiedmer
 http://www.aranacorp.com
 
----------------------------------------------------------------------------------------*/

#include <Maestro.h>
Maestro maestro(2,3);

String msg, m1, m2;
int sep, servoId=-1, servoPos=-1;

/************** Main Program **************/
void setup() {
 Serial.begin(9600);
 maestro.begin(9600);
 Serial.println("Waiting for command (YxZZZZ): ");
}

void loop() {

 readSerialPort();
 convertMsgToCmd();
 
    //Apply command to servo
    if (servoId>=0 && servoPos>=0 && servoId<18 && servoPos>=500 && servoPos<=10000) {
     
       maestro.setTarget(servoId, servoPos);
       Serial.print(F("Command "));
       Serial.print(servoPos);
       Serial.print( F(" sent "));
       Serial.print(F("to servo "));
       Serial.println(servoId);
   
   servoId=-1;
   servoPos=-1;
   Serial.println(F("Waiting for command ... "));
 }
}

/************** Functions **************/
void readSerialPort(){
 while (Serial.available()) {
   delay(10);  
   if (Serial.available() >0) {
     char c = Serial.read();  //gets one byte from serial buffer
     msg += c;
   }
 }
}

void convertMsgToCmd(){
   if (msg.length() >0) {
     Serial.println(msg);
     sep = msg.indexOf('x');
     
     m1 = msg.substring(0, sep); //get servo id
     m2 = msg.substring(sep+1, msg.length()); //get servo pos
     
     servoId=-1;
     servoPos=-1; //declare as number  
    
     char carray1[6]; //magic needed to convert string to a number
     m1.toCharArray(carray1, sizeof(carray1));
     servoId = atoi(carray1);
     
     char carray2[6];
     m2.toCharArray(carray2, sizeof(carray2));
     servoPos = atoi(carray2);
      
     msg="";
 }
}

Fique à vontade para comentar ou nos enviar uma mensagem se tiver dificuldades com o seu controlador serial.

Aplicações

Referências

Retrouvez nos tutoriels et d’autres exemples dans notre générateur automatique de code
La Programmerie

Exit mobile version