How to read the command Get Moving Status

How do you know that your program sent 147 correctly?

I’m not very familiar with the read() and write() commands you are using. What library are they in? Where is the documentation for them? What are the return values of these functions supposed to represent? What values are getting returned by these functions when you call them in the code above?

I suspect that the read() command does not behave as you expect. It probably just reads all the existing bytes in the serial port receive buffer. In other words, it probably doesn’t wait to receive a byte from the Maestro, it just gives you the bytes that have already been received. In that case, you should try either delaying for some time after write() and before read() (a few milliseconds should be enough), OR you should make a loop that calls read() repeatedly until it returns 1 (assuming the return value is the number of bytes read).

-David

Also, how did you create fd? I’m not sure that controlling /dev/ttyACM0 is as simple as just reading and writing data bytes from it. There might be some additional protocol you have to use.

-David

hello David,

I konw that my program send correctly 147, because i sent other commands (only send, example: Set terget=132, set speed=135…) and work perfectly. I mean i can send commands to the servo controller but i cant read it.

the way to open the port is:

int open_port(void){
   int fdd=open("/dev/ttyACM0",O_RDWR | O_NOCTTY | O_NDELAY);
   if (fdd<0) {printf("error opening /dev/ACM0")}
   return(fdd);
}

Im using Ubuntu, and USB Dual Port, ACM0 to Read and Write.

Do you Know if I need to open both ports(ACM0 to write and ACM1 to read)?

and this is the read function specification

int read(int fd, void * ptr, int numbytes)
include: <unistd.h>
fd = file descriptor as returned by open
ptr = address in memory where data is to be stored;
may be a pointer of any type.
numbytes = number of bytes to attempt to read
returns <0 for error, 0 for end-of-file,
or number of bytes successfully read.
(for a non-blocking interactive file, that may be zero).

Thank you for your response

Ok David,

You are Right, with this code works fine:

while(n!=sizeof(value))
{
   n=read(fd,&value,sizeof(value));
}

I only needed a while loop to wait the response.

And finaly I only used the ACM0 port in DUAL USB PORT

Thanks a lot.

Hello Saaravik,

It is good to see that you got it working. However, your loop will take up a large amount of CPU time (maybe 100%?) while it waits for the response, which really should not be necessary. I would recommend either putting a delay of 1ms into the loop or looking into how to turn off the O_NONBLOCK setting on the serial port (with stty or fnctl) if it is enabled.

Also, I would like to point out that it is a bad idea to use sizeof(char) (which happens to equal 1) to determine the number of bytes that you want to read. The Maestro documentation specifies the fact that there is exactly one byte to be read, so making that number “1” look like it is determined by the C language rather than by the Maestro is misleading and could lead to problems in the future. A better way would be to define arrays, using the number “1” explicitly:

   unsigned char getMovingState(int fd){
   unsigned char serialBytes[1];
   unsigned char value[1];
   int n;

   serialBytes[0]=147;
   n=write(fd,serialBytes,sizeof(serialBytes));
   n=read(fd,value,sizeof(value));

   return (value[0]);
}

When written this way, it should be obvious where the “1” comes from and how to extend the code to support multi-byte commands.

-Paul

First, thank you to all for the response.

I continue with the same problem :frowning: I thought that was fixed, but the problem continue. I can’t read from servo cotroller

I post all my code:

int open_port(void){
  int fdd; /* File descriptor for the port */
  fdd = open("/dev/ttyACM0", O_RDWR | O_NONBLOCK);
  if (fdd <0)  {
    /* Could not open the port.     */
     printf("open_port: Unable to open /dev/ACM0");
  }
  else
     fcntl(fdd, F_SETFL, 0);
  return (fdd);
}
int getMovingState(int fd){
	unsigned char serialBytes[1];
	unsigned char value;
	int n,aux;
	
	serialBytes[0]=147;

	n = write(fd,serialBytes,sizeof(serialBytes));
	if (n < 0)	{printf("Error Getting the Moving State\n");return -1;}
	
	n=0;
	
	while(n!=1){n = read(fd,&value,1);usleep(1000);}
	
	printf("value: %c \n",value);
	
	aux=atoi(value);
	
	return(aux);
}

