Problem reading multiple properties through ASCII

Hello!
Setup: Teensy and ODrive (able to replicate issue on a test bench with just this)

We are running a control function, and at the end of the control function we save a bunch of the calculated variables (error, etc) as well as a few ODrive parameters (vbus_voltage, ibus, encoder_pos) and log them to an SD card. However, we have found in the logs that a lot of the time the ODrive parameters will switch at random throughout the run. For example, the voltage reading would stay consistently at the expected voltage, but then the reading would switch to the encoder position reading.

This is likely due to the timing of reading in values from the Serial connection. Below is the way we are currently using the ASCII protocol (same way as the Arduino library). We have considered just putting delays in-between the ODrive parameter calls, but don’t want the slowdown in the control function that it would cause.

Do you have any ideas as to ways we can ensure the data is successfully transmitted before requesting the next bit of data?

ODrive parameter requesting:

float ODrive::get_voltage()
{
  OdriveSerial << "r vbus_voltage\n";
  return ODrive::read_float();
}

This is the section of code that the variables get switched up in

  out[RPM] = eg_rpm;
  out[RPM_COUNT] = *m_eg_tooth_count;
  out[DT] = dt;
  out[ACT_VEL] = motor_velocity;
  out[ENC_POS] = odrive.get_encoder_pos(constant.actuator_motor_number);
  out[HALL_IN] = inbound_signal;
  out[HALL_OUT] = outbound_signal;
  out[T_START] = timestamp;
  out[ODRV_VOLT] = odrive.get_voltage();
  out[ODRV_CUR] = odrive.get_current();
  out[ROLLING_FRAME] = gb_rolling;
  out[EXP_DECAY] = gb_exp_decay;
  out[REF_RPM] = ref_rpm;
  out[T_STOP] = millis();

Any help would be appreciated, and thank you for your time!

Hmm, I haven’t used the serial commands much, or the Arduino library. But maybe there is a blocking version that you could use, in a separate thread? That could get complicated though tbh, and I don’t know if Arduino even supports threads.

Otherwise, you could maybe reduce the polling rate of the less important variables.
If out were a global struct and not a return value, then it would keep all of its last values unless you update them. So you don’t have to update -all- of them each time through the control loop. You could update half of them, and update the other half next time through the loop.
Of course, the trade-off with this is that your logging is less able to capture fast transient behaviour, but that’s probably a better outcome than slowing the control loop.

For example, you could do something like:

static uint8_t mux = 0;
switch(mux++ % 2)
{
    case 0:
        out.vbus_voltage = odrive.get_voltage();
        break;
    case 1:
        out.ibus_current = odrive.get_current();
        break;
    default:
      // error("The modulo must be the same as the number of cases .. ");
        break;
}

The normal library is blocking, they’d need a non-blocking one (timer without delay) is all.

With that said, when ODrive returns there’s no real way to know which variable it just returned via ASCII.

Hi, I have made a simple non-blocking Arduino library to communicate with the Odrive. You can take a look at it here:
bvtvusn/OdriveLink: This Arduino Library communicates with the Odrive BLDC controller. The communication supports checksums. The advantage of this library is that it does not hang if the Odrive does not respond to a command. Instead the callback will just not be called. (github.com)