Micro Maestro - GET POSITION command problem

Dear All!

I am using the Micro Maestro controller in serial mode in python and c. After invoking the GET POSITION command sometimes the controller responds nothing. What could cause this strange behaviour? I query the device with GET ERROR, but no error code is returned, the leds are flashing yellow. It may happen on any channel, and the problem seems to be solved after sending a SET TARGET command. Why responds “null” the controller?

Thanks your reply in advance.
biga.

Hello.

The Maestro should always respond to the get position command and the get errors command if your command is valid and the Serial Mode has been configured correctly. I suspect you are reading the bytes from the Maestro using some kind of non-blocking function which means you have no guarantee that the bytes will actually be there when the function returns. Could you write a simple example program that demonstrates the problem? It should be the simplest thing that should work but doesn’t.

–David

Hello David!

Thanks for your reply! I am using this c code below to query the position of a channel. Maybe you are right, I call the standard c “read” function, if it is non-blocking that is the problem. I don’t use any special include (only stdio.h and fcntl.h). The function is called in a middle of a 25 fps video stream, and sometimes it returns nothing.
I did not spent so much time in serial c programming, so if you can give me any example how to do it right, it would be appreciated :))
c code:

static int get_pos(int port, int servo)
{
        char command[2];
        unsigned int rb, response[3];
        int i, iores;
        short stop;
        command[0] = 0x90; //get position command
        command[1] = servo; //servo index
        iores = write(port, &command, sizeof(command));
        i = 0;
        stop = 0;
        //waiting for maestro servo controller's reply
        while (stop == 0)
        {
                iores = read(port, &rb, sizeof(rb));
                if(iores > 1)
                {
                        response[i++] = rb;
                        stop = 1;
                }
                rb = 0;
                usleep(2500);
        }
        return response[0] / 4;
}

Thanks, biga.

What do you mean by “returns nothing”? Did you mean it returns 0? In C, if a non-void function ever returns then it will return some value.

The Maestro’s Get Position command is two bytes (0x90 and channel) but you are not doing anything to guarantee that the command gets sent because you are not checking the return value of the write() function.

The Maestro’s Get Position command results in a two-byte response but you are not doing anything to guarantee that your program actually reads both bytes. For example, if read() returns 1 then it means that you have only succeeded in reading one byte from the Maestro, but your function will return anyway.

You did not post a complete program so it is hard to tell what options are enabled on the port. If the O_NONBLOCK option is enabled, then these issues can definitely cause you problems because you could read/write too little data.

Does your code run in Linux or Windows? It looks like Linux, please see this:

The only thing I would add to that example is that you should make sure the ONLCR and OCRNL options are disabled by adding this line of code right before tcsetattr:

options.c_oflag &= ~(ONLCR | OCRNL);

If it actually is Windows, see this example code:

–David

Hi David!

I read the topic you mentioned and now the serial read() is working in blocking mode :), but additionally I had to set another option to get it work in really blocking mode: options.c_cc[VMIN] = 2; which blocks the read function until 2 characters arrives.
Now I am happy with this, but I still can reproduce the original problem, so may not be the blocking was the problem:
if I set a channel to 1 <= x <= 65535 with SET TARGET, the GET POSITION works well, but if I set to 0 or 65536 the Maestro returns 0x00 0x00. I am getting this result until I set a valid value for example 6000.
Is this normal operation? :slight_smile:

Here is a sample code:

#include <stdio.h>
#include <string.h>
#include <time.h>
#include <fcntl.h>
#include <termios.h>

int init(char *portname)
{
        int port;
	struct termios options;
        port = open(portname,O_RDWR|O_NOCTTY);
        if (port == -1)
        {
                printf("Unable to open port %s\n",portname);
                return -1;
        }
        printf("Port opened: %s, handler: %d\n", portname, port);
	tcgetattr(port, &options);
	options.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
	options.c_cc[VMIN] = 2;
	tcsetattr(port, TCSANOW, &options);
	return port;
}

int get_error(int port)
{
        char command;
        char response[2] = "";
        unsigned int retval = 0; 
	int iores = 0;
        command = 0xA1;
        iores = write(port, &command, sizeof(command));
	iores = read(port, response, 2);
        printf("read iores: %d\n", iores);
        if (iores != 2)
                printf("error reading: %d bytes read", iores);
	printf("Error: 0x%02x 0x%02x\n",response[0],response[1]);
	retval = *((int *)(response));
        return retval;
}

int set_pos(int port, unsigned short servo, unsigned short pos)
{
	char command[4];
	int i, iores;
	pos *= 4;
	command[0] = 0x84; //command type
   	command[1] = servo; //servo index
   	command[2] = pos & 0x7F; //pos low bits
   	command[3] = (pos >> 7) & 0x7F; //pos high bits
	iores = write(port, &command, sizeof(command));
	if(iores > 0)
	{
		printf("Position set to %d\n", pos);
		return pos;
	} else 
	{
		printf("I/O Error!\n");
		return 0;
	}
}

int get_pos(int port, int servo)
{
	char command[2];
	char response[2] = "";
	int iores = 0;
	unsigned int  retval = 0;
	command[0] = 0x90; //get position command
        command[1] = servo; //servo index
        iores = write(port, &command, sizeof(command));
        iores = read(port, response, 2);
	printf("read iores: %d\n", iores);
	if (iores != 2)
		printf("error reading: %d bytes read", iores);
        printf("Servo %d  position: 0x%02x 0x%02x\n", servo,response[0],response[1]);
	retval = *((int*)(response));
	return retval;
}

int main(int arg, char** argv)
{
	char *portname = "/dev/ttyACM0";
        int port, i;
	int servo = atoi(argv[1]); 
	port = init(portname);
	printf("Get Position: %d\n",get_pos(port, servo));
	if(argv[2])
		printf("%d\n", set_pos(port, servo, atoi(argv[2])));
	printf("Get Position: %d\n",get_pos(port, servo));
	printf("Error: %d\n", get_error(port));
	close(port);
}

biga.

I am glad you got things working and shared your code with us. It’s good to know about that VMIN option.

The Maestro’s Set Target command takes a 14-bit number, so numbers higher than 16383 (4095.75 microseconds) definitely won’t work.

–David