DC Motor Control

This week I worked on controlling a DC motor using the pulse width modulation (PWM) in the dsPIC30F4011 to adjust the speed of the motor. The code I started with would drive the motor at 75% duty cycle for two seconds then 25% for two seconds and repeat, this code can be found here. The DC motor pulls a lot more current than the PIC can supply so I needed to use a driver chip (SN754410NE), This chip would amplify the current enough to drive the motor. On this chip we can apply the PWM to the enable pin on either side giving us the ability to switch the chip on and off very quickly and this turns on and off the motors, this switching will then change the speed. If the enable pins were left alone the motor would just run at full speed.

After I got the basic circuit working I wanted to make the motor speed change dependent on a sensor of some sort so I decided to use the HC-SRF04 ultra sonic range sensor. Using the sensor I would detect an object in front of the sensor and adjust the speed proportionally and if the object got within a certain distance the motor would stop. The circuit I used is below:

range motor.png

The range sensor works by sending out a sonar and waits and see how long it takes for the wave to come back. The distance is proportional to the pulse width of the echo using the formula (pulse width in us)/58. In the code I tried to have a counter that would increment every microsecond but because of the PICs scan cycle being slowed down by every instruction this wasn’t giving back right values. So to get around this I measured the actual pulse width of the echo using the PICKIT2’s logic tool and compared it to the value the PIC was getting. An example of the pulse width from the echo is like this:
pulse width
This shows a 570us pulse meaning an object was 9.83cm away. So taking a few values from the logic tool and the UART I plotted them on a graph.
Echo Graph
From the graph I got the following formula: ActualPW = ReadPW * 6.844 – 35.263. Then from this I just needed to divide by 58 to get the distance. With that sorted I could finish the code.

//
// dsPIC30F4011 example - Control speed of DC motor using range finder
// The motor adjusts its speed proportional to the distance of an
// object infront of it, if the object is within a certain distance
// the motor stops
// Written by Ronan Byrne, Adapted from a code Written by Ted Burke Last updated 09-10-2015
//

#include <xc.h>
#include <libpic30.h>
#include <stdio.h>

// Configuration settings
_FOSC(CSW_FSCM_OFF & FRC_PLL16); // Fosc=16x7.5MHz, i.e. 30 MIPS
_FWDT(WDT_OFF);                  // Watchdog timer off
_FBORPOR(MCLR_DIS);              // Disable reset pin

float distance();
float d;
float S;
float t;

int main(void)
{
    // Make RD0 and RD1 digital outputs and RD2 and digital input
    TRISD = 0b100;

    // Configure PWM
    // PWM period = PTPER * prescale * Tcy = 9470 * 64 * 33.33ns = 20ms
    _PMOD1 = 0;   // PWM channel 1 mode: 0 for complementary, 1 for independent
    _PEN1H = 1;   // PWM1H pin enable: 1 to enable, 0 to disable
    _PTCKPS = 3;  // PWM prescaler setting: 0=1:1, 1=1:4, 2=1:16, 3=1:64
    PTPER = 9470; // Set PWM time base period to 20ms (15-bit value)
    PDC1 = 0;     // 0% duty cycle on channel 1 (16-bit value)
    _PTEN = 1;    // Enable PWM time base to start generating pulses

    // Setup UART
    U1BRG = 48;            // 38400 baud @ 30 MIPS
    U1MODEbits.UARTEN = 1; // Enable UART

    // Control motor
    while(1)
    {
        d = distance();     // Call the distance fuction to give us d
        printf("Distance = %f \n", d); // Print the value of d to the UART
        if(d > 100)         // Clamp the distance at 100cm to get full range of PWM
        {
            d = 100;
        }
        else if(d < 10) // Stop if an object is within 10cm
        {
            d = 0;
        }

        S = d / 100.0;      // Calculate the speed
        printf("Speed = %f \n", S); //Print value for speed to UART

        PDC1 = S * 2 * PTPER; // 0 - 100% duty cycle
        _LATD0 = 1;           // Turn on motor
    }
    return 0;
}

float distance()
{
    // Send 10us trigger pulse
    _LATD1 = 1 ;
    __delay32(300);
    _LATD1 = 0;

    // Wait for start of echo pulse
    while(_RD2 ==  0)
    {
        // nothing here
    }

    // Measure how long the pulse is
    float t = 0.0;
    while(_RD2 == 1)
    {
        __delay32(30); // Delay for 1us
        t = t + 1.0;   // Increment time
    }

    // This formula was found by comparing the real pulse width
    // of the echo to what the PIC was reading
    t = (t * 6.844) - 35.263; // This is very close to the real pulse width
    float d = 0.0;
    d = t / 58.0;             // Formula for distance is us/58

    // Leave 100ms for any ultrasound reflections to die away
    __delay32(3000000);

    // Pass the measured distance back to the calling function
    return d;
}

The code used for the range sensor was adapted from here. The sensor is very accurate at short distances the values are a few millimeters out but as the range increases this inaccuracy increases but not by too much, it also occasionally sees 0 but only for one cycle so it doesn’t effect the speed. A video shown how it works is shown below:

In the video you can see the speed of the motor changing depending on how far my hand is away from the sensor and that the motor stops at 10cm. This code could be improved to slow down and stop the motor depending on the speed an object getting closer to sensor. A real life example of this would be a car driving too fast towards a red light with a car stopped at the lights, if the driver didn’t slowed down fast enough the controller would kick in.

3 thoughts on “DC Motor Control

  1. Excellent post Ronan! I particularly like how you did that experiment to calibrate the distance readings you were getting. What did you use to draw that circuit diagram by the way? It looks great. Excellent work overall.

    Ted

    Like

    • Thanks Ted, the software I used was Circuit Wizard, its great for making quick circuits and testing them but I don’t think it is the easiest to read off of when the wires start crossing over

      Like

Leave a comment