Brushed Motor Control?

On another note; what about 3 phase motors with DC exited rotors? Given constant excitation current, these are almost identical to a BLDC, as far as the 3-phase circuitry is concerned, I think? That said, making the most of the controllable rotor excitation is kindof the point of such motors… but if there is an unused outputpin on the odrive controller to control the rotor circuitry, again the rest is should be a software problem.

@madcowswe This has been working well for me in voltage control mode, but I’d like to get current control working. Previously you said:

I’m trying to map this on to the actual function. I see the code section for the clark and park transforms, but nothing called ‘Imotor’. Could you share more details on how to do current control?

For convenience, here is a direct link to the FOC_Current function:

I mostly just need current control for my brushed motor application, though if its reasonable I have another application where I’m interested in separate current control per channel, so any insight there would also be nice.

Thanks!

You basically just do a single-phase version of the q axis control, starting from //current error

I would just write a new function, personally

Thanks @Wetmelon and @madcowswe in the discord chat the other day. After we talked it finally dawned on me that I just needed to find which variables provide measured current, and then I just make a normal current controller based on that feedback. All the magic in FOC_Current apparently distracted me from realizing I just didn’t know where measured current comes from.

1 Like

Okay! Brushed motor current control is working great on my branch. I can use the trapezoidal position control which is great. Some of the command implementations are a bit hacky, but if anyone (@Wetmelon?) wants to merge this somewhere I can clean up anything. I wasn’t sure whether I should add new command values to control some of the things or just hijack some existing ones.

But the Odrive is great for brushed motor control. I still need precise feedback and some of the other motors on our robot are brushless, so sticking with one controller is great. Some day I may want to control three brushed motors from one Odrive but that’s code for another time!

For completeness I’ve uploaded my config and startup script as well.

Hello! I tried your firmware, but have some issues.
I connect phase B and C to motor and all working fine, but at low currents. p gains on current and pos are >50, but still only 1.5A at 24V supply. Duty is about 10-15% on it. How to increase current?

sorry, problem is in vel.gain… now works fine! Thanks!

2 Likes

Hey that’s great to hear! If you run in to any other issues please let me know. :slight_smile:

@tlalexander I just tried this and I’m having trouble with the build. It looks like there are various fixes for a new compiler toolchain in the latest odrive master branch that I tried to port over, and then my attempt to merge your ‘master’ branch to odrive master also failed.

Any ideas? Could you take a look at updating your version and submitting as a pull request to get integrated into the main odrive release?

