Need help arduino control

Hi…i m playing odrive a week…i like odrive…i need a sketch for arduinio…that will control odrive…
1 incremental encoder connected to arduino …and 1 encoder attached to hoverboard hub motor…i want that when i turn the encoder that connect to arduino ,the hub motor acts like the position of arduino encoder.
i tried but writing a sketch is chinese for me…do i need to pay for the sketch? Thnx

Hello

You can use the ODrive Arduino library (https://github.com/madcowswe/ODrive/tree/master/Arduino/ODriveArduino). There is an example sketch you can work with and learn from.

The encoder from the hoverboard hub motor needs to be set up in the ODrive firmware via odrivetool. The process of setting up the encoder is well-described here (https://docs.odriverobotics.com)

Why would you want to control a hoverboard with an encoder? Isn’t it better to just have a potentiometer to do speed control? But if you want to read encoders using Arduino, I can recommend you to start with the encoder lib for Arduino (https://github.com/PaulStoffregen/Encoder)

If you are stuck somewhere, I am willing to find some time to help you.

Thank you…i want to make position control…speed not important…i want to make something like that…

Do you think odrive can handle that job on the first video?

Yes, the odrive with the help of an arduino can accomplish what is in the first video.

Use the position (setPosition) part of the arduino example in the example link above. You would then be easily to take in position information of encoder not connected to the motor, and ouput that number to the odrive using setposition. This should accomplish what is in the first video.

Note, you will have to make sure that your pulses per revolution for each of the encoders are either the same or convert them to match each other.

Rough non programming flow:

  1. Get encoder position of separate encoder (example: 250)
  2. Set position of odrive motor using setPosition (example: 250)
  3. Output position data to serial to confirm positions match

Again, both encoders’ PPR will need to match for this to work.

Also, as lowiek said above, the hoverboard motors will need to be set up using the odrive firmware before being able to control with arduino if my understanding is right.

1 Like

Thanks a lot…i will try…

Hi again…can you show me a simple sketch if you have time thanks.i attached encoder to arduino and read encoder positions on serial monitor.but i couldnt make odrive to understand that…

Post your arduino code, so that we can see what you are doing.

// here it is thank you,
#include <SoftwareSerial.h>
#include <ODriveArduino.h>

// Printing with stream operator
template 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(8, 9); //RX (ODrive TX), TX (ODrive RX)
// Note: you must also connect GND on ODrive to GND on Arduino!

// ODrive object
ODriveArduino odrive(odrive_serial);

// encoder object
static int pinA = 2; // Our first hardware interrupt pin is digital pin 2
static int pinB = 3; // Our second hardware interrupt pin is digital pin 3
volatile byte aFlag = 0; // let’s us know when we’re expecting a rising edge on pinA to signal that the encoder has arrived at a detent
volatile byte bFlag = 0; // let’s us know when we’re expecting a rising edge on pinB to signal that the encoder has arrived at a detent (opposite direction to when aFlag is set)
volatile byte encoderPos = 0; //this variable stores our current value of encoder position. Change to int or uin16_t instead of byte if you want to record a larger range than 0-255
volatile byte oldEncPos = 0; //stores the last encoder position value so we can compare to the current reading and see if it has changed (so we know when to print to the serial monitor)
volatile byte reading = 0; //somewhere to store the direct values we read from our interrupt pins before checking to see if we have moved a whole detent

void setup() {
// ODrive uses 115200 baud
odrive_serial.begin(115200);

// Serial to PC
Serial.begin(115200);
while (!Serial) ; // wait for Arduino Serial Monitor to open

Serial.println(“ODriveArduino”);
Serial.println(“Setting parameters…”);
Serial.println(“Ready!”);
Serial.println(“Send the character ‘0’ or ‘1’ to calibrate respective motor (you must do this before you can command movement)”);
Serial.println(“Send the character ‘s’ to exectue test move”);
Serial.println(“Send the character ‘b’ to read bus voltage”);
Serial.println(“Send the character ‘p’ to read motor positions in a 10s loop”);
// encoder setup
pinMode(pinA, INPUT_PULLUP); // set pinA as an input, pulled HIGH to the logic voltage (5V or 3.3V for most cases)
pinMode(pinB, INPUT_PULLUP); // set pinB as an input, pulled HIGH to the logic voltage (5V or 3.3V for most cases)
attachInterrupt(0,PinA,RISING); // set an interrupt on PinA, looking for a rising edge signal and executing the “PinA” Interrupt Service Routine (below)
attachInterrupt(1,PinB,RISING); // set an interrupt on PinB, looking for a rising edge signal and executing the “PinB” Interrupt Service Routine (below)
// Serial.begin(115200); // start the serial monitor link
}

void loop() {
if(oldEncPos != encoderPos) {
Serial.println(encoderPos);
oldEncPos = encoderPos;
}
if (Serial.available()) {
char c = Serial.read();

// Run calibration sequence
if (c == '0' || c == '1') {
  int motornum = c-'0';
  int requested_state;

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

  requested_state = ODriveArduino::AXIS_STATE_ENCODER_OFFSET_CALIBRATION;
  Serial << "Axis" << c << ": Requesting state " << requested_state << '\n';
  odrive.run_state(motornum, requested_state, true);

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

// Sinusoidal test move
  if(encoderPos>0) {
//Serial.println(encoderPos);
  odrive.SetPosition(0, encoderPos*100);

// oldEncPos = encoderPos;

}
}
}
void PinA(){
cli(); //stop interrupts happening before we read pin values
reading = PIND & 0xC; // read all eight pin values then strip away all but pinA and pinB’s values
if(reading == B00001100 && aFlag) { //check that we have both pins at detent (HIGH) and that we are expecting detent on this pin’s rising edge
encoderPos --; //decrement the encoder’s position count
bFlag = 0; //reset flags for the next turn
aFlag = 0; //reset flags for the next turn
}
else if (reading == B00000100) bFlag = 1; //signal that we’re expecting pinB to signal the transition to detent from free rotation
sei(); //restart interrupts
}

void PinB(){
cli(); //stop interrupts happening before we read pin values
reading = PIND & 0xC; //read all eight pin values then strip away all but pinA and pinB’s values
if (reading == B00001100 && bFlag) { //check that we have both pins at detent (HIGH) and that we are expecting detent on this pin’s rising edge
encoderPos ++; //increment the encoder’s position count
bFlag = 0; //reset flags for the next turn
aFlag = 0; //reset flags for the next turn
}
else if (reading == B00001000) aFlag = 1; //signal that we’re expecting pinA to signal the transition to detent from free rotation
sei(); //restart interrupts
}

Okay, so a few things. What encoder are you using with the odrive/motor combination, and what encoder are you using as the standalone one that is connected to the arduino?

Also, before trying to combine the two, have you tried just getting your odrive working with the arduino and the ODriveArduinoTest.ino file?

Lastly, I would recommend using the encoder library from pjrc https://www.pjrc.com/teensy/td_libs_Encoder.html. It makes setting up and reading encoders much easier.

wayneStock

i m using 600 ppr incremental encoder for arduino and the motor… odriveArduinotest.ino is working good…setposition command working good…but i m not good at coding …i copy and paste some arduino sketchs…but i couldnt…i checked the library, newleft, newright positions… but how can i tell odrive to set these positions(newleft, newright in the library) .thnks again…

Okay give me a second to put something together. What arduino are you using for this?

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

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; }

Encoder encoder2(2, 3); //Pins must be interrupt pins for arduino in use (2, 3) is used for UNO
// Serial to the ODrive
SoftwareSerial odrive_serial(8, 9); //RX (ODrive TX), TX (ODrive RX)
ODriveArduino odrive(odrive_serial);

int axis0 = 0;
volatile long encoder2Pos = 0;
bool calibrationBool = false;

void setup() 
{
  // ODrive uses 115200 baud
  odrive_serial.begin(115200);

  // Serial to PC
  Serial.begin(115200);
  while (!Serial) ; // wait for Arduino Serial Monitor to open

  Serial.println("ODriveArduino");
  Serial.println("Setting parameters...");

  // Lets just stick with one motor for now - Setting velocity limit and current limit
  odrive_serial << "w axis" << axis0 << ".controller.config.vel_limit " << 22000.0f << '\n';
  odrive_serial << "w axis" << axis0 << ".motor.config.current_lim " << 11.0f << '\n';

  Serial.println("Ready!");
  Serial.println("Send the character '0' calibrate motor (you must do this before you can command movement)");
  Serial.println("Send the character 's' to exectue test move");
  Serial.println("Send the character 'b' to read bus voltage");
  Serial.println("Send the character 'p' to read motor positions in a 10s loop");
}
void loop() 
{

  encoder2Pos = encoder2.read();
  
  if (Serial.available()) 
  {
    char c = Serial.read();

    // Run calibration sequence
    if (c == '0') //Only worrie about motor0
    {
      int requested_state;

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

      requested_state = ODriveArduino::AXIS_STATE_ENCODER_OFFSET_CALIBRATION;
      Serial << "Axis" << c << ": Requesting state " << requested_state << '\n';
      odrive.run_state(axis0, requested_state, true);

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

      calibrationBool = true;
    }

  
    // Read bus voltage
    if (c == 'b') 
    {
      odrive_serial << "r vbus_voltage\n";
      Serial << "Vbus voltage: " << odrive.readFloat() << '\n';
    }
    if (c == 'r') //reset encoder val to 0
    {
      encoder2.write(0);
      odrive.SetPosition(axis0, 0.0);
    }

  }

  if (calibrationBool) //Will not run until calibration has been performed
  {
    float motorPos = float(encoder2Pos); //Get encoder 2 position and convert to float

    odrive.SetPosition(axis0, motorPos); //Set odrive motor equal to encoder 2 position
  }
}

Try something like this to get you started. Mind you, I have not tested this code, so I cannot say that it will 100% work, but it should get you going in the right direction.

Also want to note that you will need change your encoder pins to match your interrupt arduino pins.

Lastly, I would also make a new sketch to test just the encoder portion of the code. Make sure that one revolution of the encoder is actually 600 pulses using this library.

hi
i have good news and bad news.

first try: it works perfect …very happy…thanks a lot.

then i disconnect battery from o drive and arduino,

second try : odrive stops working…i tried both on arduino and anaconda… windows cant realise odrive…

any suggestions??

As in odrive does not show up in your window devices?

yes not shown windows devices…i think i need to install odrive firmware again…interesting…this will be 3rd installation…