Pololu Maestro 6-channel controller with TS-7800

Hello,
I am using an embedded arm ts 7800 to control the maestro servo controller. I have been looking through the pololu user’s guide and am having a little trouble getting the sample code to work. I am running this off of the TTL on the board, I have gone in to the maestro control center and checked that it is in dual usb and crc is not checked. When ever I compile the code I have no problems, but when I run the code the controller gives me a solid red light with a yellow blinking light and my terminal window doesnt give me any output to running it. I am running the servo on channel 2. I have tried one code which will output:
open port: port /dev/ttts7 has been opened correctly.
fd = 3
:::: 4:
:::: 4:
:::: 4:
etc…
repeatedly.
The code below does this.

#include <stdio.h>   /* Standard input/output definitions */
#include <stdlib.h>
#include <time.h>
#include <string.h>  /* String function definitions */
#include <unistd.h>  /* UNIX standard function definitions */
#include <fcntl.h>   /* File control definitions */
#include <errno.h>   /* Error number definitions */
#include <termios.h> /* POSIX terminal control definitions */

void put(int servo, int angle);   // Moves servo (0-5) to angle (500-5500)
void waitMS (int ms); // This allows for a set system instruction pause. Note: 1000ms = 1 sec.
void neutral(); // This sets up all the servos neutral positions before use.

typedef unsigned int DWORD;
int mainfd = 0;   /* File descriptor for the port */

void waitMS (int ms) {
   clock_t endwait;
   endwait = clock() + ms * CLOCKS_PER_SEC/1000;
   while (clock() < endwait);
}
/*
* 'open_port()' - Open the serial port.
* Returns the file descriptor on success or -1 on error.
*/
int open_port (char portName[]) {
   int fd;   /* File descriptor for the port */
   fd = open(portName, O_RDWR | O_NOCTTY | O_NDELAY);

   if (fd == -1) {  /* Could not open the port */
      fprintf(stderr, "\nopen port: Unable to open %s - %s\n\n", portName, strerror(errno));
      exit(EXIT_FAILURE); // EXIT
   }
   else {
      printf("\nopen port: port %s has been opened correctly.\n\n", portName);
      printf("fd = %i\n\n", fd);
   }

   return (fd);
}

void config_port(int mainfd) {
   struct termios options;


 tcgetattr (mainfd, &options);

   // Set the read and write speed to 19200 BAUD.
   // All speeds can be prefixed with B as a settings.
   cfsetispeed (&options, B9600);
   cfsetospeed (&options, B9600);

   // Now to set the other settings. Here we use the no parity example. Both will assumme 8-bit words.

   // PARENB is enabled parity bit. This disables the parity bit.
   options.c_cflag &= ~PARENB;

   // CSTOPB means 2 stop bits, otherwise (in this case) only one stop bit.
   options.c_cflag &= ~CSTOPB;

   // CSIZE is a mask for all the data size bits, so anding with the negation clears out the current data$
   options.c_cflag &= ~CSIZE;

   // CS8 means 8-bits per work
   options.c_cflag |= CS8;
}

void close_port(int mainfd, char portName[]) {
   /* Close the serial port */
   if (close(mainfd) == -1) {
      fprintf(stderr, "\n\nclose port: Unable to close %s - %s\n\n", portName, strerror(errno));
      exit(EXIT_FAILURE); // EXIT
   }
   else {
      printf("\n\nclose port: The port %s has been closed correctly.\n\n", portName);
      exit(EXIT_SUCCESS);
   }
}


int main(int argc, char* argv[]){
  if (argc != 2) {
      printf("USAGE: %s PORT. i.e. %s /dev/ttts7.\n", argv[0], argv[0]);
      exit(EXIT_FAILURE); // EXIT
   }

   mainfd = open_port(argv[1]);
   config_port(mainfd);

    waitMS(2000);   // Wait one second
                                            
    unsigned char serialBytes[4];
    int channel = 0x2;
    int target = 6000;

    serialBytes[0] = 0x84; // Command byte: Set Target.
    serialBytes[1] = channel; // First data byte holds channel number.
    serialBytes[2] = target & 0x7F; // Second byte holds the lower 7 bits of target.
    serialBytes[3] = (target>>7) & 0x7F;   // Third data byte holds the bits 7-13 of target.

  int a;
  while(1){
    a = write(mainfd,serialBytes,4);
    printf(":::: %i: \n",a);
    waitMS(100);
  }

    close_port(mainfd, argv[1]);

}

Another code that I have tried I believe is closer to the sample code that pololu has in the user guide, which as I have said compiles fine, but when I run it, it gives me the solid red light with the blinking yellow, and shows no output in my working window.

// 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 <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 main()
{
  // Open the Maestro's virtual COM port.
  //const char * device = "\\\\.\\USBSER000";  // Windows, "\\\\.\\COM6" also works
  const char * device = "/dev/ttts7";  // Linux
  //const char * device = "/dev/cu.usbmodem00034567"; // Mac OS X
  int fd = open(device, O_RDWR | O_NOCTTY);
  if (fd == -1)
  {
    perror(device);
    return 1;
  }


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

  int target = (position < 6000) ? 7000 : 5000;
  printf("Setting target to %d (%d us).\n", target, target/4);
  maestroSetTarget(fd, 0, target);

  close(fd);
  return 0;
}

I apologize if I am posting this in the wrong section or the format is wrong, this is my first time using these forums.

Thanks in advanced for any help.

Hello. It sounds like you are trying to control the Maestro using its TTL serial interface (RX/TX lines). That means you cannot use the “USB Dual Port” serial mode. The best serial mode for the Maestro in that case is “UART, fixed baud rate”. You should make sure that the baud rate you choose in the Maestro Control Center matches the baud rate you choose in your code.

