Arduino+odrive skip calibration

I just managed to get my odrive working with arduino, but since i’m planning to use this in restricted mechanical space, is there a way to only have to do calibration once, and then save the calibration somehow so i don’t have to calibrate each power up?
I can’t afford to have my components moving without me telling them too, as it will be used in a car shifter.

EDIT: I followed the instructions on this page: https://docs.odriverobotics.com/encoders.html
It did this using odrivetool, expecting that when hooking up the arduino it uses that config.

1 Like

You need an encoder with an index signal (Z line), and then you should be able to use the instructions on that page. If you MUST know the angle of the encoder at boot-up without it moving whatsoever, you need an absolute encoder. Support for those is in progress.

I used the encoder ordered from the Odrive shop, which has a Z-line, i did find that in the arduino code, i can do the index search, but after that it falls idle and can’t give a position.

This is what my calibration looks like so far, it gives me a beep, goes to the index and stops, then falls trough to idle, but can’t send it to a position at this point. Do i need the closed_loop state?
Last time i did the closed loop, it started spinning at full speed, without stopping.
Here’s the code i have for the current calibration:

        requested_state = ODriveArduino::AXIS_STATE_MOTOR_CALIBRATION;
        Serial << "Axis" << 0 << ": Requesting state " << requested_state << '\n';
        odrive.run_state(atoi(0), requested_state, true);

        requested_state = ODriveArduino::AXIS_STATE_ENCODER_INDEX_SEARCH;
        Serial << "Axis" << 0 << ": Requesting state " << requested_state << '\n';
        odrive.run_state(atoi(0), requested_state, true);

Yes the closed_loop state is basically the active state. It won’t respond to commands outside of that state.

Mount the motor safely and adjust your current limit so that it has little torque and start playing with params.

Mount the motor safely

Yea, this might help with testing, only had a bracket to mount on the encoder so far, i’ll print a new holder to do some safe testing. After that i’ll get back to you with my findings (good or bad)

EDIT: Yes indeed that was what i had to do, just added the closed loop state, and now it works.
i’m guessing the encoder position was so far off that it needed too many rotations, which probably confused me.
Important thing is, it works now!
If anyone is in need of the arduino sketch, i’ll gladly make an example code!

1 Like

Hello. I would be happy to take a look to the arduino sketch. I am running into the same exact problem with the AXIS_STATE_CLOSED_LOOP_CONTROL. As soon as I executed it, the motor started spinning out of control. If you can explain it a little bit to me, if you can, please do so. Thanks

#include <SoftwareSerial.h>
#include <ODriveArduino.h>



// Printing with stream operator
template<class T> inline Print& operator <<(Print &obj,     T arg) { obj.print(arg);    return obj; }
template<>        inline Print& operator <<(Print &obj, float arg) { obj.print(arg, 4); return obj; }
// Serial to the ODrive
SoftwareSerial odrive_serial(10, 11); //RX (ODrive TX), TX (ODrive RX)
ODriveArduino odrive(odrive_serial);

void setup() {
  // put your setup code here, to run once:
  odrive_serial.begin(115200);  //Odrive Serial port
      Serial.begin(115200);       //arduino - pc serial
      while (!Serial) ; // wait for Arduino Serial Monitor to open

      Serial.println("ODriveArduino");
      Serial.println("Setting parameters...");
   for (int axis = 0; axis < 2; ++axis) {
    odrive_serial << "w axis" << axis << ".controller.config.vel_limit " << 8500.0f << '\n'; //FeedRate Limit
    odrive_serial << "w axis" << axis << ".motor.config.current_lim " << 1.0f << '\n';       //Current Limit
   }
   Serial.println("Send the character '0' or '1' to calibrate respective motor");
   Serial.println("Send the character '+' or '-' to test moves");
   //calibrateO();
}

void calibrateO()
{
    int requested_state;
    requested_state = ODriveArduino::AXIS_STATE_MOTOR_CALIBRATION;
    Serial << "Axis" << 0 << ": Requesting state " << requested_state << '\n';
    odrive.run_state(atoi(0), requested_state, true);

    requested_state = ODriveArduino::AXIS_STATE_ENCODER_INDEX_SEARCH;
    Serial << "Axis" << 0 << ": Requesting state " << requested_state << '\n';
    odrive.run_state(atoi(0), requested_state, true);

    requested_state = ODriveArduino::AXIS_STATE_CLOSED_LOOP_CONTROL ;
    Serial << "Axis" << 0 << ": Requesting state " << requested_state << '\n';
    odrive.run_state(atoi(0), requested_state, false); // don't wait

    //odrive.save_configuration();
    delay(5);
    Serial.println("Saved Config");
}
void testMoves()
{
  if (Serial.available()) 
  {
    char c = Serial.read();
    if (c == '0')
    {
       calibrateO();
    }
    if (c == '+')
    {
      odrive.SetPosition(0, 1000);    
    }
    if (c == '-')
    {
      odrive.SetPosition(0, 0);   
    }
    if (c == '2')//Read encoder position
    {
        odrive_serial << "r axis" << 0 << ".encoder.pos_estimate\n";
        Serial << odrive.readFloat() << '\t';   
    }   
  }
}
void loop() {
  // put your main code here, to run repeatedly:
  testMoves();
}

Thanks very much for the code. I will take a look at it. Do you remember the settings for the USB protocos? Right now I have both as native. Not so sure if this are the correct one.

Thanks man!!

All i did besides the code was follow the instructions on this page.