I know that i can write, because i can move the servos, but when i try to read the program is block waiting for the response that never came.

please, help me ¡¡ :smiley:

Hello,
Can you explain why you are setting the flags to 0 with fcntl? I am not too familiar with all of the options.

Also, was your code working when you sent your previous post, or not?

-Paul

Hello Paul,

No, the code didnt work.
How do you read the controller? do you use read function?

Thanks you

i forgotten to say that i set flags to cero to flush the buffer. But i have try with and without sets flags and the result is the same.

Im C code in Ubuntu enviroment with servo controller in DUAL USB PORT.

Do you use the same rutines to write/read the servo controller?

Thanks a lot.

Here is an old tutorial on using the serial port with Linux that is a bit out of date but might be helpful to you. Almost everything I ever knew about using the serial port in linux is in there, and that does not contain any example of doing the reading.

Yes, I would use read() to read bytes from the servo controller. No, I would not use the same functions for read and write - I would use read() to read and write() to write. Is that what you were asking?

Are you sure you are in the right serial mode (USB Dual Port or USB Chained) and writing to the correct port? You can use the Pololu Serial Transmitter to test the configuration under Windows. I just did that, and command 0x93 seems to work for me!
-Paul

Thank you for your reply Paul,

I have cheked my configuration on windows with the pololu transmitter and works fine.
But I still can’t read it in Linux. I dont know where is the mistake :frowning:

Im sure that im using USB DUAL Port and using the ACM0 port, because i can write in it.

Im using this functions: rabbit.eng.miami.edu/info/functions/unixio.html
to open, close,read and write in the servo controller.

And this is the code to configure the port:

int config_port(int fd){
	struct termios options;
    /* Get the current options for the port... */
	tcgetattr(fd, &options);
	/* Set the baud rates to 115200... */
	cfsetispeed(&options, B115200);
	cfsetospeed(&options, B115200);
	
	/* Enable the receiver and set local mode... */
	options.c_cflag |= (CLOCAL | CREAD);
	// No parity (8N1): 
	options.c_cflag &= ~PARENB;
	options.c_cflag &= ~CSTOPB;
	options.c_cflag &= ~CSIZE;
	options.c_cflag |= CS8;
	// no Flow Control
	//options.c_cflag &= ~CNEW_RTSCTS;
	
	/* Set the new options for the port...*/
	tcsetattr(fd, TCSANOW, &options);
	fcntl(fd, F_SETFL, 0);
	return 0;
	
}

This is the code to write (that it works fine)

int setTarget(int fd,int servo,int target){
	unsigned char serialBytes[4];
	int n,output;
	
	target=target*4;
	
	serialBytes[0]=132;
	serialBytes[1]=servo;
	serialBytes[2]=target&0x7F;
	serialBytes[3]=(target>>7)&0x7F;
	
	n = write(fd,serialBytes,sizeof(serialBytes));
	if (n < 0)	
		{
			printf("Error Setting the Target %i for servo %i\n",target,servo);
			output=-1;
		}
	else 
		{
			output=n;
		}
	
	
	return output;
}

and this is the code to read

int getErrors(int fd){
	unsigned char serialBytes;
	unsigned char value[2];
	int n,output;
	
	serialBytes=161;

	n = write(fd,&serialBytes,1);
	if (n < 0)	
		{
			printf("WC n=%i. Error Getting the Errors Messages\n",n);
			output= -1;
		}
	else
		{
			
			fcntl(fd, F_SETFL, O_NONBLOCK);
			n=0;
			while (n!=2){
			usleep(5000);
			fcntl(fd, F_SETFL, 0);
			n=read(fd,value,2);}
			if (n!=2) 
				{
					printf("RR n=%i. Error Getting the Errors Messages\n",n);
					output=-1;
				}
			else
				{
					output=atoi(value);
				}
		}
	
	return(output);
}

and the result is the same: I can write, but I cant read.

Thank you So Much.

I hope you can help me.