If you continue to have trouble, please tell me your latest settings/code and what errors you see in the Maestro Control Center when the red LED is on. A description of your connections and some pictures would also help.

–David

David,
I changed that, and I have gotten that all worked out, thanks for the quick reply. For some reason though the servo keeps spinning and does not find the end “target” and close the port. As I have said I am fairly new to this, but I am understanding about 85-90% of the code. I am just not sure why this never finds an end point. It is still outputting the same thing as I have said before but this time while the servo is spinning:

fd = 3
:::: 4:
:::: 4:
:::: 4:
:::: 4:
:::: 4: etc…

I will attach the code as I have it now, not too much has changed. I did check to baud rates and they are matching, but as I have said my only problem now is that the servo is not reaching an end point.

#include <stdio.h>   /* Standard input/output definitions */
#include <stdlib.h>
#include <time.h>
#include <string.h>  /* String function definitions */
#include <unistd.h>  /* UNIX standard function definitions */
#include <fcntl.h>   /* File control definitions */
#include <errno.h>   /* Error number definitions */
#include <termios.h> /* POSIX terminal control definitions */

void put(int servo, int angle);   // Moves servo (0-5) to angle (500-5500)
void waitMS (int ms); // This allows for a set system instruction pause. Note: 1000ms = 1 sec.
void neutral(); // This sets up all the servos neutral positions before use.

typedef unsigned int DWORD;
int mainfd = 0;   /* File descriptor for the port */

void waitMS (int ms) {
   clock_t endwait;
   endwait = clock() + ms * CLOCKS_PER_SEC/1000;
   while (clock() < endwait);
}
/*
* 'open_port()' - Open the serial port.
* Returns the file descriptor on success or -1 on error.
*/
int open_port (char portName[]) {
   int fd;   /* File descriptor for the port */
   fd = open(portName, O_RDWR | O_NOCTTY | O_NDELAY);

   if (fd == -1) {  /* Could not open the port */
      fprintf(stderr, "\nopen port: Unable to open %s - %s\n\n", portName, strerror(errno));
      exit(EXIT_FAILURE); // EXIT
   }
   else {
      printf("\nopen port: port %s has been opened correctly.\n\n", portName);
      printf("fd = %i\n\n", fd);
   }

   return (fd);
}

void config_port(int mainfd) {
   struct termios options;

   // Get the current settings of the serial port.
   tcgetattr (mainfd, &options);

   // Set the read and write speed to 19200 BAUD.
   // All speeds can be prefixed with B as a settings.
   cfsetispeed (&options, B9600);
   cfsetospeed (&options, B9600);

   // Now to set the other settings. Here we use the no parity example. Both will assumme 8-bit words.

   // PARENB is enabled parity bit. This disables the parity bit.
   options.c_cflag &= ~PARENB;

   // CSTOPB means 2 stop bits, otherwise (in this case) only one stop bit.
   options.c_cflag &= ~CSTOPB;

   // CSIZE is a mask for all the data size bits, so anding with the negation clears out the current data$
   options.c_cflag &= ~CSIZE;

   // CS8 means 8-bits per work
   options.c_cflag |= CS8;
}

void close_port(int mainfd, char portName[]) {
   /* Close the serial port */
   if (close(mainfd) == -1) {
      fprintf(stderr, "\n\nclose port: Unable to close %s - %s\n\n", portName, strerror(errno));
      exit(EXIT_FAILURE); // EXIT
   }
   else {
      printf("\n\nclose port: The port %s has been closed correctly.\n\n", portName);
      exit(EXIT_SUCCESS);
   }
}


int main(int argc, char* argv[]){
  if (argc != 2) {
      printf("USAGE: %s PORT. i.e. %s /dev/ttts6.\n", argv[0], argv[0]);
      exit(EXIT_FAILURE); // EXIT
   }

   mainfd = open_port(argv[1]);
   config_port(mainfd);

    waitMS(2000);   // Wait one second

 unsigned char serialBytes[4];
    //Sets which motorcontroller port you are talking to ie. 0x2=channel 2
    int channel = 0x2;
    //Changes speed of servo, not sure how just yet
    int target = 600;

    serialBytes[0] = 0x84; // Command byte: Set Target.
    serialBytes[1] = channel; // First data byte holds channel number.
    serialBytes[2] = target & 0x7F; // Second byte holds the lower 7 bits of target.
    serialBytes[3] = (target>>7) & 0x7F;   // Third data byte holds the bits 7-13 of target.

  int a;
  while(1){
    a = write(mainfd,serialBytes,4);
    printf(":::: %i: \n",a);
    waitMS(100);
  }

    close_port(mainfd, argv[1]);

}

Thank you for your help.
And I hope that this does help others as well, I know theres not too much documentation on the ts-7800 for beginners, but I am getting through to it little by little. If anyone else is having similar problems, please ask.

-Josh

Hello, Josh. Your program has this infinite loop in it:

  while(1){
    a = write(mainfd,serialBytes,4);
    printf(":::: %i: \n",a);
    waitMS(100);
  }

Why do you expect that loop to terminate?

I am not sure why the servo would keep spinning. Is it a continuous rotation servo? How does it behave when you control it using the Maestro Control Center?

–David

Ah, ok that makes sense. Yes it is a continuous rotation servo. I will mess with the code a little and see if I can get it to do what I am trying. Being just a 90 degree turn and stopping. Thanks for all of your help david.

-Josh

David,
Thanks again for all of your help. We got it programmed on the TS-7800 with the continuous rotation servo to do what I was trying to do. We have the servo moving forward stopping then moving back and stopping again. I will try to post code later, as I do not have the computer with me right now, but I just wanted to thank you guys for all help.