does braking really work?

been working on adding an encoder to a model railroad turntable to control position and looking at approaches for controlling motor speed to stop close to the desired position.

considering a calibration sweep that measures distance traveled when a motor is stopped, braked and reversed.

an isr is used to process encoder events. it updates position, captured timestamps and the changes in timestamps (dt ~= speed).

the calibration code has three options: off, braking and reversed. for each, it turns the motor on for 300 msec, then stops the motor based on the option and finally waits for the motor to stop turning when it sees two consecutive equal time stamps from the isr.

the cal code captures the position, timestamp and dt when it starts the motor, applies the option to stop the motor and when it finally stops.

for option one, it simply sets the motor speed (PWM) to zero. the following output shows the results. the 3 measurements are shown, reporting timestamp, dt from the isr and the position.

calRate reports deltas between the 2nd and 3rd measurement. calRate dt is the delta between msec values and rate is difference in pos * 100 / difference in mses.

a quick answer is dPos, 1282, the distance traveled before stopping

calStart: 1
 calTimes: 0  msec 4529, dUsec 0, pos 0
 calTimes: 1  msec 4830, dUsec 196, pos 1242
 calTimes: 2  msec 5350, dUsec 11124, pos 2524

calRate:  dPos 1282 dt 520 rate 246 coast

the 2nd option is to brake in addition to turning the motor off. my understanding of braking is to create a short path across the motor leads. i set the h-bridge to connect both motor leads to ground.

i see no difference by doing braking, dPos 1300 vs 1282 above

2
calStart: 1
 calTimes: 0  msec 7303, dUsec 11124, pos 2524
 calTimes: 1  msec 7604, dUsec 200, pos 3749
 calTimes: 2  msec 8164, dUsec 6464, pos 5049

calRate:  dPos 1300 dt 560 rate 232 brake

and to verify the measurement, as well as trying something else, the 3rd option is to reverse the motor. this requires an additional step which is to set the speed to zero just before stopping. The code does this when the isr dt (difference in timestamps) is > 1msec, 1000 usec. for an encoder with 30 vanes which is 1800 rpm.

as expected, the motor stopped much quicker, 69 steps compared to 1282 above.

3
calStart: 1
 calTimes: 0  msec 11274, dUsec 6464, pos 5049
 calTimes: 1  msec 11575, dUsec   204, pos 6286
 calTimes: 2  msec 11674, dUsec 9476, pos 6355
 calTimes: 3  msec 11594, dUsec 5900, pos 6366

calRate:  dPos 69 dt 99 rate 69 reverse

i’m surprised how effecting reversing the motor is, but don’t understand why braking didn’t have the expected affect.

what don’t i understand?

// -------------------------------------
// just rising edge of B and check A
static unsigned long isrMsec   = 0;
static unsigned long isrUsec   = 0;
static unsigned long isrDtUsec = 0;
static          long pos       = 0;
static          long pos1      = 0;
static          int  capture   = 1;

void
isr (void)
{
    byte encA   = (digitalRead(PIN_E_A));
    byte encB   = (digitalRead(PIN_E_B));

    unsigned long usec = micros ();
    unsigned long msec = millis ();
    isrDtUsec   = usec - isrUsec;
    isrUsec     = usec;
    isrMsec     = msec;

    pos1 = pos;

    if (encA)  {
        pos++;
        dir =  1;
    }
    else  {
        pos--;
        dir = -1;
    }

    enc = encB << 1 | encA;

    // -----------------------------------------------
    // initial debug
 // if (debug || (C_RUN == cond1 && C_STOP == cond))  {
    if (debug)  {
        Serial.print ("# isr: enc ");
        Serial.print (enc);
        Serial.print (", encLast ");
        Serial.print (encLast);
        Serial.print (", pos ");
        Serial.println (pos);
    }
    cond1 = cond;

    // -----------------------------------------------
    if (capture) {
     // buf [bufIdx++] = micros() & 0xFFFF;
        buf [bufIdx++] = usec & 0xFFFF;
        buf [bufIdx++] = pos;
        buf [bufIdx++] = hPwm;
        buf [bufIdx++] = enc << 4 | hDir;

        bufIdx = BUF_SIZE <= bufIdx ? 0 : bufIdx;
    }
}

// ---------------------------------------------------------
typedef enum {
    CAL_NONE,
    CAL_COAST_RUNUP,
    CAL_COAST,
    CAL_BRAKE_RUNUP,
    CAL_BRAKE,
    CAL_DONE,
    CAL_ERR,
} CalSt_t;

CalSt_t  calSt = CAL_NONE;

typedef struct {
    unsigned long  msec;
             long  pos;
             long  dt;
} CalDat_t;

const char* optStr [] = { "", " coast", " brake", " reverse", " unk", " unk" };

int calOpt = 0;

#define CalDatSize   6
CalDat_t calDat [CalDatSize]  = {};

