Multi servo control and stop functionality

Hi,

I’ve been trying for a while to control 8 servomotrs GS9025MG from goteck for a quadripod.
I’m using an arduino and a Micro Serial Servo Controller (8-channel) from pololu.

I found loads of different code to send command to the SSC (confusing between Micro SSC and Maestro) especially to stop the servomotors.

I finally got something nearly working but I cannot achieve full postion range with the servomotors. Also because of some jittering issue with the servos, I’d like to stop sending pulse when servo has reached the target.

Two questions to summarize:

  • Is there any mistake in my code that could explain why the servomotors doesn’t reach extreme position?

  • I tried several power supply from AA batteries to LiPo batteries and even a 0.7A charger but nothing seems to resolve the jittering issue. What should I use for 8 or more servomotors?

Thanks in advance for your help.

Xukyo

Here is the Arduino code

#include <MicroSSC.h>

MicroSSC maestro(10,11,9600);

 int nbServo=8;
void setup()
{
  Serial.begin(9600);
}
 int FU[8]={3000,1000,3000,3000,3000,3000,1800,3000};
 int BD[8]={4500,3000,1500,1500,1500,5000,3800,1000};
 
void loop()
{
  Serial.println("Servo MIN : 1000");
  for(int i=0;i<nbServo;i++){
    maestro.setTarget(i, BD[i]);//6000);
    maestro.stop(i);
  }
  delay(1000);
  
  Serial.println("Servo MAX : 4000");
    for(int i=0;i<nbServo;i++){
    maestro.setTarget(i, FU[i]);//6000);
    maestro.stop(i);
  }
  delay(2000);

}

And here is the library I wrote


//Libraries
#include "Arduino.h"
#include "MicroSSC.h"
#include "SoftwareSerial.h"
// Pin assignement

// Variables

// Parameters
#define DELAY_WRITE 30
//set up MicroSSC configuration
#define deviceId 0x01 //12
#define startByte 0x80 //
// Command list
#define setCmd 0x00 //
#define targetCmd 0x04 //


/******************************************************************\
* PRIVATE FUNCTION: Constructor
*
* PARAMETERS:
* ~ void
*
* DESCRIPTIONS:
* object constructor 
\******************************************************************/
MicroSSC::MicroSSC(int pinRx, int pinTx, unsigned int baudrate)
{
  pinMode(pinRx, INPUT);
  pinMode(pinTx, OUTPUT);
  _pinRx = pinRx;
  _pinTx = pinTx;
  _MicroSSCSerial = new SoftwareSerial(pinRx,pinTx);
  _MicroSSCSerial->begin(baudrate);
}

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

/******************************************************************\
* PRIVATE FUNCTION: stop
*
* PARAMETERS:
* ~ servo ID number
*
* DESCRIPTIONS:
* Send sequence of command so that the MicroSSC send nothing to the
* the servo
\******************************************************************/
void MicroSSC::stop(unsigned char servo)
{
  _MicroSSCSerial->write(startByte); //start byte
  _MicroSSCSerial->write(deviceId); //device id
  _MicroSSCSerial->write((byte)0x00); //command number
  _MicroSSCSerial->write(servo); //servo number
  _MicroSSCSerial->write((byte)0x0F); //
  //_MicroSSCSerial->write((byte)0x00); //
  
  delay(DELAY_WRITE);
  // 7 6 5 4 3 2 1 0
  // bit 7 0 always
  // bit 6 0 off 1 on
  // bit 5 direction default 0
  // bit 0-4 range
  // 0 0 0 1 1 1 1 1
}

Hello.

It sounds like you are using our discontinued Micro Serial Servo Controller; please note that this is different from our Maestro USB Servo Controllers, which are better in almost every way. If you are using the Micro Serial Servo Controller, the appropriate serial commands and protocol can be found in the Micro Serial Servo Controller User’s Guide.

Can you explain in more detail what you mean when you say the servos are not reaching their extreme positions? From a brief Internet search, it looks like those servos have an operation range of around 60 ± 10°; can you quantify what you are getting from yours?

It also looks like those servos are rated to draw quite a bit of current (1A at 6V with no load). Does the jitter stop if you only connect one servo? If so, you might try powering the servos separately from the Serial Servo Controller and splitting them into 2 (or more) power banks, using a separate power supply for each.

