DC motor current limiter

Thread Starter

topher217

Joined Oct 17, 2019
22
You can also try an inrush current thermistor on the motor.
Tried it, but forgot to add it as a method in my original post. From the thermistors I've tried, it's far too slow. As temperature increases only occur after some time at a higher current (some hundreds of milliseconds in this case) and the current peaks only last 5-10 microseconds, this also is unable to suppress them. Thats why I'm hoping to find a good mosfet solution as the switching time is typically in the nanoseconds range.
 

Thread Starter

topher217

Joined Oct 17, 2019
22
Easily programmed with a proper motor controller using proper frequency/current control loops and dynamic braking to drain excess KE. Slam-Bang reversals by just flipping a switch (going back and forth at full speed) doesn't seen a good way to enable precision balancing.
http://www.crydom.com/en/tech/newsletters/jan 2013 - solid statements - dc motor reversing.pdf
You're right, and if I were trying to create a better controller, I'd be doing it in the way you describe. But as this project is meant for reinforcement learning controllers, not your typical PID or otherwise pre-programmed controller, this is also not an option here. I have a demo software just to show how the robots work, which uses such a PID controller, which does as you say, using the derivative controller it limits the change in angular velocity so that no "slam-bangs" occur.
 

nsaspook

Joined Aug 27, 2009
13,315
If only this were possible with the motor's I've been told to use :D ... Yes, this was an argument I put forth at the beginning of the project, but for reasoning too lengthy to post here, I've been told I have to use the motors I'm currently using...which will regularly hit their max torque during the back and forth behavior needed to balance. Its wasteful for power, wears down the motors to their breaking point regularly, but it is what it is. :\

The motors in the cornell project are MASSIVE compared to the ones we're using. We're using those tiny little thumb sized chinese motors. Again, I totally agree with you that this would be ideal, but this is just another design restriction I have to work around. I'll keep trying to push this though. :)
It sounds to me you've been setup for failure unless you constrain the physical requirements and/or refine your software/hardware system to something more effective in limiting error feedback KE. Motor current limiting is fixing a symptom, not the root problem of poor motor reaction control and inadequate control system mass moving resources for your current control model.

https://www.instructables.com/Arduino-Neural-Network-Self-Balancing-Two-Wheel-Ro/
 

Thread Starter

topher217

Joined Oct 17, 2019
22
It sounds to me you've been setup for failure unless you constrain the physical requirements and/or refine your software/hardware system to something more effective in limiting error feedback KE. Motor current limiting is fixing a symptom, not the root problem of poor motor reaction control and inadequate control system mass moving resources for your current control model.

https://www.instructables.com/Arduino-Neural-Network-Self-Balancing-Two-Wheel-Ro/
I can completely see where you are coming from, but after reading through the instructable, it looks like this project would have the same problem, but the circuit simply doesn't involve battery charging or battery protection, so the author isn't running into the unwanted tripped shutdown that I am. You can hear the motors stalling in the video and see the rapid back and forth behavior of the untrained network. This exactly what happens in our robots as well. There is most certainly the same current spikes occurring, but there is no protection circuit shutting anything down.

The L293D driver the author uses has a 600mA max peak non-repetitive output current, which is quite low compared to the 3.2A or so I'm seeing. So as his driver chip is not burning out (or at least not yet! :D ) ... the most likely cause is that his robot exerts a smaller angular momentum (i.e. the mass is smaller, the height is lower, or both). By the looks alone, I'm sure both of these are true. The author also keeps the robot upright and prevents it from tilting too far from one side or the other with their hands while training (this also limits the maximum torque the motors will ever apply).

Since I cannot change the mass or height of our robot significantly, my only option to solve the problem rather than the symptom would be to use a motor with larger maximum torque, such that it could never stall under normal operation. But the problem there is that you still cannot guarantee a NN will not explore a behavior that will not result in achieving the maximum torque for a given motor.

Imagine the best case scenario:

You have a NN controlled robot that is free to change the PWM on the motors to any pulse width at any time. For a trained NN model, the NN has some idea regarding how a given PWM output will affect its future tilt angle theta. Starting the robot upright as in the video, the amount of pulse width necessary to correct for the small errors in theta not equal to 0 (assuming theta=0 is the vertical balanced position in this example) would be very small, i.e. the maximum torque of the motors would never need to be reached to keep it upright.

