Odrive integrate in Marlin

Hello dear community,

I thought a topic about the firmware Marlin would be very helpful, because I have read many questions and also have questions myself.
Maybe we can chat here and help each other in terms of integrating the Odrive system into the firmware.

best regards
Tim

1 Like

My project!

I’m currently building a FDM machine (3D printer) with a buildspace of 400x400x400 mm. I use the Corexy system for the x- and y-axis. The z-axis is moved by three threaded spindles connected to a motor.
The motor for the z-axis as well as the two motors for the x- and y-axis are equipped with the Odrive v3.6 system. I use the “Bigtree skr pro v1.1” board as mainboard.

My ODrive system consists of two “Odrive v3.6” (24V) and three “DUAL SHAFT MOTOR - D6374 150KV”. The motors are each equipped with a “CUI AMT102” encoder.
For programming I use Anaconda (Odrive) and Visual Studio code + PlatformIO (Marlin)

I connected the Odrive v3.6 to the mainboard via the pins GND, step and direct. For that I configured the Odrive v3.6 as described in https://docs.odriverobotics.com/interfaces-> Step / direction. Of course, I went through the “Getting Started” process before.

These commands helped me with the setup. (https://docs.odriverobotics.com/encoders -> Startup sequence notes)

odrv0.axis0.motor.config.current_lim = 5
odrv0.config.brake_resistance = 0.02
odrv0.axis0.motor.config.pole_pairs = 7
odrv0.axis0.encoder.config.cpr = 8192
odrv0.axis0.encoder.config.mode = ENCODER_MODE_INCREMENTAL
odrv0.axis0.motor.config.motor_type = MOTOR_TYPE_HIGH_CURRENT`
odrv0.axis0.encoder.config.calib_range = 0.05
odrv0.axis0.motor.config.calibration_current = 10.0
odrv0.axis0.motor.config.resistance_calib_max_voltage = 12.0
odrv0.axis0.controller.config.vel_limit = 50000
odrv0.save_configuration()
odrv0.reboot()

2 Likes

Integration of the Odrive system into the firmware Marlin.

As I have read / understood, nothing needs to be adjusted in Marlin. Only the motor drivers must be deactivated.

//#define X_DRIVER_TYPE A4988
//#define Y_DRIVER_TYPE A4988
//#define Z_DRIVER_TYPE A4988
//#define X2_DRIVER_TYPE A4988
//#define Y2_DRIVER_TYPE A4988
//#define Z2_DRIVER_TYPE A4988
//#define Z3_DRIVER_TYPE A4988
//#define E0_DRIVER_TYPE A4988
//#define E1_DRIVER_TYPE A4988
//#define E2_DRIVER_TYPE A4988
//#define E3_DRIVER_TYPE A4988
//#define E4_DRIVER_TYPE A4988
//#define E5_DRIVER_TYPE A4988

But in the Marlin firmware there is a section about encoders. Does something have to be changed here?

// ENCODER SETTINGS
//
// This option overrides the default number of encoder pulses needed to
// produce one step. Should be increased for high-resolution encoders.
//
//#define ENCODER_PULSES_PER_STEP 4
//
// Use this option to override the number of step signals required to
// move between next/prev menu items.
//
//#define ENCODER_STEPS_PER_MENU_ITEM 1
/**

  • Encoder Direction Options
  • Test your encoder’s behavior first with both options disabled.
  • Reversed Value Edit and Menu Nav? Enable REVERSE_ENCODER_DIRECTION.
  • Reversed Menu Navigation only? Enable REVERSE_MENU_DIRECTION.
  • Reversed Value Editing only? Enable BOTH options.
    */
    //
    // This option reverses the encoder direction everywhere.
    //
    // Set this option if CLOCKWISE causes values to DECREASE
    //
    //#define REVERSE_ENCODER_DIRECTION
    //
    // This option reverses the encoder direction for navigating LCD menus.
    //
    // If CLOCKWISE normally moves DOWN this makes it go UP.
    // If CLOCKWISE normally moves UP this makes it go DOWN.
    //
1 Like

My problems. :sob:

  • The engines do not move when I send commands over the mainbaord.

So I do not see any errors but I get the message “step_dir_active = False (bool)”
How do I get this activated?

Blockquote
In [51]: dump_errors(odrv0)
axis0
axis: no error
motor: no error
encoder: no error
controller: no error
axis1
axis: no error
motor: no error
encoder: no error
controller: no error

Blockquote
In [52]: odrv0
Out[52]:
vbus_voltage = 24.124805450439453 (float)
serial_number = 334E314D3536 (int)
hw_version_major = 3 (int)
hw_version_minor = 6 (int)
hw_version_variant = 56 (int)
fw_version_major = 0 (int)
fw_version_minor = 4 (int)
fw_version_revision = 10 (int)
fw_version_unreleased = 0 (int)
user_config_loaded = True (bool)
brake_resistor_armed = True (bool)
system_stats:
uptime = 668701 (int)
min_heap_space = 4216 (int)
min_stack_space_axis0 = 7788 (int)
min_stack_space_axis1 = 7868 (int)
min_stack_space_comms = 12956 (int)
min_stack_space_usb = 3292 (int)
min_stack_space_uart = 3932 (int)
min_stack_space_usb_irq = 1796 (int)
min_stack_space_startup = 612 (int)
usb: …
i2c: …
config:
brake_resistance = 0.029999999329447746 (float)
enable_uart = False (bool)
enable_i2c_instead_of_can = False (bool)
enable_ascii_protocol_on_usb = True (bool)
dc_bus_undervoltage_trip_level = 8.0 (float)
dc_bus_overvoltage_trip_level = 59.92000198364258 (float)
gpio1_pwm_mapping: …
gpio2_pwm_mapping: …
gpio3_pwm_mapping: …
gpio4_pwm_mapping: …
gpio3_analog_mapping: …
gpio4_analog_mapping: …
axis0:
error = 0x0000 (int)
step_dir_active = False (bool) <–How do I get this activated?
current_state = 1 (int)
requested_state = 0 (int)
loop_counter = 5337519 (int)
lockin_state = 0 (int)
config: …
motor: …
controller: …
encoder: …
sensorless_estimator: …
trap_traj: …
watchdog_feed()
axis1:
error = 0x0000 (int)
step_dir_active = False (bool)
current_state = 1 (int)
requested_state = 0 (int)
loop_counter = 5338259 (int)
lockin_state = 0 (int)
config: …
motor: …
controller: …
encoder: …
sensorless_estimator: …
trap_traj: …
watchdog_feed()
can:
node_id = 0 (int)
TxMailboxCompleteCallbackCnt = 0 (int)
TxMailboxAbortCallbackCnt = 0 (int)
received_msg_cnt = 0 (int)
received_ack = 0 (int)
unexpected_errors = 0 (int)
unhandled_messages = 0 (int)
test_property = 0 (int)
test_function(delta: int)
get_oscilloscope_val(index: int)
get_adc_voltage(gpio: int)
save_configuration()
erase_configuration()
reboot()
enter_dfu_mode()

BlockquoteIn
[53]: odrv0.axis0
Out[53]:
error = 0x0000 (int)
step_dir_active = False (bool) <-- How do I get this activated
current_state = 1 (int)
requested_state = 0 (int)
loop_counter = 5686434 (int)
lockin_state = 0 (int)
config:
startup_motor_calibration = False (bool)
startup_encoder_index_search = True (bool)
startup_encoder_offset_calibration = False (bool)
startup_closed_loop_control = True (bool)
startup_sensorless_control = False (bool)
enable_step_dir = True (bool)
counts_per_step = 2.0 (float)
watchdog_timeout = 0.0 (float)
step_gpio_pin = 1 (int)
dir_gpio_pin = 2 (int)
lockin: …
motor:
error = 0x0000 (int)
armed_state = 0 (int)
is_calibrated = True (bool)
current_meas_phB = 0.19182288646697998 (float)
current_meas_phC = -0.23333871364593506 (float)
DC_calib_phB = -0.6752362847328186 (float)
DC_calib_phC = -1.1765987873077393 (float)
phase_current_rev_gain = 0.02500000037252903 (float)
thermal_current_lim = 13.502291679382324 (float)
get_inverter_temp()
current_control: …
gate_driver: …
timing_log: …
config: …
controller:
error = 0x0000 (int)
pos_setpoint = 171792.234375 (float)
vel_setpoint = 10000.0 (float)
vel_integrator_current = 0.3760688006877899 (float)
current_setpoint = 0.0 (float)
vel_ramp_target = 0.0 (float)
vel_ramp_enable = False (bool)
config: …
set_pos_setpoint(pos_setpoint: float, vel_feed_forward: float, current_feed_forward: float)
set_vel_setpoint(vel_setpoint: float, current_feed_forward: float)
set_current_setpoint(current_setpoint: float)
move_to_pos(pos_setpoint: float)
move_incremental(displacement: float, from_goal_point: bool)
start_anticogging_calibration()
encoder:
error = 0x0000 (int)
is_ready = True (bool)
index_found = True (bool)
shadow_count = 288528 (int)
count_in_cpr = 1808 (int)
interpolation = 0.5 (float)
phase = 1.5747861862182617 (float)
pos_estimate = 288528.03125 (float)
pos_cpr = 1808.2431640625 (float)
hall_state = 0 (int)
vel_estimate = 0.0 (float)
calib_scan_response = 0.0 (float)
config: …
set_linear_count(count: int)
sensorless_estimator:
error = 0x0000 (int)
phase = -0.3478332757949829 (float)
pll_pos = -0.34887126088142395 (float)
vel_estimate = -0.24448880553245544 (float)
config: …
trap_traj:
config: …
watchdog_feed()

I’m kind of a noob here but I think you can just do
odrv#.axis#.config.enable_step_dir = True
for each of the odrives and axes

@Zugende did @tuftman-0’s answer solve your problem? You should be able to enable the step/dir interface like this.

But in the Marlin firmware there is a section about encoders. Does something have to be changed here?

From what I recall, this is talking about the rotary encoder used to navigate the printer’s LCD menu, and has nothing to do with the motors.
Regardless, the step/dir interface of Marlin has no feedback, it just sends out step and direction pulses and the ODrive is taking care of the closed loop position control using the encoder’s feedback.

1 Like