I noticed in your code that you are sending the command to stop each servo immediately after sending the target position. Depending on how your servos react to the servo channel being disabled, it might not have enough time to react to the new target position before the signal is disabled.

Brandon

Hi again Brandon,

could you just give me the correct command to disable a servo channel on
the MSSC?
The servo is still controlled when I set target to zero or if I try to
disable the target.

Thanks in advance for your help.

Here is the piece of code that I use

// Parameters
#define DELAY_WRITE 30
//set up MicroSSC configuration
#define deviceId 0x01 //12
#define startByte 0x80 //
// Command list
#define setCmd 0x00 //
#define targetCmd 0x04 //

void MicroSSC::setTarget(unsigned char servo, unsigned int target)
{
  _MicroSSCSerial->write(startByte); //start byte
  _MicroSSCSerial->write(deviceId) ; //device id
  _MicroSSCSerial->write(targetCmd); //command number
  _MicroSSCSerial->write(servo); //servo number
  if(target==0){
    _MicroSSCSerial->write((byte)target); //
    _MicroSSCSerial->write((byte)target); //
  }else{
    _MicroSSCSerial->write((target & 0x1f80) >> 7); //
    _MicroSSCSerial->write(target & 0x7f); //
    //_MicroSSCSerial->write(target & 0x7F); // Send first 4bits
  //_MicroSSCSerial->write((target >> 7) & 0x7F); // Send last 4bits
  }
  delay(DELAY_WRITE);

}


void MicroSSC::stop(unsigned char servo)
{
  _MicroSSCSerial->write(startByte); //start byte
  _MicroSSCSerial->write(deviceId); //device id
  _MicroSSCSerial->write((byte)0x00); //command number
  _MicroSSCSerial->write(servo); //servo number
  _MicroSSCSerial->write((byte)0x0F); //
  //_MicroSSCSerial->write((byte)0x00); //

  delay(DELAY_WRITE);
  // 7 6 5 4 3 2 1 0
  // bit 7 0 always
  // bit 6 0 off 1 on
  // bit 5 direction default 0
  // bit 0-4 range
  // 0 0 0 1 1 1 1 1
}

I do not see any problem with the bytes you are sending in your stop function; command 0x00 with a data byte of 0x0F should turn off the signals on the specified servo channel.

How a servo reacts when the RC signal is removed depends on the particular servo you are using. For example, most analog servos typically stop holding their position when the hobby RC signal is removed. I suspect you are using digital servos that continue holding the last position they received even after the signal has stopped. If that is the case, you would probably need to find some other way to remove power from the servos to make them stop holding their position. The Mini Serial Servo Controller cannot control the power to the servos directly.

Brandon

Hi Brandon,

Thanks a lot for this info. I changed the GS9025MG for a HS5495BH which is a digital servo but it did not work and that might be the reason.

That doesn’t explain why I cannot get full range on the GS9025MG when I try to stop the servo with the mssc. I reach full range when I am not using the “stop” function.

Full range 0-180°

   for(int i=0;i<nbServo;i++){
      maestro.setTarget(i, FU[i]);//6000);
  }

Smal range less than 60°

   for(int i=0;i<nbServo;i++){
      maestro.setTarget(i, FU[i]);//6000);
      maestro.stop(i);
  }

Should I create a “activate” function?

The code using your stop function is telling the servo controller to disable the servo channel immediately after telling it the new target position, so I suspect there just is not enough time for the servo to receive its new target position before the signals are being stopped by your stop command. Also, do you have speed limits set on your servo channels?

You might try running through a second for loop that runs the stop command for each servo channel after a small delay to see if that fixes the problem.

I am not sure what you mean when you say “activate” function; what do you intend it to do?

Brandon

Hello Brandon,

There is already a delay of 30ms between each stop command. As you say, it
might be because I’m using digital servo.

Do you have any new products replacing the 8-channel servo controller? with
8 channel I mean

Thanks a lot for your help.
Best regards,

Xavier

Hello.

The 12-channel Mini Maestro would be the most direct replacement we have for the 8-channel serial servo controller. As I mentioned in a previous post, the Maestro controllers are newer and better in almost every way.

By the way, the HS5495BH servos you mentioned look like they are rated to go 60 degrees in about 0.17 seconds, so they will need much more than 30ms to rotate 180 degrees.

Brandon