odriverobotics / ODriveArduino

Arduino library for the ODrive
MIT License
10 stars 9 forks source link

odrive.getFeedback() not working properly #1

Open PascalSpino opened 1 year ago

PascalSpino commented 1 year ago

Hello, The getFeedback() and getPosition(), getVelocity() functions do not seem to work for me. I am using an ODrive S1 with Teensy 3.6. I have followed the tutorial "Controlling ODrive from an Arduino". The only modification I made to the example sketch was to change the Serial ports. I successfully control the position of the motor with repeating sinusoidal motion - no issues here. I have verified separately with odrivetool and the web GUI that the position and velocity feedback coming from the ODrive over USB are accurate. However, the functions getFeedback (as well as getPosition and getVelocity) from the Arduino sketch are extremely unreliable. feedback.pos and feedback.vel are almost always 0, apart from seemingly accurate values once every so often. I have tried commenting out the setPosition function of the example script and rotating the motor by hand but the same unexpected behavior occurs. The getPosition and getVelocity functions behave similarly except they also return very large positive and negative integers frequently.

samuelsadok commented 1 year ago

The return value 0.0 is typical for when no reply, or a reply with an incorrect formatting was received (as per Arduino convention - I wish it would default to safer error handling).

The most likely reason for this, especially if it's intermittent, is that the signal on the line isn't sufficiently clean, so the UART reads wrong characters.

Are you using a hardware serial port on the Teensy? What baudrate did you set? Do you have a possibility to inspect the data directly on the line? (USB-serial-adapter, logic analyzer, oscilloscope)

PascalSpino commented 1 year ago

I am using the hardware serial port on the Teensy, with a baud rate of 19200. I have tried other baud rates and hardware serial ports but seen the same issue. I cannot inspect the data directly for now, but I have noticed that the getFeedback() does consistently give me the correct values over a certain range of travel for the motor (although it mostly returns zeros, just sometimes a believable value over this particular range). For the rest of the range of travel the values it gives are completely incorrect (very large numbers or zero).

I have wired up the Teensy to the ODrive S1 as the tutorial shows with the Uno. Do I need to do anything special to keep the signal line clean? Communication to the ODrive with setPosition() seems perfect, it is just getting feedback from the ODrive that is problematic. I have a 2 Ohm resistor connected to the ODrive S1 for braking and I am using an incremental encoder (AMT102-V) that I have verified works with the web GUI.

samuelsadok commented 1 year ago

With a hardware serial port I would expect it to work fine at a baudrate of 19200 (or actually higher too).

Here are two more suggestions:

Note that the ODrive simply discards messages that don't have the correct format. This is why the Arduino example sends setpoints continuously, so that it can tolerate some degree of message loss/corruption. If the rate of errors is low enough, you wouldn't notice. The getFeedback() exchange is in general more complex than setPosition() (it involves two messages instead of one), so it's plausible that it would fail more often.

PascalSpino commented 1 year ago

Thank you for your help, I was able to find the source of the issue and get everything working. The culprit were these lines

  serial_ << "f " << kMotorNumber << "\n";
  String response = readLine();

In the getFeedback() function.

The Teensy 3.6 was evidently operating 'too fast' by sending out the feedback request to the ODrive and then reading back the response before the entire message had been sent back by the ODrive. This resulted in a partial response being received by the Teensy each time - explaining a lot of the strange behavior. I tested on an Arduino Uno and the same issue did not present itself because the Uno operates slow enough to not run into this issue, it seems. The problem could be fixed by adding a short delay between sending the request to the ODrive and reading the response, but I just increased the baud rate until receiving the response from the ODrive was consistently faster than the Teensy.

Ideally, I would like to continue to read the response until a message-terminating-character is received from the ODrive, at which point I know a full response has been collected and the program can continue. This solution would then be independent of microcontroller speed or baud rate. However, it does not seem that the feedback response from the ODrive contains any consistent terminating character. Is this correct?

samuelsadok commented 1 year ago

I see, interesting. The response does have a terminating character, which is \n. readLine() waits for this, but it has a default timeout of 10ms (defined in the header file). Running the numbers, 10ms at 19200 baud/s leaves time for 20 bytes, which may indeed be a bit on the tight side.

Can you increase the timeout to 50ms and see if that works without other modifications?