horchler / DynamixelQ

Library to control ROBOTIS Dynamixel smart servo actuators with the OpenCM9.04 microcontroller
12 stars 5 forks source link

noInterrupts() doesn't work with Dxl.read and Dxl.write ? #1

Closed Rouno closed 6 years ago

Rouno commented 6 years ago

Hi @horchler, a couple of months ago you recommended me to use your own library instead of Robotis one and I'm glad I did this. However I'm facing a new problem here.

Not sure this is a related issue but do you know if DynamixelQ library rely on interruption ? I have problems in syncRead and syncWrite when I disable interruption. Any data I get from my actuators is 255 and writing data makes nothing ! Here is roughly what I'm doing :

...

void loop() { noInterrupts(); Dxl.syncRead(...); //4 actuators, reading position, speed and load

... some light code ...

Dxl.syncWrite(...); //4 actuators, writing position, speed and load

USBprintf(...); //4 actuators, printing position, speed and load to pc interrupts(); }

void usbInterrupts(byte* buffer, byte nCount) { process actuators position, speed and torque commands from pc }

Would you have any suggestion ? Many thanks for your help !

horchler commented 6 years ago

Hmmm. I've never tested this sort of thing. The begin method of the DXL object does attach a USART interrupt (see line 64 of DXLQ.cpp). This is how the OpenCM9.04 talks to the actuators. Board.cpp uses timer interrupts for blink functionality, but I don't think you're using that.

Does this only occur with syncRead and syncWrite? And do you know if it's one or the other or both that have issues? How about with lower level functions like readWord and writeWord? I'd also make sure that it's not USBprintf itself by moving it to outside of the interrupt blocking. Printing over serial may also rely on interrupts, but I'd have to dive deep into the low level code for the board to see how.

What are you trying to do by blocking interrupts? Are you blocking your own interrupts or just trying to get better performance? If the former, then think you may need to just disable your own interrupts.

See also this page and this post (Arduino-focussed, but still applicable I think; function names may vary).

Rouno commented 6 years ago

Hi Horchler, Many thanks to take the time to answer me :) Actually my program is very simple : I'm running a control application on my PC (using processing) that is receiving actuators sensor data from openCM and also sending actuator commands.

I think that interruptions might not be the best way to do that though ... But I also tried without (although the function name is still usbInterrupt) with just a :

void loop(){
  byte buffer[64];
  int size=0;
  while(SerialUSB.available()){
    buffer[size]=SerialUSB.read();
    size+=1;
  }
  usbInterrupt(buffer,size);
...
}

But in that case the program on OpenCM crashes after a few second after my processing application sends commands

horchler commented 6 years ago

Just a quick response now (more later or tomorrow).

I think I understand what you're doing. Have you tried using SerialUSB.attachInterrupt(usbInterrupt); and defining a void usbInterrupt(byte* buffer,byte ncount) function? This is described a bit here at the bottom of the page. I've used this approach to send command over USB from a computer (not with Processing though). I'll try to find some example code tonight.

See also my tosser and smartTosser examples in the examples folder. These assume that raw Dynamixel commands are being sent (the OpenCM9.04 hardly does any work here other than piping data), but the basic idea is there and can be converted to something else maybe. The tosser approach is useful in same cases, but obviously can introduce latency.

Rouno commented 6 years ago

I tried that in the first place but got few corrupted data when sending data from pc to OpenCM and the same data from OpenCM back to pc. (4 * 3 integers every 20ms) But getting corrupted data may just be normal and that I should be using checksum function ...

Rouno commented 6 years ago

Just a quick update on this, I figured out how to solve this issue by using SerialUSB.detachInterrupt() and SerialUSB.attachInterrupt(usbInterrupt) as encapsulation of dynamixel syncreading and syncwriting code