SDC2160MR Serial communication irregularities in time

4 years 3 months ago #29534548 by Sergi
Hi,

My setup:
Linux Ubuntu 18LTS.
Motor controller: SDC2160MR
Motor: SC401H GEFEG-NECKAR
Encoder: RV30 GEFEG-NECKAR
RS232/USB adapter(Standard, cannot find manufacturer :( )
Industrial PC: NUC i3-7100U

I would like to send a motor command (set speed to the motor channel), request and read the encoder value and the speed value in the most robust way and fast as possible, I know there is a trade of with speed/robustness but I want to see how far I can get.. I use a serial RS232 comunication to read asynchronously the encoder and speed values (using boost library), basically its a callback that it gets called everytime I get data on the communication line. My PC does not have serial port so in order to convert it, I use an adapter serial/usb.

I use the linux APi functions clock_gettime() and sigprocmask() to get a time stamp and to block signals when doing critical operations
This is my main sequence.
while(1)
{

clock_gettime(CLOCK_MONOTONIC_RAW, &elapsed_from_sequence);
send_cmds();
clock_gettime(CLOCK_MONOTONIC_RAW, &elapsed_from_sequence_last);
diff_time = (elapsed_from_sequence_last.tv_nsec - elapsed_from_sequence.tv_nsec); 
//printf("%d - us elapsed reading\n", diff_time );

clock_gettime(CLOCK_MONOTONIC_RAW, &time_experiment_last);
				
float dif_end_experiment = (time_experiment_last.tv_sec - elapsed_from_sequence.tv_sec)*1000.0 + (time_experiment_last.tv_nsec elapsed_from_sequence.tv_nsec)/1000000.0;//ms
			
end_experiment = end_experiment + dif_end_experiment; //ms
			
if (end_experiment >= time_test)
{
  // LOG DATA AND CLOSE				
}
}

This are the commands that I am sending:
void send_cmds()
{
	boost::system::error_code error;
	// block the signal so it cannot enter to the callback async.
	sigprocmask (SIG_BLOCK, &block_read_cb, NULL);
   
	serial_driver->flush_serial_port(serial_driver->flush_send, error);
    serial_driver->flush_serial_port(serial_driver->flush_receive, error);

	serial_driver->send("!M 150 150");
	sigprocmask (SIG_UNBLOCK, &block_read_cb, NULL);
    // unblock the signal so we can read '+' and '/r'
	usleep(sleep_5ms);
	
	sigprocmask (SIG_BLOCK, &block_read_cb, NULL);

	clock_gettime(CLOCK_MONOTONIC_RAW, &time_elapsed_encoder);
	// block command encoder
	serial_driver->send("?C\r");

	sigprocmask (SIG_UNBLOCK, &block_read_cb, NULL);
	usleep(sleep_5ms);
	
	// un block
	std::cout<<"SENT: ?C" << std::endl;

	clock_gettime(CLOCK_MONOTONIC_RAW, &time_elapsed_speed);

	// block #########################
	sigprocmask (SIG_BLOCK, &block_read_cb, NULL); 

	serial_driver->send("?S\r"); // speed cmd

	// unblock
	sigprocmask (SIG_UNBLOCK, &block_read_cb, NULL);
	usleep(sleep_5ms);
	
}

Secondly, what I achieved: I am able to send and receive data at 0.1 ms. However, when I measure the difference between time stamps of the consecutive samples I have irregularities in the measure. What I found out is that sometimes I am sending commands to the controller but it does not give me a response(see 1.), or it gives the same data twice (see 2.). I tried to put sleep in the system so the driver has enough time to process the commands. the maximum sleep time that I tried was 500ms and the behaviour that I found was the same. Roughly about 5% of the data gets lost or did not have any response. I am wondering if this is normal and I should filter it out, or shall I configure something from the driver (I checked the manual carefully and did not find anything about it, like clearing communication buffer or something..)

With a sleep value of 5ms for each command I expect to have around 15-16ms of time response. However I see outliers in a upper boundary ( to ~40 ms) and low boundary ( ~0ms). Check the figure attached.

1. Behaviour for upper spikes: I am sending commands and the driver does not respond, so the time is increasing and when I get the next sample the difference in time is higher. It does not get into the callback that initiates the read process.

2. Behaviour for low spikes: In the while loop iteration I see the encoder values printed twice although I was asking them once. because it processes the data twice in the same loop iteration, The difference in time in the consecutive samples is really low .

Finally my personal opinion. I think that this problem was caused because I was saturating the motor control driver with so many commands that when the reading buffer is full, it needs time to clear it and fill it again. But then it does not make sense that when I gave the driver sleep times of 500 ms, it is not able to manage it...
I read that USB communication is not that robust as using RS232 or R485. My guess is that the adapter + using usb can be messing this data.
My last guess is that the problem is in the driver. So I should write the basic script to clear the buffer and give priority to the encoder / speed cmds. I know I could filter this data easily and remove outliers, but this increases computation time and I think maybe I am missing something important.

I would like the follwing from the community:
1. I would like to know if you have any suggestion about the issue.
2. If you know of a project with a similar aim that I can look at.
3. There are known issues about buffer overloading of the motor controller driver. There is any way to flush the buffer?

Cheers!
Attachments:

Please Log in or Create an account to join the conversation.

4 years 3 months ago #29534554 by Gabriel_Isko
Can you verify that you are actually sending data to the serial port when we drop the data? It doesn't look great that you are trying to interact with a serial port during a blocked signal, but it is impossible to tell without access to your serial driver source. We use the sstream library in our API.

Please Log in or Create an account to join the conversation.

4 years 3 months ago #29534563 by Sergi
I made a simple test. I made a shortcut in the rx, tx signals with a connector. I assume then that the motor were responding instantly. I found the same behavior, I conclude that the problem arises in my serial driver and not in the motor.

// for curiosity
I am reading the data as a string with termination character, I guess that what is happening is that the asynchronous cyclic check of the buffer does not complete the data, so it remains blocked for a while.

I am going to implement this by reading character by character instead.

Cheers!

Please Log in or Create an account to join the conversation.

4 years 3 months ago #29534564 by Gabriel_Isko
Okay, this is what I expected.

Just a heads up - we do not send a null character in our serial input. We will terminate with a carriage return though.

Please Log in or Create an account to join the conversation.

Moderators: tonysantoni
Time to create page: 0.057 seconds