Now imagine the worst case scenario:
Now, you have a robot that knows nothing about how the PWM affects its vertical position. All you program is a reward function, e.g. if theta=0 get reward, else get nothing. (I know this is a poorly defined reward function, but this is intentional for this example). Also assume the robot has balancer arms so it will not fall into an unrecoverable state during training. What often happens in this case is the robot will swing back and forth as fast as it can to swing past theta=0 as many times as possible so as to get that reward as often as possible. Although this is not ideal (ideally it will be constantly getting this reward by staying upright) this is an example of a NN getting stuck at a local optima or minima, and happens quite regularly for basic NNs. Regardless of the motor size in this case, the motor will go to max angular velocity in one direction and then reverse this to max angular velocity in the other direction. Because it is trying to reach the maximum angular velocity as fast as possible, the motor will undergo max torque during these rapid changes back and forth.

Now, for a well trained NN controller, or a well tuned PID controller, you are right, this should never be an issue. The problem is that the project and platform I'm working on are being made for the sole purpose of this type of NN training. All kinds of NN will be used and tested. My job is to ensure others can create these various NN controllers without the robot shutting down regardless of what they program. Does that clarify my design requirements any better?

I could of course just remove the battery proection circuit to be the same as the instructable, but I guess you can see why I want to avoid this :D
 

nsaspook

Joined Aug 27, 2009
13,315
To me that just shows the limitations of using a full authority, no control limits NN (self-learning) controller in a balancing robot. I understand the requirement of a hardware enforced sandbox during training but it also seems realistic to include some effort to reduce the initial PWM control of the NN until somewhat sane balancing behavior.
 
Last edited:

Thread Starter

topher217

Joined Oct 17, 2019
22
To me that just shows the limitations of using a full authority, no control limits NN (self-learning) controller in a balancing robot. I understand the requirement of a hardware enforced sandbox during training but it also seems realistic to include some effort to reduce the initial PWM control of the NN until somewhat sane balancing behavior.
Thats an interesting idea, but its tough to say as limiting the PWM control during the learning phase, and then reintroducing it after learning may lead to some unexpected consequences.

I'm trying to dig deeper into the firmware on the microcontroller to see if I can't speed up the loop somehow, and also considering a 3rd microcontroller dedicated only to this. I'm also testing to see if I can't just accept the lag and use a lower current limit where I'd expect the peaks to have a much wider time frame that could potentially be caught be the existing microcontroller. I'll update after testing. Thanks for the ideas!
 

MaxHeadRoom

Joined Jul 18, 2013
28,702
I'm not quite sure I'm understanding your suggestions. The microcontroller sets the In+/- and PWM signal inputs on the motor driver, and the driver takes those inputs to "control" the motor. The idea of feedback to the microcontroller would be too slow
CNC servo's control it this way at high rate all the time.
The Picmicro has a 18F2331/4431 processor with MFM, motion feedback module, also see app note AN937.
Max.
 

nsaspook

Joined Aug 27, 2009
13,315
Thats an interesting idea, but its tough to say as limiting the PWM control during the learning phase, and then reintroducing it after learning may lead to some unexpected consequences.

I'm trying to dig deeper into the firmware on the microcontroller to see if I can't speed up the loop somehow, and also considering a 3rd microcontroller dedicated only to this. I'm also testing to see if I can't just accept the lag and use a lower current limit where I'd expect the peaks to have a much wider time frame that could potentially be caught be the existing microcontroller. I'll update after testing. Thanks for the ideas!
A single capable controller should be able to handle all the compute duties with plenty of time to spare for just about any control loop you can imagine if programming in the right language and mode for motor control.

This takes just 12 us per interrupt on a PIC32MK-MC @120MHz as it cycles a 3600 point floating point variable per rotation sinewave generation table forward or backward for three-phase AC servo motor control using several PI (the D term is not needed for many motor control applications, balancing is one area where it might be helpful if we have drive limits) control loops.
https://www.ijedr.org/papers/IJEDR1402230.pdf

