Can I control a DC motor with PWM?

Post here about your Arduino projects, get help - for Adafruit customers!

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
Locked
User avatar
Qiking
 
Posts: 13
Joined: Sat Nov 22, 2014 11:38 am

Can I control a DC motor with PWM?

Post by Qiking »

I want to control an OWI robotic arm using Maya (an animation creating program) like this http://vimeo.com/7606372 (skip towards the end) The method behind it is that it uses pulse width modulation while python sends rotational signals from Maya to the arduino. So, I have stacked an adafruit motor shield on top of the arduino and set up the digital pins. The problem is that the motor in the video is a servo, while the robotic arm runs on DC motors. So is it even possible to control a DC motor with PWM? I'm not sure if it's a hardware problem or a software problem.

Here is my code and please tell me if there are any problems with it. Thanks!

Code: Select all

int pinArray[4] = {6, 9, 10, 11}; // analog pins for the servos
int minPulse = 600;             // minimum servo position
int maxPulse = 2400;            // maximum servo position
int refreshTime =  10;          // time (ms) between pulses (50Hz)

/** The Arduino will calculate these values for you **/
int computePulse = 1;
int lastPositionPacket;
int i;              // iterator
int servoPin;       // control pin for current servo
int userInput[3];   // raw input from serial buffer, 3 bytes
int pulseWidth;     // servo pulse width
int servoPosition;  // commanded servo position, 0-180 degrees
int pulseRange;     // maxPulse - minPulse
int centerServo;    // servo starting point
long lastPulse = 0; // recorded time (ms) of the last pulse
int servo;          // which servo to pulse? 1-4
int servo1[2];      // servo #1 array{pin, pulsewidth}
int servo2[2];      // servo #2 array{pin, pulsewidth}
int servo3[2];      // servo #3 array{pin, pulsewidth}
int servo4[2];      // servo #4 array{pin, pulsewidth}
int pin;            // digital pin for pulse() function
int puls;           // pulsewidth for pulse() function
int startbyte;      // start byte, begin reading input

void setup() {
  // loop through all 4 servo pins
  // and set them as OUTPUT
  // LED connected to digital pin 13
  for (i=0;i<4;i++) {
    pinMode(pinArray[i], OUTPUT);
}  
  // servo starting point (center)
  pulseRange  = maxPulse - minPulse;
  centerServo = maxPulse - ((pulseRange)/2);
  pulseWidth  = centerServo;
  // map pins to servos
  servo1[0] = pinArray[3];  // servo #1 is pin 11
  servo2[0] = pinArray[2];  // servo #2 is pin 10
  servo3[0] = pinArray[1];  // servo #3 is pin 9
  servo4[0] = pinArray[0];  // servo #4 is pin 6
  // center all servos
  servo1[1] = pulseWidth;
  servo2[1] = pulseWidth;
  servo3[1] = pulseWidth;
  servo4[1] = pulseWidth;
  // open serial connection
  Serial.begin(9600);
}

void loop() {
  // wait for serial input (min 3 bytes in buffer)
  if (Serial.available() > 2) {
    //read the first byte
    startbyte = Serial.read();
    // if it's really the startbyte (255)
    if (startbyte == 255) {
      // then get the next two bytes
      for (i=0;i<2;i++) {
        userInput[i] = Serial.read();
      }
      // first byte = servo to move?
      servo = userInput[0];
      // second byte = which position?
      servoPosition = userInput[1];
      // packet check
      if (servoPosition == 255) { servo = 255; }
      // positonChangeCheck
      
      // compute pulseWidth from servoPosition
      pulseWidth = minPulse + (servoPosition * (pulseRange/180));
      // stop servo pulse at min and max
      if (pulseWidth > maxPulse) { pulseWidth = maxPulse; }
      if (pulseWidth < minPulse) { pulseWidth = minPulse; }
      
      // assign new pulsewidth to appropriate servo
      switch (servo) {
        case 1:
          servo1[1] = pulseWidth;
    
          break;
        case 2:
          servo2[1] = pulseWidth;
          break;
        case 3:
          servo3[1] = pulseWidth;
          break;
        case 4:
          servo4[1] = pulseWidth;
          break;
      }
    }
  }
  // pulse each servo
  if (millis() - lastPulse >= refreshTime) {
      pulse(servo1[0], servo1[1]);
      pulse(servo2[0], servo2[1]);
      pulse(servo3[0], servo3[1]);
      pulse(servo4[0], servo4[1]);
      // save the time of the last pulse
      lastPulse = millis();
}
}

void pulse(int pin, int puls) {
    digitalWrite(pin, HIGH); // start the pulse
    delayMicroseconds(puls); // pulse width
    digitalWrite(pin, LOW);  // stop the pulse
}

User avatar
adafruit_support_mike
 
Posts: 67485
Joined: Thu Feb 11, 2010 2:51 pm

Re: Can I control a DC motor with PWM?

Post by adafruit_support_mike »

Yes, you can control the speed of a motor with PWM, and you can control direction with an H-bridge (which exists on the Motor Shield).

The Motor Shield library has functions to run DC motors forward and backwards, and one to set the speed with PWM. The product page for the Motor Shield has links to several projects that use DC motors, but the best place to start is with the basic tutorial:

https://learn.adafruit.com/adafruit-mot ... or-arduino

User avatar
adafruit_support_bill
 
Posts: 88141
Joined: Sat Feb 07, 2009 10:11 am

Re: Can I control a DC motor with PWM?

Post by adafruit_support_bill »

One problem is that PWM control of a DC motor is not the same as PWM control of a Servo.