// -------------------------------------
void
calRate (
    int         idx,
    const char* lbl)
{
    unsigned long dt   = calDat [idx+2].msec - calDat [idx+1].msec;
    unsigned long dPos = calDat [idx+2].pos  - calDat [idx+1].pos;

    Serial.print  ("calRate: ");

    Serial.print  (" dPos ");
    Serial.print  (dPos);
    Serial.print  (" dt ");
    Serial.print  (dt);
    Serial.print  (" rate ");
    Serial.print  (100 * dPos / dt);

    Serial.println (lbl);
}

// -------------------------------------
void
calTimes (
    int opt )
{
    for (int i = 0; i < CalDatSize; i++)  {
        Serial.print  (" calTimes: ");
        Serial.print  (i);

        Serial.print  ("  msec ");
        Serial.print  (calDat [i].msec);
        Serial.print  (", dUsec ");
        Serial.print  (calDat [i].dt);
        Serial.print  (", pos ");
        Serial.print  (calDat [i].pos);
        Serial.print  ("\n");
    }

    calRate (0, optStr [opt]);
 // calRate (3, " brake");
}

// -------------------------------------
unsigned long calMsec = 0;

bool
calStopped (void)
{

    delay (20);
    noInterrupts ();
    unsigned long msec = isrMsec;
    interrupts ();

    bool res = false;

    if (calMsec)  {
        res = calMsec == msec;
    }
    calMsec = msec;

    return res;
}

// -------------------------------------
void
calDatUpdate (
    int             idx,
    unsigned long   msec )
{
    calDat [idx].msec = msec;
    noInterrupts ();
    calDat [idx].pos  = pos;
    calDat [idx].dt   = isrDtUsec;
    interrupts ();
}

// -------------------------------------
void
calStart (
    CalSt_t         st,
    unsigned long   msec,
    int             idx )
{
    setDir   (D_CW);
    SetSpeed (H_MAX);
    calSt       = st;
    calMsec     = 0;
    calDatUpdate (idx, msec);

    Serial.print  ("calStart: ");
    Serial.print  (calSt);
    Serial.print  ("\n");
}

// -------------------------------------
#define MIN_RUNUP   300
CalSt_t
cal (void)
{
    unsigned long msec     = millis ();

    switch (calSt)  {
        case CAL_DONE:
        case CAL_NONE:
            calStart (CAL_COAST_RUNUP, msec, 0);
            break;

        case CAL_COAST_RUNUP:
            if (msec - calDat [0].msec > MIN_RUNUP)  {
                calDatUpdate (1, msec);
                switch (calOpt)  {
                    case 3:
#if 0
                        SetSpeed (200);
                        setDir(D_CCW);
#else
                        Reverse()
#endif
                        break;

                    case 2:
                        SetSpeed (0);
                        setDir(D_SHORT);
                        break;

                    case 1:
                        SetSpeed (0);
                        break;

                    case 0:
                    default:
                        break;
                }

                calSt = CAL_COAST;
            }
            break;

        case CAL_COAST:
            if (calStopped())  {
                calDatUpdate (2, msec);
                calTimes (calOpt);
                calSt = CAL_DONE;
                calOpt = 0;
            }
            else if (3 == calOpt)  {
                noInterrupts ();
                long dtUsec= isrDtUsec;
                interrupts ();
                if (1000 < dtUsec && 0 < hPwm)  {
                    setSpeed (0);
                    calDatUpdate (3, msec);
                }
            }
            break;

        case CAL_ERR:
            break;

        default:
            calSt = CAL_ERR;
            break;
    }

    return calSt;
}

Braking does work, so there is something wrong with your setup. You can very easily verify that if you twist the leads of a brushed DC or stepping motor together, it is much more difficult to rotate the shaft by hand.

i set the h-bridge to connect both motor leads to ground.

What H-bridge, and how?

Be very careful with rapid reversal of motor direction. A brushed DC motor will draw twice the stall current if instantaneously reversed, possibly damaging brushes and/or destroying the motor driver. So, let it brake to a stop before reversing the current flow.

If you drive the turntable through a worm gear I would expect it to stop almost instantaneously when power is disconnected from the motor (without any need for braking) because the worm drive cannot be driven by the 'table and the friction in the drive will probably be sufficient to stop the motor.

...R

thanks for the comments

What H-bridge, and how?

SN754410 configurateion on left

|500x241

If you drive the turntable through a worm gear I would expect it to stop almost instantaneously when power is disconnected from the motor (without any need for braking) because the worm drive cannot be driven by the 'table and the friction in the drive will probably be sufficient to stop the motor.

below is the mechanism tested with that took 1282 steps to stop by just setting pwm to 0. I would expect shorter stop time/distances when attached to the turntable thru large 4" gear driven by worm.

|500x279

The SN754410 is the problem. It is old, inefficient bipolar Darlington technology and cannot provide an effective “short circuit” in brake mode, as the internal voltage drop can be up to 4V.

Use a modern motor driver with MOSFET outputs instead. Pololu has an excellent collection.

