[Maestro Micro, Linux, C-code] Problem with channel setting

Hello,

at first I would like to say “Hello!!” to every user of this forum, to site admins and to every Pololu’s stuff user:).

I use Micro Maestro 6-Channel USB Servo Controller and Ubuntu Linux. My problem is that I would like to set a channel (e.g. 0 or 5) to a High state. I’m not sure if this is clear, but I would like to set a current on the signal pin of this channel (I would like to achive the same result as when You use the “Pololu Maestro Control center” and ‘enable’ each channel). I have a LED connected to that pin and I would like to light that LED with that pin. I know that this device wasn’t made for LED blinking, but I it’s curious for me. I found some code to connect to Maestro which works very nice, but I have no idea what should I send to ‘turn this pin on’. In example below I use code to control servo, but it doesn’t work for me.

Here is the code:

#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 size setting.
   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/ttyACM1.\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 = 5;
    int target = 6000;
    
    serialBytes[0] = 0x84; // Command byte: Set Target.  
    serialBytes[1] = channel; // First data byte holds channel number.  
    serialBytes[2] = 0xFF; // Second byte holds the lower 7 bits of target.  
    serialBytes[3] = 0xFF;   // 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]);

}

OK, that’s all :). Hope I found some help here :).

Hello,

From a quick glance at your program, it looks like you are sending byte 0xFF as a data byte, which is not valid. All data bytes must have their high bit clear to not be interpreted as command bytes. I recommend starting with the exact example given in the User’s Guide for the set target command.

Please use our Serial Transmitter first to make sure that your Maestro is configured correctly and that you are trying to send the right bytes. Then, if it does not work, tell us what happened! There should be various flashing LEDs and possibly an error message visible in the Configuration Utility that are really useful in debugging any problems. Post your Maestro’s configuration file and a version of your code that is as simple as possible (probably one function, no loops, etc) or it is really hard for us to help you.

-Paul

Hi there.

My bad with those 0xFF values. I read about it in that help. I made a mistake, because I was desperate to change anything, but before I had tried values from User’s Guide which You suggested Paul.

Here’s my configuration file:

<!--Pololu Maestro servo controller settings file, https://www.pololu.com/catalog/product/1350-->
<UscSettings version="1">
  <NeverSuspend>false</NeverSuspend>
  <SerialMode>UART_FIXED_BAUD_RATE</SerialMode>
  <FixedBaudRate>9600</FixedBaudRate>
  <SerialTimeout>0</SerialTimeout>
  <EnableCrc>false</EnableCrc>
  <SerialDeviceNumber>12</SerialDeviceNumber>
  <SerialMiniSscOffset>0</SerialMiniSscOffset>
  <Channels ServosAvailable="6" ServoPeriod="156">
    <!--Period = 19,968 ms-->
    <!--Channel 0-->
    <Channel name="" mode="Servo" min="3328" max="8000" homemode="Off" home="3328" speed="0" acceleration="0" neutral="6000" range="1905" />
    <!--Channel 1-->
    <Channel name="" mode="Servo" min="3968" max="8000" homemode="Off" home="3968" speed="0" acceleration="0" neutral="6000" range="1905" />
    <!--Channel 2-->
    <Channel name="" mode="Servo" min="3968" max="8000" homemode="Off" home="3968" speed="0" acceleration="0" neutral="6000" range="1905" />
    <!--Channel 3-->
    <Channel name="" mode="Servo" min="3968" max="8000" homemode="Off" home="3968" speed="0" acceleration="0" neutral="6000" range="1905" />
    <!--Channel 4-->
    <Channel name="" mode="Servo" min="3968" max="8000" homemode="Off" home="3968" speed="0" acceleration="0" neutral="6000" range="1905" />
    <!--Channel 5-->
    <Channel name="" mode="Servo" min="3968" max="8000" homemode="Off" home="3968" speed="0" acceleration="0" neutral="6000" range="1905" />
  </Channels>
  <Sequences />
  <Script ScriptDone="true" />
</UscSettings>

I’m using Serial Transmitter but I can’t figure it out what should I send to light that LED. I will try to solve this later.

Hello,

If you cannot get the exact bytes given in the manual to do anything (look at the Control Center to see whether they have done anything), you know that your problem is with the Maestro configuration.

The configuration file you posted is for a Maestro configured for UART serial mode. You need to read about serial modes and pick a better option!

-Paul

Hello,

I have finally figured out what was wrong with my program. Paul, You were right about problem with configuration my Maestro. It was configured for UART serial mode, which disabled me from sending any commands to Maestro. I read manual very carefully and I found solution. I have to admit that “RTFM way” in most cases is the most proper solution.

Thanks for Your cues :).

Robert