Site icon AranaCorp

Pilotez un contrôleur série Maestro avec Arduino

Lorsque vous voulez piloter plusieurs servomoteurs et que vous avez besoin de beaucoup d’entrées/sorties disponibles pour faire fonctionner votre robot (pour piloter Hexana, par exemple), il est plus pratique d’utiliser un contrôleur série de servomoteur tel que le Mini Maestro de Pololu.

Prérequis: Programmez avec Arduino, Communiquez avec votre Arduino, Pilotez un servo avec Arduino

Matériel

Présentation du contrôleur série Maestro

Lorsqu’on utilise plusieurs servomoteurs, typiquement, lorsque le nombre de servomoteurs dépasse le nombre de sortie de la carte électronique, il est nécessaire d’utiliser un contrôleur de servomoteur externe au microcontrôleur principal. Il en existe plusieurs types et certains vont même vous permettre de piloter jusqu’à 32 servomoteurs en même temps.

Celle que je vais vous présenter est la carte Maestro de chez Pololu. Elle existe sous différents formats 6, 12, 18 ou 24 sorties pour servomoteur.

Avec cette solution, la carte principale (la carte maître, Arduino ou Raspberry Pi) donne les ordres au contrôleur (carte esclave) via un port série qui les transmet et fournit la puissance aux servomoteurs.

Cela permet de :

Retrouvez toutes les infos sur la série de driver Mini Maestro sur le site de Pololu.

Configuration et test préalable du contrôleur série Maestro

Pour configurer le contrôleur série Maestro, il vous suffit de télécharger le logiciel et les pilotes pour Windows (ou pour Linux). Vous pouvez retrouver les procédures d’installation en anglais pour Windows et pour Linux en suivant les liens respectifs.

Une fois le logiciel Maestro Control Center et les pilotes installés, branchez le contrôleur Maestro au PC en utilisant le câble USB.

Lorsque le contrôleur est connecté vous pouvez voir son numéro d’identification en haut à gauche et retrouver ses paramètres de configuration dans l’onglet « Serial Settings ».

Vous pouvez tester le contrôleur série Maestro et vos servomoteurs à l’aide du logiciel sur l’onglet « Status ». N’oubliez pas de brancher une alimentation sur le bornier du Mini Maestro sinon le servomoteur ne bougera pas.

Les servomoteurs peuvent avoir des paramètres de fonctionnement différents. Vous pouvez modifier les paramètres des sorties du contrôleur série dans l’onglet « Channel Settings ». A vous de tester les paramètres qui correspondent à votre servomoteur.

Schéma de connexion

La carte Arduino accepte une tension d’alimentation entre 7 et 12V et peut être alimenter par le port USB de l’ordinateur. La logique du contrôleur série est alimentée par la sortie 5V de l’Arduino et les servomoteurs sont alimenté par une batterie. Il peut être nécessaire de rajouter un régulateur de tension si la tension d’alimentation est différente de la tension nominale des servomoteurs (par exemple : une Lipo 2S délivre 7,4V alors que la tension nominale d’un servomoteur SG90 est de 5V).

Les bornes 2(Rx) et 3(Tx) de la carte Arduino sont connectées aux bornes TX et RX de la carte Maestro respectivement.

Le schéma de câblage est facilement transposable pour les contrôleurs série Mini Maestro 6 12 et 18 voies.

Code de base pour piloter un contrôleur série Maestro

Pour piloter le contrôleur série avec une carte Arduino, il faut envoyer une séquence de commande via un port série. Le programme suivant permet d’envoyer une commande de position aux différentes voies d’un Mini Maestro à l’aide du moniteur série de l’IDE Arduino.

Tout d’abord, nous initialisons le port série permettant de communiquer avec la carte Maestro.

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

Puis, nous ajoutons une fonction permettant de recevoir les données envoyées via le moniteur série.

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

Pour des raisons pratiques, nous n’envoyons qu’une commande via le moniteur. Nous créons donc une fonction pour séparer l’ID du servo de la valeur de position à l’aide du caractère séparateur « 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="";
 }
}

Enfin, nous envoyons ces données à la carte Maestro en utilisant le protocole Pololu qui se résume en une séquence de bytes contenant la sélection du protocole, l’ID de la carte maestro, la sélection de la commande et la valuer de la position.

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

Mis bout à bout, cela nous donne le code suivant:

/*----------------------------------------------------------------------------------------
 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="";
 }
}

Librairie pour piloter un contrôleur série Maestro

Si vous utilisez des contrôleurs série Maestro dans différents projets, il est plus pratique de coder les règles de communication dans une librairie. Vous pouvez ainsi réutiliser la librairie sans faire de copier/coller et alleger votre code. Vous pouvez écrire votre propre librairie ou utiliser celle créée par Ryan Mulligan sur Github.

Pour créer une librairie, nous créons deux fichiers .cpp et .h que nous copions dans un dossier Documents\Arduino\libraries\Maestro.

le fichier 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

Le fichier 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);
}

Le programme ressemble alors à cela:

/*----------------------------------------------------------------------------------------
 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="";
 }
}

N’hésitez pas à nous laisser un commentaire ou à nous envoyer un message si vous rencontrez des difficultés pour piloter votre contrôleur série.

Applications

Références

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

Quitter la version mobile