*
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017 Oskar Weigl
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,91 @@
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "ODriveArduino.h"
|
||||
|
||||
static const int kMotorOffsetFloat = 2;
|
||||
static const int kMotorStrideFloat = 28;
|
||||
static const int kMotorOffsetInt32 = 0;
|
||||
static const int kMotorStrideInt32 = 4;
|
||||
static const int kMotorOffsetBool = 0;
|
||||
static const int kMotorStrideBool = 4;
|
||||
static const int kMotorOffsetUint16 = 0;
|
||||
static const int kMotorStrideUint16 = 2;
|
||||
|
||||
// Print 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; }
|
||||
|
||||
ODriveArduino::ODriveArduino(Stream& serial)
|
||||
: serial_(serial) {}
|
||||
|
||||
void ODriveArduino::SetPosition(int motor_number, float position) {
|
||||
SetPosition(motor_number, position, 0.0f, 0.0f);
|
||||
}
|
||||
|
||||
void ODriveArduino::SetPosition(int motor_number, float position, float velocity_feedforward) {
|
||||
SetPosition(motor_number, position, velocity_feedforward, 0.0f);
|
||||
}
|
||||
|
||||
void ODriveArduino::SetPosition(int motor_number, float position, float velocity_feedforward, float current_feedforward) {
|
||||
serial_ << "p " << motor_number << " " << position << " " << velocity_feedforward << " " << current_feedforward << "\n";
|
||||
}
|
||||
|
||||
void ODriveArduino::SetVelocity(int motor_number, float velocity) {
|
||||
SetVelocity(motor_number, velocity, 0.0f);
|
||||
}
|
||||
|
||||
void ODriveArduino::SetVelocity(int motor_number, float velocity, float current_feedforward) {
|
||||
serial_ << "v " << motor_number << " " << velocity << " " << current_feedforward << "\n";
|
||||
}
|
||||
|
||||
void ODriveArduino::SetCurrent(int motor_number, float current) {
|
||||
serial_ << "c " << motor_number << " " << current << "\n";
|
||||
}
|
||||
|
||||
void ODriveArduino::TrapezoidalMove(int motor_number, float position){
|
||||
serial_ << "t " << motor_number << " " << position << "\n";
|
||||
}
|
||||
|
||||
float ODriveArduino::readFloat() {
|
||||
return readString().toFloat();
|
||||
}
|
||||
|
||||
float ODriveArduino::GetVelocity(int motor_number){
|
||||
serial_<< "r axis" << motor_number << ".encoder.vel_estimate\n";
|
||||
return ODriveArduino::readFloat();
|
||||
}
|
||||
|
||||
int32_t ODriveArduino::readInt() {
|
||||
return readString().toInt();
|
||||
}
|
||||
|
||||
bool ODriveArduino::run_state(int axis, int requested_state, bool wait) {
|
||||
int timeout_ctr = 100;
|
||||
serial_ << "w axis" << axis << ".requested_state " << requested_state << '\n';
|
||||
if (wait) {
|
||||
do {
|
||||
delay(100);
|
||||
serial_ << "r axis" << axis << ".current_state\n";
|
||||
} while (readInt() != requested_state && --timeout_ctr > 0);
|
||||
}
|
||||
|
||||
return timeout_ctr > 0;
|
||||
}
|
||||
|
||||
String ODriveArduino::readString() {
|
||||
String str = "";
|
||||
static const unsigned long timeout = 1000;
|
||||
unsigned long timeout_start = millis();
|
||||
for (;;) {
|
||||
while (!serial_.available()) {
|
||||
if (millis() - timeout_start >= timeout) {
|
||||
return str;
|
||||
}
|
||||
}
|
||||
char c = serial_.read();
|
||||
if (c == '\n')
|
||||
break;
|
||||
str += c;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
|
||||
#ifndef ODriveArduino_h
|
||||
#define ODriveArduino_h
|
||||
|
||||
#include "Arduino.h"
|
||||
|
||||
class ODriveArduino {
|
||||
public:
|
||||
enum AxisState_t {
|
||||
AXIS_STATE_UNDEFINED = 0, //<! will fall through to idle
|
||||
AXIS_STATE_IDLE = 1, //<! disable PWM and do nothing
|
||||
AXIS_STATE_STARTUP_SEQUENCE = 2, //<! the actual sequence is defined by the config.startup_... flags
|
||||
AXIS_STATE_FULL_CALIBRATION_SEQUENCE = 3, //<! run all calibration procedures, then idle
|
||||
AXIS_STATE_MOTOR_CALIBRATION = 4, //<! run motor calibration
|
||||
AXIS_STATE_SENSORLESS_CONTROL = 5, //<! run sensorless control
|
||||
AXIS_STATE_ENCODER_INDEX_SEARCH = 6, //<! run encoder index search
|
||||
AXIS_STATE_ENCODER_OFFSET_CALIBRATION = 7, //<! run encoder offset calibration
|
||||
AXIS_STATE_CLOSED_LOOP_CONTROL = 8 //<! run closed loop control
|
||||
};
|
||||
|
||||
ODriveArduino(Stream& serial);
|
||||
|
||||
// Commands
|
||||
void SetPosition(int motor_number, float position);
|
||||
void SetPosition(int motor_number, float position, float velocity_feedforward);
|
||||
void SetPosition(int motor_number, float position, float velocity_feedforward, float current_feedforward);
|
||||
void SetVelocity(int motor_number, float velocity);
|
||||
void SetVelocity(int motor_number, float velocity, float current_feedforward);
|
||||
void SetCurrent(int motor_number, float current);
|
||||
void TrapezoidalMove(int motor_number, float position);
|
||||
// Getters
|
||||
float GetVelocity(int motor_number);
|
||||
// General params
|
||||
float readFloat();
|
||||
int32_t readInt();
|
||||
|
||||
// State helper
|
||||
bool run_state(int axis, int requested_state, bool wait);
|
||||
private:
|
||||
String readString();
|
||||
|
||||
Stream& serial_;
|
||||
};
|
||||
|
||||
#endif //ODriveArduino_h
|
||||
@@ -0,0 +1,6 @@
|
||||
# ODriveArduino
|
||||
Arduino library for the ODrive
|
||||
|
||||
To install the library, first clone this repository. In the Arduino IDE select: *Sketch -> Include Library -> Add .ZIP Library...*
|
||||
|
||||
Select the enclosing folder (e.g. ODriveArduino) to add it. Restarting the Arduino IDE may be necessary to see the examples in the *File* dropdown. Check the included example *ODriveArduinoTest* for basic usage.
|
||||
+97
@@ -0,0 +1,97 @@
|
||||
|
||||
#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(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);
|
||||
|
||||
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...");
|
||||
|
||||
// In this example we set the same parameters to both motors.
|
||||
// You can of course set them different if you want.
|
||||
// See the documentation or play around in odrivetool to see the available parameters
|
||||
for (int axis = 0; axis < 2; ++axis) {
|
||||
odrive_serial << "w axis" << axis << ".controller.config.vel_limit " << 22000.0f << '\n';
|
||||
odrive_serial << "w axis" << axis << ".motor.config.current_lim " << 11.0f << '\n';
|
||||
// This ends up writing something like "w axis0.motor.config.current_lim 10.0\n"
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
|
||||
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 (c == 's') {
|
||||
Serial.println("Executing test move");
|
||||
for (float ph = 0.0f; ph < 6.28318530718f; ph += 0.01f) {
|
||||
float pos_m0 = 20000.0f * cos(ph);
|
||||
float pos_m1 = 20000.0f * sin(ph);
|
||||
odrive.SetPosition(0, pos_m0);
|
||||
odrive.SetPosition(1, pos_m1);
|
||||
delay(5);
|
||||
}
|
||||
}
|
||||
|
||||
// Read bus voltage
|
||||
if (c == 'b') {
|
||||
odrive_serial << "r vbus_voltage\n";
|
||||
Serial << "Vbus voltage: " << odrive.readFloat() << '\n';
|
||||
}
|
||||
|
||||
// print motor positions in a 10s loop
|
||||
if (c == 'p') {
|
||||
static const unsigned long duration = 10000;
|
||||
unsigned long start = millis();
|
||||
while(millis() - start < duration) {
|
||||
for (int motor = 0; motor < 2; ++motor) {
|
||||
odrive_serial << "r axis" << motor << ".encoder.pos_estimate\n";
|
||||
Serial << odrive.readFloat() << '\t';
|
||||
}
|
||||
Serial << '\n';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user