C:
/*
* PWM 1ms waveform interrupt routine, timer #2
*/
void wave_gen(uint32_t status, uintptr_t context)
{
    DEBUGB0_Set();
    if (V.pwm_stop && V.pwm_update)
        return;

    V.pwm_update = true;
    if ((--m35_2.set) || (--m35_4.speed <= 0)) { // generate drive waveforms at m35_4.speed or bypass using m35_2.set
        V.TimeUsed = (uint32_t) _CP0_GET_COUNT() - V.StartTime;
        V.StartTime = (uint32_t) _CP0_GET_COUNT();
        m35_1.vel = VEL1CNT;
        m35_2.vel = VEL2CNT;
        m35_3.vel = VEL3CNT;
        /*
         * load sinewave constants from three-phase 3600 values per cycle lookup tables
         */
        phase_duty(&m35_2, m35_4.current, V.m_speed, V.pacing);
        phase_duty(&m35_3, m35_4.current, V.m_speed, V.pacing);
        phase_duty(&m35_4, m35_4.current, V.m_speed, V.pacing);
        set_motor_speed(abs(m35_2.error), pi_freq_error);
        m35_4.speed = V.motor_speed;
    }

    current_error = hb_current(u_total, false) - MPCURRENT;
    pi_current_error = lp_filter_f(UpdatePI(&current_pi, current_error), 5);
    /*
     * generate a current error drive signal
     */
    m35_4.current = MPCURRENT + (MPCURRENT - (int32_t) pi_current_error);
    /*
     * limit motor drive current
     */
    if (m35_4.current > motor_volts) {
        m35_4.current = motor_volts;
    }
    m35_4.current_prev = m35_4.current;
    /*
     * position error from motor encoder vs position setting encoder
     */
    m35_2.error = (POS3CNT * m35_3.gain) - POS2CNT;
    /*
     * generated a motor drive frequency from the position error signal
     */
    pi_freq_error = fabs(UpdatePI(&freq_pi, (double) m35_2.error));
    /*
     * limit frequency error signal
     */
    if (pi_freq_error > 1999.0) {
        pi_freq_error = 1999.0;
    }
    /*
     * check for position error dead-band
     */
    if (abs(m35_2.error) < motor_error_stop) {
        ResetPI(&freq_pi);
        m35_2.set = 3;
    } else {
        m35_2.set = false;
    }
    /*
     * motor stop/start pacing
     */
    V.pacing = velo_loop(pi_velocity_error, m35_2.set);
    /*
     * position housekeeping
     */
    if (m35_2.error > 0) {
        if (m35_2.ccw) {
            m35_2.ccw = false;
        }
        m35_2.cw = true;
    } else {
        if (m35_2.cw) {
            m35_2.cw = false;
        }
        m35_2.ccw = true;
    }
    if (m35_2.error == 0) {
        m35_2.cw = false;
        m35_2.ccw = false;
    }
    /*
     * set channel duty cycle for motor sinewave outputs at ISR time 1ms intervals
     */
    MCPWM_ChannelPrimaryDutySet(MCPWM_CH_1, m35_2.duty);
    MCPWM_ChannelPrimaryDutySet(MCPWM_CH_2, m35_2.duty);
    MCPWM_ChannelPrimaryDutySet(MCPWM_CH_3, m35_3.duty);
    MCPWM_ChannelPrimaryDutySet(MCPWM_CH_4, m35_4.duty);
    DEBUGB0_Clear();
}
Control system testing using manual QEI position controls as the system dynamically generates the required three-phase signal frequencies and current levels per motor phase line to match the desired input position.

Only 2 motor phases shown on the oscope.
 
Last edited:

Thread Starter

topher217