thanks

This is part of another topic ! I know that picture.

Sock puppet BANNED !

gcjr: below is the mechanism tested with that took 1282 steps to stop by just setting pwm to 0.

There is nothing connected to the worm gear in your image. The behaviour will be very different when there is a load on the worm.

...R

Hi, The brake provided by shorting the motor is dependent on the motor speed, so the slower the motor goes the less regen braking you have. Shorting the motor relies on the regen current from the motor causing the brake effect, so it may be effective at high speeds, but not at low speeds. What is the max speed of your motor and what speed do you run it up to in the cal run?

Electric cars and trains do not get effective regen/short braking down to a full stop.

Tom.... :)

Its worth pointing out that braking is much more effective for larger motors than small ones. You can get a feel for how a motor performs by shorting its leads and turning it by hand - the more resistance you feel, the better it will be at braking. Large industrial motors can damage themselves it you apply 100% braking at full speed, the forces and currents are that large.

With small motors the best control is active, using a PID library, then you can arrange to always stop at the exact position given by the encoder. This is more complex though, but will be immune to changes in load, etc.

finally out of jail (banned)

i confirmed that a dead short on the small DC motors i'm playing with has an "amazing" affect. With a jumper across a motor, i can see it does not spin freely and when driving the motor I was able to quickly reduce power and short the lead with a jumper to stop the motor very quickly.

however, when i tried wiring a mosfet (mtd20n03hdl) across the output and switching it on with code when power is reduced i saw little effect. I'll guess this particular 20A mosfet may not have 0.03 Ohms resistance with 30 ma.

i'm wondering if a TC4427 H-bridge with 7 Ohms resistance will be any better.

gcjr:
however, when i tried wiring a mosfet (mtd20n03hdl) across the output and switching it on with code when power is reduced i saw little effect. I’ll guess this particular 20A mosfet may not have 0.03 Ohms resistance with 30 ma.

Across the output of what?
Can you please post a copy of your circuit, in CAD or a picture of a hand drawn circuit in jpg, png?

If it was a H-Bridge then you would not be able to bias the MOSFET correctly to turn it on.
Tom… :slight_smile:

drain and source of mosfet across the h-bridge outputs and motor terminals. more negative side of h-bridge to source and more positive side to drain

this only works with the motor driven in one direction

Hi, What do you do with the H-Bridge MOSFETs?

The gate of the brake MOSFET will be biased ON by the Arduino with respect to gnd, but if you have ALL the H-Bridge MOSFETs turned OFF, the brake MOSFET has no gnd reference for the gate, so it will not conduct.

PLEASE...Can you please post a copy of your circuit, in CAD or a picture of a hand drawn circuit in jpg, png?

Tom... :)

a output of h-bridge is 10V when running

|500x495

Hi, Thanks, almost there. Can you include power supply and pin labels please? A picture is worth a thousand words, especially for circuit description.

You didn't answer the question in my post #13.

Thanks.. Tom... :)

A & B are pins 14 and 13

but your point is if PWM is zero going to the enable, pin 9, B is floating (?) along with S and the FET may not be conducting.

so I need to set both output low, but make PWM full on

thanks

Hi,
A proper circuit diagram will help greatly.
A picture is worth a thousand words.

Have you actually assembled the hardware and actually experimented with stopping?

Tom… :slight_smile:

but if you have ALL the H-Bridge MOSFETs turned OFF, the brake MOSFET has no gnd reference for the gate, so it will not conduct.

the above made me realize that while I configured the h-bridge for braking I didn't turn on the drivers. Configuring the h-bridge for a short and setting the PWM output to max corrected my oversight.

when i do, braking causes the motor to stop in about 1/4 the distance (dPos = 350 vs 1369)

1
calStart: 1
 calTimes: 0  msec 5659, dUsec 0, pos 0
 calTimes: 1  msec 5960, dUsec 200, pos 1231
 calTimes: 2  msec 6560, dUsec 14612, pos 2600
 calTimes: 3  msec 0, dUsec 0, pos 0
 calTimes: 4  msec 0, dUsec 0, pos 0
 calTimes: 5  msec 0, dUsec 0, pos 0
calRate:  dPos 1369 dt 600 rate 228 coast
2
calStart: 1
 calTimes: 0  msec 10664, dUsec 14612, pos 2600
 calTimes: 1  msec 10966, dUsec 196, pos 3842
 calTimes: 2  msec 11205, dUsec 9280, pos 4192
 calTimes: 3  msec 0, dUsec 0, pos 0
 calTimes: 4  msec 0, dUsec 0, pos 0
 calTimes: 5  msec 0, dUsec 0, pos 0
calRate:  dPos 350 dt 239 rate 146 brake

The SN754410 is the problem. It is old, inefficient bipolar Darlington technology and cannot provide an effective "short circuit" in brake mode, as the internal voltage drop can be up to 4V.

the above gave me the impression that braking was not possible using an h-bridge with BJTs.

thanks for helping sort things out