Pololu Robotics & Electronics
Menu
My account Comments or questions? About Pololu Contact Ordering information Distributors

Pololu Forum

Servo throw

Hello,

I have played with some pololu controllers before, serial ones, I bought a USB one a bit ago (the little meastro 6 channel one). I also got some inexpensive servos to play with a bit (tower-pro MG90s).

I am trying to work with some c example code that I found on the pololu site The servos are supposed to be able the have a 180 dgr ‘throw’/‘sweep’ with a duty cycle between 1 and 2 ms, with 1500us being center.

However, it only seems to do a 90 degree throw/sweep, 45 degr to each side from ‘center’

any ideas why that is??

I don’t know if I am supposed to add code here, but it’s short:

// Uses POSIX functions to send and receive data from a Maestro.
// NOTE: The Maestro's serial mode must be set to "USB Dual Port".
// NOTE: You must change the 'const char * device' line below.

#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include <termios.h>



// Gets the position of a Maestro channel.
// See the "Serial Servo Commands" section of the user's guide.
int maestroGetPosition(int fd, unsigned char channel)
{
unsigned char command[] = {0x90, channel};

if (write(fd, command, sizeof(command)) == -1) {
   perror("error writing");
   return -1;
   }
 
unsigned char response[2]; 
if (read(fd,response,2) != 2) {
   perror("error reading");
   return -1;
   }
 
return response[0] + 256*response[1];
}

// Sets the target of a Maestro channel.
// See the "Serial Servo Commands" section of the user's guide.
// The units of 'target' are quarter-microseconds.
int maestroSetTarget(int fd, unsigned char channel, unsigned short target)
{
unsigned char command[] = {0x84, channel, target & 0x7F, target >> 7 & 0x7F};

if (write(fd, command, sizeof(command)) == -1)
   {
   perror("error writing");
   return -1;
   }
return 0;
}


int maestroGoHome(int fd)
{
unsigned char command[] = {0xA2};

if (write(fd, command, sizeof(command)) == -1)
   {
   perror("error writing");
   return -1;
   }
return 0;
}

int main()
{
// Open the Maestro's virtual COM port.
const char * device = "/dev/ttyACM0";  // Linux

int fd = open(device, O_RDWR | O_NOCTTY);

if (fd == -1) {
   perror(device);
   return 1;
   }

struct termios options;

tcgetattr(fd, &options);
options.c_iflag &= ~(INLCR | IGNCR | ICRNL | IXON | IXOFF);
options.c_oflag &= ~(ONLCR | OCRNL);
options.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
tcsetattr(fd, TCSANOW, &options);


int position, target;


position = maestroGetPosition(fd, 0);
printf("Current position is %d.\n", position);

printf("Going home\n");
maestroGoHome(fd);
sleep(1);

target = 4000;   //  4 * 1000    -90 degr
printf("Setting target to %d (%d us -- -90 degr.).\n", target, target/4);
maestroSetTarget(fd, 0, target);

sleep(1);

target = 6000;  //  4 * center   0 degr
printf("Setting target to %d (%d us -- 0 degr.).\n", target, target/4);
maestroSetTarget(fd, 0, target);

sleep(1);

target = 8000;  //  4 * 2000    90 degr
printf("Setting target to %d (%d us -- 90 degr.).\n", target, target/4);
maestroSetTarget(fd, 0, target);

close(fd);
return 0;</code>
}

Hello, rocr.

The Maestro does not have any way to tell the maximum servo range by its self, so you will need to cautiously explore that range by expanding the pulse widths you send it until you reach those limits. The “How do I use my Maestro servo controller to get the maximum possible range of motion from my servo?” FAQ under the FAQs tab of the Maestro product page talks about doing so.

-Derrill

Hello Derrill,

I knew that part (I had an older serial one for a long time, have a USB one too now). I was wondering how the control center does it. Also, the servo I have is a 180 degr one, and the pulsewidt between 1ms and 2ms (1.5ms center) acording to the specs.

So, since the “serial commands” use 1/4 us as the unit, the target should be between 4000 and 8000 with the center at a target of 6000, correct?

When I do that, the servo only has a throw/sweep of 90 degrees, not 180, and if I go outside the 4000-8000 range, nothing (indeed) happens.

So I was wondering if there is a settingI missed or so.

thanks,

Ron

However, when I do

You are correct, the Maestro does use 1/4 µs units, so your ranges are correct.

Have you changed the Min and Max ranges for your servo channel in the Maestro Control Center as described in the FAQ I linked to in my previous post, or are you just trying to send serial commands outside the 4000 to 8000 range without doing so? If you have not extended the allowable range, the Maestro will still be limiting the pulse widths being sent to the servo; you will have to expand the range in the Maestro Control Center to allow serial commands like that to work properly.

-Derrill

Well, actually that was what I was looking at from a windows pc, I installed it on Ubuntu (19.10) now.

In the “channels settings” tab, the min value is 1000 (992 actually) and the max is 2000 I wonder if in that regular ms are used?

I don’t know if the firmware is a little old, it has 1.02 on it.

thanks,

Ron

Yes, the Channel Settings and Status tab in the Maestro Control Center show the target in units of microseconds, The 1/4 µs units are used when scripting or sending serial commands. I don’t expect the firmware version to be related to your issue.

I suggest just doing some experimentation with the range and see what results you get.

-Derrill