Joined Oct 17, 2019
22
CNC servo's control it this way at high rate all the time.
The Picmicro has a 18F2331/4431 processor with MFM, motion feedback module, also see app note AN937.
Max.
Neither link seems to work. Could you link to the actual datasheet or page (rather than a search result on digikey, these don't seem to be permanent links).

If I'm understanding correctly, I'm not disagreeing that a microcontroller can manage such a scenerio in general; I'm saying the microcontroller on our robot cannot. Adding another microcontroller is one solution, but comes with plenty of other design considerations, including the possibility that it consumes more power than just the inline resistor I proposed in Method 3 of my original post.
 

Thread Starter

topher217

Joined Oct 17, 2019
22
A single capable controller should be able to handle all the compute duties with plenty of time to spare for just about any control loop you can imagine if programming in the right language and mode for motor control.

This takes just 12 us per interrupt on a PIC32MK-MC @120MHz as it cycles a 3600 point floating point variable per rotation sinewave generation table forward or backward for three-phase AC servo motor control using several PI (the D term is not needed for many motor control applications, balancing is one area where it might be helpful if we have drive limits) control loops.
https://www.ijedr.org/papers/IJEDR1402230.pdf

C:
/*
* PWM 1ms waveform interrupt routine, timer #2
*/
void wave_gen(uint32_t status, uintptr_t context)
{
    DEBUGB0_Set();
    if (V.pwm_stop && V.pwm_update)
        return;

    V.pwm_update = true;
    if ((--m35_2.set) || (--m35_4.speed <= 0)) { // generate drive waveforms at m35_4.speed or bypass using m35_2.set
        V.TimeUsed = (uint32_t) _CP0_GET_COUNT() - V.StartTime;
        V.StartTime = (uint32_t) _CP0_GET_COUNT();
        m35_1.vel = VEL1CNT;
        m35_2.vel = VEL2CNT;
        m35_3.vel = VEL3CNT;
        /*
         * load sinewave constants from three-phase 3600 values per cycle lookup tables
         */
        phase_duty(&m35_2, m35_4.current, V.m_speed, V.pacing);
        phase_duty(&m35_3, m35_4.current, V.m_speed, V.pacing);
        phase_duty(&m35_4, m35_4.current, V.m_speed, V.pacing);
        set_motor_speed(abs(m35_2.error), pi_freq_error);
        m35_4.speed = V.motor_speed;
    }

    current_error = hb_current(u_total, false) - MPCURRENT;
    pi_current_error = lp_filter_f(UpdatePI(&current_pi, current_error), 5);
    /*
     * generate a current error drive signal
     */
    m35_4.current = MPCURRENT + (MPCURRENT - (int32_t) pi_current_error);
    /*
     * limit motor drive current
     */
    if (m35_4.current > motor_volts) {
        m35_4.current = motor_volts;
    }
    m35_4.current_prev = m35_4.current;
    /*
     * position error from motor encoder vs position setting encoder
     */
    m35_2.error = (POS3CNT * m35_3.gain) - POS2CNT;
    /*
     * generated a motor drive frequency from the position error signal
     */
    pi_freq_error = fabs(UpdatePI(&freq_pi, (double) m35_2.error));
    /*
     * limit frequency error signal
     */
    if (pi_freq_error > 1999.0) {
        pi_freq_error = 1999.0;
    }
    /*
     * check for position error dead-band
     */
    if (abs(m35_2.error) < motor_error_stop) {
        ResetPI(&freq_pi);
        m35_2.set = 3;
    } else {
        m35_2.set = false;
    }
    /*
     * motor stop/start pacing
     */
    V.pacing = velo_loop(pi_velocity_error, m35_2.set);
    /*
     * position housekeeping
     */
    if (m35_2.error > 0) {
        if (m35_2.ccw) {
            m35_2.ccw = false;
        }
        m35_2.cw = true;
    } else {
        if (m35_2.cw) {
            m35_2.cw = false;
        }
        m35_2.ccw = true;
    }
    if (m35_2.error == 0) {
        m35_2.cw = false;
        m35_2.ccw = false;
    }
    /*
     * set channel duty cycle for motor sinewave outputs at ISR time 1ms intervals
     */
    MCPWM_ChannelPrimaryDutySet(MCPWM_CH_1, m35_2.duty);
    MCPWM_ChannelPrimaryDutySet(MCPWM_CH_2, m35_2.duty);
    MCPWM_ChannelPrimaryDutySet(MCPWM_CH_3, m35_3.duty);
    MCPWM_ChannelPrimaryDutySet(MCPWM_CH_4, m35_4.duty);
    DEBUGB0_Clear();
}
Control system testing using manual QEI position controls as the system dynamically generates the required three-phase signal frequencies and current levels per motor phase line to match the desired input position.

Only 2 motor phases shown on the oscope.
Did you make the video? I'm not sure what I'm supposed to be understanding from this. What is being measured on the scope?

The microcontroller on the IOIOBoard we're using is the PIC24FJ256. I did some loop testing late last week and found for the most basic loop program (checking and setting a single IO pin status) I was getting <100 ns loop times. This also includes the time to write to the log with the timestamps, so its likely even faster without such logging. Things get a bit hairier when testing the PWM generation. I have another basic sample program that generates the PWM signal on two pins and sets the IO controlling the driver's H-bridge (i.e. setting the direction of the motor). I'm really not sure why as I didn't write the firmware, but the setting of the IO pins in this case takes several hundreds of microseconds. Worse still generating the PWM signal takes 1-3 milliseconds. I'm trying to understand the firmware better to know why the time frames jump so high for these operations.

I also tested the timeframe of the current spikes generated by the motor with a simple switching sequence (1 second 100% forward, 1 second 0%, 1 second 100% reverse, 1 second 0%). Note the current spikes would likely be even higher without the 1 second 0% pauses between reversals, but I still see the current spikes associated with in-rush current from a stopped motor to 100% motor. The rise time of the current from 0% to 100% is typically 5-10 microseconds, with ringing and settling times much longer (100-200 microseconds).

So in order to suppress the peaks I'd have to:

1.) Set initial PWM (e.g. 100%)
2.) Measure current on some current sense circuit at some pin on the IOIO Board
3.) Compare current measurement to some predefined limits to determine adjusted PWM.
4.) Determine new PWM that would result in acceptable current during next measurement.
5.) Set new PWM