I want to be able to use the same controller with both brushed and brushless motors, and the odrive seems better than most of the brush controllers I’ve seen anyway. (For the curious, the application is https://www.7el.us/shop/solar-electric-tractor-48#attr= )

1 Like

Cool robot!

I will take a look at updating my code maybe in the next six months, but I’m not sure when I will have the time.

For now, if you’re familiar with Docker you may want to building the code in an Ubuntu 18.04 container to see if that works. A virtual machine would work too and may be more intuitive.

I can also add a hex file of the build to the git repo if that would help you?

1 Like

@tlalexander yes a hex file would be helpful, along with any sort of quickstart you might have.

In the meantime, the reason I went with an open source controller is in case @madcowswe can comment on if I updated this right… https://github.com/odriverobotics/ODrive/pull/544

Alright, I got my toolchain issues sorted out on my estop branch, and now I get this (I have to flash with an stlink, DFU does not work for unknown reasons)

In [7]: dump_errors(odrv0, True)
axis0
  axis: Error(s):
    AXIS_ERROR_MOTOR_FAILED
  motor: Error(s):
    MOTOR_ERROR_NOT_IMPLEMENTED_MOTOR_TYPE
  fet_thermistor: no error
  motor_thermistor: no error
  encoder: no error
  controller: no error
axis1
  axis: Error(s):
    AXIS_ERROR_MOTOR_FAILED
  motor: Error(s):
    MOTOR_ERROR_NOT_IMPLEMENTED_MOTOR_TYPE
  fet_thermistor: no error
  motor_thermistor: no error
  encoder: no error
  controller: no error

In [8]: odrv0.axis0.motor.config
Out[8]: 
pre_calibrated = False (bool)
pole_pairs = 7 (int)
calibration_current = 10.0 (float)
resistance_calib_max_voltage = 2.0 (float)
phase_inductance = 0.0 (float)
phase_resistance = 0.0 (float)
torque_constant = 0.03999999910593033 (float)
direction = 0 (int)
motor_type = 5 (int)
current_lim = 10.0 (float)
current_lim_margin = 8.0 (float)
torque_lim = inf (float)
inverter_temp_limit_lower = 100.0 (float)
inverter_temp_limit_upper = 120.0 (float)
requested_current_range = 60.0 (float)
current_control_bandwidth = 1000.0 (float)
acim_slip_velocity = 14.706000328063965 (float)
acim_gain_min_flux = 10.0 (float)
acim_autoflux_min_Id = 10.0 (float)
acim_autoflux_enable = False (bool)
acim_autoflux_attack_gain = 10.0 (float)
acim_autoflux_decay_gain = 1.0 (float)

Hey that’s great! I should still push a HEX file for future users.

But actually that means its working. I didn’t want to add a new error as then I couldn’t use stock odrivetool (I think?) so I used MOTOR_ERROR_NOT_IMPLEMENTED_MOTOR_TYPE for the e-stop as this code was mostly for internal use.

You’ve got to put 5v (or is it 3.3v?) on I think GPIO8 and then clear errors. The MOTOR_ERROR_NOT_IMPLEMENTED_MOTOR_TYPE should go away!

This is the kind of thing I’d pay to have supported and documented in the mainline release, with a specific error message for ESTOP.

Looks like I’ll try the non-estop version for now :stuck_out_tongue:

Yes definitely documentation would be good. The point of the e-stop feature is to stop the motors if the circuit is not active. I chose GPIO8 for that. So if you want an e-stop function this one works for that! The point is that throwing an error disables the motors, I just picked an existing error instead of adding a new one. You can run a little jumper wire across the header from 3.3v to GPIO8 if you want to use the branch. Then add an e-stop at some point to break the circuit if you want to immediately stop the system. When you reset the e-stop, just clear errors* and it all works as normal.

* dump_errors(odrv0,True)

I went back to the previous commit before the estop and I’m trying to work back to proving basic functionality. At this point all I need is to replace an existing RC-control ‘tank mode’ H-bridge motor controller with an odrive, and for testing I just need to command a voltage, or current setpoint and have the controller pick the right direction (polarity) and PWM timings.

There is no encoder, so odrive_brushed.py seems like substantial overkill.

One of the things I really liked about the motor controller I’ve got now is it has LED indicators and pushbutton switches so you can validate wiring and mechanical without having to have the full control system up and running.

It would be nice to have some sort of direct joystick interface as a backup as well, ideally something like https://www.apem.com/us/jc-series-460.html but there are no analog inputs. I do see sparkfun has some i2c thumb joysticks.

@tlalexander
I just tried to control brushed motor by position feedback.
I a new function for brushed motor current feedback.

bool Motor::enqueue_brushed_voltage_timings(float v_q) {

// Clamp voltage_setpoint to just shy of vbus voltage.

//v_q limtter

if((-vbus_voltage * BRUSHED_VOLTAGE_MAX_RATIO) > v_q)

  v_q = -vbus_voltage * BRUSHED_VOLTAGE_MAX_RATIO;

if((vbus_voltage * BRUSHED_VOLTAGE_MAX_RATIO) < v_q)

  v_q = vbus_voltage * BRUSHED_VOLTAGE_MAX_RATIO;

float drive_ratio = v_q/vbus_voltage;

float tA, tB, tC;

tA = 0.5f;

tB = (drive_ratio + 1.0f)/2.0f;

tC = 1.0f - tB;

next_timings_[0] = (uint16_t)(tA * (float)TIM_1_8_PERIOD_CLOCKS);

next_timings_[1] = (uint16_t)(tB * (float)TIM_1_8_PERIOD_CLOCKS);

next_timings_[2] = (uint16_t)(tC * (float)TIM_1_8_PERIOD_CLOCKS);

next_timings_valid_ = true;

return true;

}

But, AXIS_STATE_CLOSED_LOOP_CONTROL, it doesN’t works.

Please advice for me if you have good idea.

If anyone sees this in the future please see my reply on the other thread here:

@tlalexander
Hello, thank you for excellent work! I am trying to use your code to control my Brushed DC motor(Nominal Voltage:24V Current:3A) with TLE5012B ABI Incremental encoder connected to axis1.

I updated my firmware using your github HEX file(v3.6-56V) and my odrivetool version is 0.5.2.
I modified your config.json a little bit for the current limit and keep the main part such as
motor->config->“motor_type”: 3,
controller->config->“control_mode”:0,
encoder->config->“mode”:0
and run your odrive_brushed.py to line 58
odrv0.axis1.controller.current_setpoint = 0.5 #modify 3 to 0.5 A

It did run for about 2~3 seconds, but then stopped. dump_error(odrv0) shown the errors as below.
axis1
axis: Error(s):
UNKNOWN ERROR: 0x00000040
motor: Error(s):
MOTOR_ERROR_DRV_FAULT
sensorless_estimator: no error
encoder: no error
controller: no error

I wonder if you could give me some advice? Is it necessary/possible to calibrate ABZ encoder first?
Many thanks!