Strange problem with 8 Port Servo Controller

Hello,

i have a 8 Port mini servo controller, working in Pololu mode, connected to a USB to Serial converter. My system is Opensuse, i use C for developing the controller software.
Everything seems pretty fine so far, communication works properly and so on…

My only problem is:
I wrote a demo program which starts moving the servo at a value of 120…and then goes up to 160 (range is about 50 degrees), one step per second.
The servo seems to move fine so far…but if i send the values 139, 140, the servo moves one step backward instead of forward…at 141 and above…everything continues fine until the servo reaches position corresponding to value 160.
here is my code…i use 8 bit command, just read 120-160 for the “pos” variable.

int setpos8bit(struct sc *sc, char servo, unsigned int pos) {
  unsigned char buf[6];
  unsigned int temp;
  unsigned char hi_byte;
  unsigned char lo_byte; 

  temp = pos & 0x1f80;
  hi_byte = temp>>7;
  lo_byte = pos & 0x7f;
  
  buf[0]=0x80;//start byte
  buf[1]=0x01;//device id
  buf[2]=0x03;//command number
  buf[3]=servo;//servo number
  buf[4]=hi_byte;//data1
  buf[5]=lo_byte;//data2

  printf("hi-byte: %X | lo-byte: %X\n",buf[4],buf[5]);
  
  write(sc->fd,buf,6);
  return 1;
}

this is just the command for transmitting data… i use a loop with 1 sec usleep in order to generate the values & send them via the setpos8bit function.
i initialize the serial interface via

int connect(struct sc *sc) {
  struct termios options;

  sc->connected=0; /* reset in case we fail to connect */

  sc->fd = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY);
  if (sc->fd == -1) 
    {
      printf("unable to open /dev/ttyUSB0\n");
      return 0;
    }
  else fcntl(sc->fd, F_SETFL, 0);

  tcgetattr(sc->fd, &options);

  /* go to 9600 baud */
  cfsetispeed(&options, B9600);
  cfsetospeed(&options, B9600);

  options.c_cflag |= (CLOCAL | CREAD); /* enable */

  options.c_cflag &= ~PARENB; /* 8N1 */
  options.c_cflag &= ~CSTOPB;
  options.c_cflag &= ~CSIZE;
  options.c_cflag |= CS8;

  /* set all of the options */
  tcsetattr(sc->fd, TCSANOW, &options);

  sc->connected=1;
  return 1;
}

the strange thing is…if i try the same (increasing servo position step by step) using the absolute command…there is no problem! the servo moves straight from the beginning to the end.
i have tried several servos on different ports…the behaviour is just the same.
is it possible that this is a firmware bug in the servo controller?

thank you very much for help!
chris

Hello.

I have done some tests and have not been able to duplicate your results. Just to make sure we’re both doing the same thing, here are the bytes sequences I send after a power up:

[0x80, 1, 3, 7, 1, 9]
[0x80, 1, 3, 7, 1, 10]
[0x80, 1, 3, 7, 1, 11]
[0x80, 1, 3, 7, 1, 12]
[0x80, 1, 3, 7, 1, 13]

I looked at the pulse output on an oscilloscope and verified that the pulse width increased by a little bit with each command. Can you send just those commands and see if you still have the problem?

- Jan

hello,
thanks for your reply.i have not been able to test your command-bytes but as far as i can see…
my software exactly generates the commands that you posted here when i use 137-141 as int values for the “pos” variable. you can easily check the code with a calculator that can handle binary values…
the problem only occurs when you send 0x01 as first data byte and 00001011 (139 -> pos var, or 11 in your example) or 00001100 (140 -> pos var, or 12 in your example) for the second data byte… have no problems with the 1 data byte command and the absolute command…

the next possibility to test the controller will be next friday, i will post my results then.
take care,
chris

Hello again,
i just wrote a simple function to send the commands you posted a few lines earlier to the controller:
the result is just the same…the servo motor moves forward until low-byte is 0xB …then goes back one step at 0xC and moves forward again
with 0xD…
what is going wrong there? :confused:

here is the source code:

void send_test(struct sc *sc, char servo)
{
  int i;
  unsigned char buf[6];
  
  buf[0]=0x80;//start byte
  buf[1]=0x01;//device id
  buf[2]=0x03;//command number
  buf[3]=servo;//servo number
  buf[4]=0x01;//hi-byte

  for (i=0; i<5; i++)
    {
      buf[5]=(char) (9+i);//test-data
      printf("writing %x to the controller\n",buf[5]);
      write(sc->fd,buf,6);
      usleep(1000000);
    }
}

any ideas?
thank you

Well, I sent the exact bytes I showed, and it worked correctly. At this point, I’d recommend doing something to verify the bytes coming out of your serial port (ideally, look at the serial line with an oscilloscope) or abandoning the 8-bit command since the absolute position command is working and that’s what we recommend for a PC-based application, anyway.

- Jan