all well within the rise time of the current spike (<5 microseconds). I don't see this as possible with the current loop times I'm measuring (1-3 milliseconds). Also I'd likely have to add additional steps as step 4 assumes I know how to properly adjust the PWM to limit the current when in fact I'd likely have to have at least two measurement points in order to determine the slope of the current so as to implement a derivative type controller to prevent it from shooting too far too fast. So I'd likely need two loops within <5 microseconds which seems even more impossible.
 

nsaspook

Joined Aug 27, 2009
13,315
The video is just a example of what's possible with controllers designed for motor control.

Right, the Slam-Bang spike suppression can't be handled by the normal PWM/PID loop because that likely runs on a timer ISR and updates, like you've found, in the order of milliseconds. Far too slow and it shouldn't normally be expected to handle such events with well engineered systems and software. Over-current limiting, EMO, hard limit switching are exceptions usually handled in its own exception ISR that executes immediately outside of the normal motor control loop when triggered by the exception to execute a predefined (or if you have a 32-bit controller maybe computed) set of routines/code to handle the condition before returning to normal motor control if that is possible after the exception. External interrupts, comparators, a fast computational ADC with hardware result triggers are all ways to handle these types of events.
 

Thread Starter

topher217

Joined Oct 17, 2019
22
External interrupts, comparators, a fast computational ADC with hardware result triggers are all ways to handle these types of events.
Do you have any particular example circuits showing these ideas in use? There are plenty of examples in cookbook I mentioned in Method 4 of my original post about obtaining some form of a current sensing circuit, but the methods of how to use this to limit the current are missing. I can understand how to do it if I feed back this current measurement to an ADC on a microcontroller, but as discussed, this is too slow for what I'm dealing with.
 

nsaspook

Joined Aug 27, 2009
13,315
Your PIC24 has several analog comparator modules that can be configured to generate an interrupt when an input exceeds a voltage reference threshold.

Some models (dsPIC33) have the high-speed comparator and other POWER control related goodies.
https://docs.rs-online.com/9ff1/0900766b81590bcd.pdf

http://ww1.microchip.com/downloads/en/DeviceDoc/39710b.pdf
The High-Speed Analog Comparator module provides a way to monitor voltage, current and other critical signals in a power conversion application that may be too fast for the CPU and ADC to capture. There are a total of 4 comparator modules, 1 of which is controlled by the Master core and the remaining 3 by the Slave core. The comparator module can be used to implement Peak Current mode control, Critical Conduction mode and hysteretic control-based power supplies.
...
The comparator provides a high-speed operation with a typical delay of 15 ns. The output of the comparator can be processed by pulse stretcher and digital filter blocks, which prevent comparator response to unintended fast transient signals.
Your basic circuit might look like this.
OverCurrent+protection.jpg

Your current sensing circuit sends the (filtered to your requirements) voltage to the comparator analog input. Over X voltage threshold flags an comparator interrupt, during that interrupt you might be able to look for other info like speed if a rotary encoder is present for velocity information on how to handle the over-current signal.

https://www.electronicdesign.com/po...amage-via-fast-accurate-overcurrent-detection

https://www.ti.com/lit/ds/sbos613b/sbos613b.pdf
A INA300 integrated over-current detector could connect the ALERT signal to an external interrupt pin on the PIC controller for fast response to over-current events.
 
Top