Hi Saaravik,
I have not had a chance yet, but I intend to give this code a try on a linux computer over here. I will let you know whether or not I can get it working.

Another thing you could try, by the way, is using the second ttyACM device to see whether you can send data to and from the TTL UART. An easy way to check is to connect TX to RX on the Maestro - then any bytes you send should be echoed back to you.

-Paul

Hello again,

I still cant read the Servo Maestro :’(

When I send the command 0xA1 (161) with Pololu Serial Transmiter in windows I received:

Why I receive twice 00’? I dont understand this.

And another question is: how do you send this command in C code and receive it?
Which type of variables do you use?

For example to write into servo controller, i use a String or vector of Unsigned char and to read i use unsigned char too.
Do you think that is this correct?

Im lost. I dont know why my code doesnt work :frowning:

Ok, I know Why i receive twice the response 00’

Is because, i write wrong the command, 161 is for get Errors and 147 is for get the moving State.
Now I understand this.

But in linux my code still doesnt work.

another question: does the device send any special final character?

Okay, I think I have a linux solution for you. You need to put the terminal into “raw mode” using the tcsetattr() function so that it does not wait for a newline character before actually sending the bytes. Here is a complete program that works for me:

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

int main()
{
  int fd = open("/dev/ttyACM0", O_RDWR | O_NOCTTY);
  char message[] = {161};
  unsigned char buf[2];
  struct termios options;

  if (fd == -1)
  {
    fprintf(stderr, "error opening");
    exit(1);
  }

  tcgetattr(fd, &options);
  options.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
  options.c_oflag &= ~(ONLCR | OCRNL);
  tcsetattr(fd, TCSANOW, &options);

  if(write(fd,message,4) == EOF)
  {
    fprintf(stderr, "error writing");
    exit(1);
  }

  int bytes_read = read(fd,buf,2);
  if(bytes_read != 2)
  {
    fprintf(stderr, "error reading: %d bytes read", bytes_read);
    exit(1);
  }

  printf("Received: 0x%02x 0x%02x\n",buf[0],buf[1]);

  exit(0);
}

As for your question - no, the device does not return a special final character. It does not even append a CRC when it is in CRC mode.

-Paul

Edit: c_oflag line added by David.

Thank you SO MUCH Paul.
You are my hero ¡¡ XD
now all works fine.

The problem was, how you said, with the raw mode.

:D:D:D:D

Great! Glad to hear that it works. Good luck with your project and please let us know how it goes!

-Paul

Hello Again,

I dont know why, but i continue with the same error:

I paste the code of the program that doesnt work. The program is waiting in read function.

#include <fcntl.h>

#include <stdlib.h>

#include <stdio.h>

#include <termios.h>



int main()

{

  int fd = open("/dev/ttyACM0", O_RDWR | O_NOCTTY);

  char message[] = {144,1};

  char command[]={132,1,0,0};

  unsigned char buf[2];

  struct termios options;



  if (fd == -1)

  {

    fprintf(stderr, "error opening");

    exit(1);

  }



  tcgetattr(fd, &options);

  options.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);

  tcsetattr(fd, TCSANOW, &options);

  int i=0;

  

  for (i=8320;i>5460;i--){

	  

	     command[2]=i&0x7F;

	     command[3]=(i>>7)&0x7F;

	     

	       if(write(fd,command,4) == EOF)

		  {

			fprintf(stderr, "error writing");

			exit(1);

		  }



	      printf("aqui\n");

		  int bytes_read = read(fd,buf,2);

		  printf("aqui2\n");

		  if(bytes_read != 2)

		  {

			fprintf(stderr, "error reading: %d bytes read", bytes_read);

			exit(1);

		  }



		  printf("Received: 0x%02x 0x%02x\n",buf[0],buf[1]);

}



  exit(0);

}

Could you try to run in your computer in order to know what is the problem.
Thank you for your help.

Please simplify this program to the simplest possible one that causes an error, and tell me exactly what that error is. Also please let us know about any warnings you got when compiling it.

-Paul

Oh, wait, I see what you are doing wrong. You have switched to a set servo command (132) - this does not return any data, so there will be nothing for you to read.

-Paul