With a servo motor, you can control the exact position within a range of 0-180 degrees. This is possible because servo motors have feedback.
https://learn.adafruit.com/adafruit-mot ... /rc-servos

A plain DC motor has no feedback, so the only thing you can control is the speed and directions. You can't control the position without position feedback.
https://learn.adafruit.com/adafruit-mot ... or-control

This project show how to add position feedback to the OWI arm: http://www.instructables.com/id/Intro-a ... he-motors/

User avatar
Qiking
 
Posts: 13
Joined: Sat Nov 22, 2014 11:38 am

Re: Can I control a DC motor with PWM?

Post by Qiking »

Thank you so much for your help! I have already added the potentiometers to the robot from a previous project. So how would I be able to control the position of the motor? Is the transistor, diode, and resistor necessary? Also, what is the function that sets the speed of the motor with PWM?

User avatar
adafruit_support_bill
 
Posts: 88141
Joined: Sat Feb 07, 2009 10:11 am

Re: Can I control a DC motor with PWM?

Post by adafruit_support_bill »

I have already added the potentiometers to the robot from a previous project. So how would I be able to control the position of the motor?
You will need to monitor the pot outputs using the Arduino analog pins (note that A4 and A5 are not available when using the motor shield). You will need to calibrate each joint by determining the range of pot output over the range of motion for each joint.
So how would I be able to control the position of the motor?
Simply put, you run the motor until the pot output matches the value for the desired position. If the value is to high, you run in one direction. If the value is too low, you run in the other direction. There are more sophisticated control algorithms that will give you smoother action, but best to get the basic feedback working first, then refine the code from there.
Is the transistor, diode, and resistor necessary?
If you are using the motor shield or an L293D H-bridge chip, these components are already built in.
Also, what is the function that sets the speed of the motor with PWM?
Using the motor shield, it is motor->setSpeed(); If you are using an H-bridge, you would call analogWrite() on the PWM pin wired to the enable pin of the bridge.

User avatar
Qiking
 
Posts: 13
Joined: Sat Nov 22, 2014 11:38 am

Re: Can I control a DC motor with PWM?

Post by Qiking »

Thank you! However, can I still use Maya to control the position of the robot or will I have to purely rely on the code and analog readings?

User avatar
adafruit_support_bill
 
Posts: 88141
Joined: Sat Feb 07, 2009 10:11 am

Re: Can I control a DC motor with PWM?

Post by adafruit_support_bill »

I'm not famliar with Maya and how it communicates with the Arduino. In theory, it should be possible to write code to mimic the behavior of the Arduino Servo library, but I don't know if that is what Maya uses.

User avatar
Qiking
 
Posts: 13
Joined: Sat Nov 22, 2014 11:38 am

Re: Can I control a DC motor with PWM?

Post by Qiking »

Alright, thank you for your help! I'll try to work on the code for Maya communication.

User avatar
Qiking
 
Posts: 13
Joined: Sat Nov 22, 2014 11:38 am

Re: Can I control a DC motor with PWM?

Post by Qiking »

Actually, I have a few other questions. Sorry for the inconvenience! How would I wire up the motor? I currently have one wire attached to the ground and one attached to a digital pin. So how would I be able to use the motor shield's library if the wires aren't connected to the terminals? Also, how does analogWrite() work? Does it return an integer that I can set as my motor speed?

User avatar
adafruit_support_bill
 
Posts: 88141
Joined: Sat Feb 07, 2009 10:11 am

Re: Can I control a DC motor with PWM?

Post by adafruit_support_bill »

How would I wire up the motor? I currently have one wire attached to the ground and one attached to a digital pin.
You can't control a motor with a digital pin alone. It cannot supply enough current, and it can't reverse the current to reverse the motor. You need an H-bridge - either an L293D chip, or the ones on the motor shield.
So how would I be able to use the motor shield's library if the wires aren't connected to the terminals?
To use the motor shield library, you need to use the motor shield. The tutorial explains how: https://learn.adafruit.com/adafruit-mot ... or-arduino
Also, how does analogWrite() work? Does it return an integer that I can set as my motor speed?
AnalogWrite accepts a value between 0 and 255. This controls the duty cycle of the PWM output between 0 and 100%. http://arduino.cc/en/Reference/analogWrite

User avatar
Qiking
 
Posts: 13
Joined: Sat Nov 22, 2014 11:38 am

Re: Can I control a DC motor with PWM?

Post by Qiking »

Then where would I attach the motor to the motor shield? Could you send me a picture of it? Also, does getmotor() still work if the motor isn't attached to the terminal block?

User avatar
adafruit_support_bill
 
Posts: 88141
Joined: Sat Feb 07, 2009 10:11 am

Re: Can I control a DC motor with PWM?

Post by adafruit_support_bill »

the tutorial explains how to use the shield:

https://learn.adafruit.com/adafruit-mot ... o/overview

User avatar
Qiking
 
Posts: 13
Joined: Sat Nov 22, 2014 11:38 am

Re: Can I control a DC motor with PWM?

Post by Qiking »

How would the motors receive the signals from the digital pins? If I put both wires into the terminal block, there will be no place for me to put the digital pin.

User avatar
adafruit_support_bill
 
Posts: 88141
Joined: Sat Feb 07, 2009 10:11 am

Re: Can I control a DC motor with PWM?

Post by adafruit_support_bill »

What digital pin are you talking about? The Arduino communicates with the motor shield via the I2C bus (pins A4 and A5). The motor shield controls the motors via the 2 H-bridge chips on the board. The motors are connected to the H-bridge outputs via the terminal blocks. These are not digital pins.

Locked
Please be positive and constructive with your questions and comments.

Return to “Arduino”