Physics 124 Week 2 Lab

Due Tue., Jan. 19 or Wed., Jan. 20 depending on section

Motors!

In this lab, we will explore the use of various motors, which forms the basis for any motion control that a project might incorporate.

We will explore three common motor types, and learn how to control their motion. First will be servo motors, including both messing with the ATMega PWM frequency settings, as well as use of the Servo library for Arduino. Next, we'll take up use of the motor shield, so that we can more easily drive stepper motors, and lastly DC motors.

Note that generally speaking, motors take a fair bit of power/current, so the Arduino—limited to 40 mA per pin—will not be able to directly drive the steppers or DC motors. We could incorporate an H-bridge transistor arrangement to handle the drive current, and that's essentially what the motor shield does for us.

Exercise 1: Direct PWM to a Servo

Let's pretend we don't have access to a fancy library for servo motors, and we want to directly drive a servo motor with an appropriately timed PWM pattern. Looking at the HiTec "manual", we find that we want to send a PWM output at 50 Hz, with a low duty cycle: 0.9 ms (out of 20) to 2.1 ms sends the servo through its full (approx. 180°) range. This corresponds to 4.5% (11/255) to 10.5% (27/255) duty cycle.

But the PWM frequency if you do a straightforward AnalogWrite() is not at all 50 Hz, and the motor will not respond. So we have to change the frequency. Even then, we have limited choices available. On the Uno/Nano, the 6 available PWM pins are run off of three different internal timers, each of which have their own "prescaling" options for variable output speed, according to the following table (defaults bold):
PWM pins Register prescaler values frequencies (Hz)
5, 6 TCCR0B 1, 2, 3, 4, 5 62500, 7812, 977, 244, 61.0
9, 10 TCCR1B 1, 2, 3, 4, 5 31250, 3906, 488, 122, 30.5
3, 11 TCCR2B 1, 2, 3, 4, 5, 6, 7 31250, 3906, 977, 488, 244, 122, 30.5

Our closest option to 50 Hz involves the use of timer 0 (pins 5 or 6) with divider option 5 (61 Hz). This means we can cover the required 0.9 to 2.1 ms pulses with duty cycles ranging from 14/255 to 33/255, leaving only 20 possible steps by this scheme. But let's go for it!

First, PWM on the O'scope

Our first task is to write a program capable of putting out the appropriate PWM frequency and pulsewidth, then verifying it on the scope before hooking up the servo. It's actually rather straightforward in the code: in the setup() portion, insert the line:

TCCR0B = TCCR0B & 0b11111000 | 0x05;

to replace the last three bits of the TCCR0B register with 101. See the short or full version of the ATMega328 datasheet for background info. Write out analog values to pin 5 or 6 corresponding to the range of duty cycles sought by the servo, and send this into the scope to look at the waveform. Use the measurement menu to measure the frequency of the waveform, and make a table of the pulse width (also via automatic scope measurement) as a function of the analogWrite() parameter. No need to step through every possibility, but empirically find the value that delivers the closest to 0.9 ms and 2.1 ms, and perhaps one or two values in the middle. Also, while you're messing around, change the last three bits in the TCCR0B register to something other than 5 so you can verify control over the frequency as per the table above.

Now to the Servo

Having ironed out a range of settings to approximate the specified parameters of the servo, let's make a program for interactive control. You will type a single-digit number from 0 to 9 into the serial monitor, and the servo will move to the appropriate position.

The Arduino has enough juice to drive the servo, which has three leads. Black is ground, red is +5 V, and the other color (yellow, often) is the PWM control lead. Use Serial.available() and Serial.read() to check for serial input and read a single character (type char) if necessary. Since C stores a char as an 8-bit entity in memory (according to the ASCII table), it can be subtracted very easily from integers, or other characters. In particular, subtracting '0' from a character will result in the integer offset of that character from zero. A further convenience is the

map(value, input_min, input_max, output_min, output_max)

function, which can take a value between zero and nine, for instance, and map it onto a different range. An example loop to get the job done is:


void loop()
{
  if (Serial.available()){                  // check if incoming serial data
    ch = Serial.read();                     // read single character
    if (ch >='0' && ch <='9'){              // use 10 step range for demo
      level = map(ch-'0',0,9,XX,YY);        // map 0-9 onto XX-YY
      analogWrite(SERVO, level);            // send to servo
      Serial.print("Setting servo level to: ");
      Serial.println(level);
    }
  }
  delay(50);                                // interactive program, so slow
}

Don't copy and paste, but read, comprehend, adapt. You should now be able to run your servo in this interactive way. Have a TA/prof check your functionality.

To Turn In

Turn in your interactive servo control code, along with your scope measurements of PWM frequencies (more than just the ~61 Hz setting) and your table of digital values and associated pulsewidth. Also, although in this case it may seem painfully simple, make a block diagram of your hookup/setup, indicating which pins do what and how the motor is connected.

Exercise 2: Servo Library

Servos are capable of fine angular control, so it is a shame to use our PWM frequency kludge to only get twenty or so steps. The ATMega chip is certainly capable of better control. After all, it runs at 16 MHz, and therefore has 60 ns clock steps. In principle, the 1.2 ms range of pulse widths should be divisible into 20,000 units, not 20. Now, the servo itself is not likely dependable at this level, but the point is that the ATMega should be.

So folks have worked out a Servo library to exercise better control of a servo, and made it part of the standard Arduino distribution. To use it, simply include the library and instantiate a servo motor in the preamble of your code/sketch:


#include <Servo.h>				// Servo library

Servo hitec;					// hitec is handle for Servo instance

Note that hitec is just an arbitrary name to give your motor. It's essentially a variable, or handle, with type Servo. Call it whatever you want. You could also instantiate more than one with a line like: Servo serv1, serv2;, if desired. In the setup(), you need to attach the servo handle to a specific pin. This could be as simple as:

hitec.attach(9)

to attach to pin 9. Or, if you want to tune the servo so that 0° and 180° really mean what they say, you can specify a minimum pulse time, in microseconds, and a maximum pulse time as well:

hitec.attach(pin, minpulse (μs), maxpulse (μs))

The default minimum and maximum is 544 μs and 2400 μs. Taking the Hitec "manual" literally, one would expect values of 900 and 2100. From the Arduino Reference page:

Feel free to increase these endpoints until the servo no longer continues to increase its range. Note however that attempting to drive a servo past its endpoints (often indicated by a growling sound) is a high-current state, and should be avoided.

Note that timer1 is used for the servo control, so on the Uno/Nano, this disrupts normal use of the PWM functionality on these two pins. Otherwise, the servo can be attached to pins 2–13, even non-PWM pins!

To move the servo, simply say hitec.write(deg), where deg is between 0 and 180. Or you can have finer, lower level control with hitec.writeMicroseconds(), where the argument is the desired pulsewidth, in microseconds. You may want to put in protective clauses in your code to prevent accidental driving of the servo beyond its intended range.

The Actual Task

Okay, now that you are familiar with the ingredients, write a simple program to tune up your servo's minimum and maximum pulsewidths corresponding to 0° and 180°. Start by using 900 and 2100 in the attach() command, and perhaps sending the motor to 0°, 90°, and 180° delaying a couple seconds between moves for you to assess the quality of alignment. Iterate values of the min and max pulsewidths until you have it down. You may optionally look at the pulses on the scope to see if the output really is nailing the pulsewidths you are requesting. Could be interesting. Keep this tuning program around, as you may want to use it later in your project to tune a servo you pick up to use at that time.

Having calibrated your servo, now do something semi-creative in controlling it. Whether it is an interactive "move where I tell you" program, or execution of an interesting pattern of motion, or some other idea—it's up to you. If stepping through some pattern, don't forget to put delays in, and perhaps go in small increments towards your goal, with short delays between steps.

To Turn In

Include your final servo control code, whose functionality was checked by a TA/prof. Include (in code/comments) the tuning you used for your servo. Also make sure the comments explain what the program/motion is meant to accomplish. Include a block diagram if how the system is hooked up, to further develop the habit of diagramming your setup (will become much more important in project phase).

Exercise 3: Stepper Motor

Note: This section may take the longest; feel free to skip to Exercise 4 if time is short.

In this exercise, you will use the motor shield to drive a stepper motor. The motor shield (schematic here) provides support for two servo motors (driven from pins 9 and 10 on the Uno), and either 2 stepper motors, 1 stepper and 2 DC motors, or 4 DC motors.

It is generally advantageous to supply external power to the motor shield. To do this:

  1. Remove the jumper adjacent to the 2-pin terminal block.
  2. Set the current limit on the power supply to 0.6 A so the motor shield capabilities are not exceeded.
  3. Hook ground and some positive voltage (depends on motor requirements) to the GND and +M terminals, respectively.
  4. More info can be found here.

Installing the Library

First, you will need to get the driver for the shield. This is not part of the standard Arduino Library, so as a result you will get experience obtaining third-party libraries and installing them in your local space.

You can find documentation on how to use the motor shield at the motor shield site. There, you can find a set of instructions for installing the library. I repeat the instructions here for convenience:

  1. First, grab the library as a zipfile from the github site.
  2. Uncompress the ZIP file onto your desktop or other handy location
  3. Rename the uncompressed folder AFMotor
  4. Check that inside AFMotor is AFMotor.cpp and AFMotor.h files. If not, check the steps above
  5. Place the AFMotor folder into your arduinosketchfolder/libraries folder. For Windows, this will probably be something like My Documents/Arduino/libraries for Mac it will be something like Documents/arduino/libraries. If this is the first time you are installing a library, you'll need to create the libraries folder (or directory). Make sure to call it libraries exactly, no caps, no other name. (for me on my Mac: /Users/tmurphy/arduino/libraries)
  6. Check that inside the libraries folder there is the AFMotor folder, and inside AFMotor is AFMotor.cpp AFMotor.h and some other files
  7. Quit and restart the Arduino IDE. You should now have a submenu called File->Examples->AFMotor->MotorParty

If you want, run the MotorParty example. Or keep it in mind for future exploration.

Controlling a Stepper

The key steps needed to get a stepper motor running are:

  1. Determine the coil pairs using a DVM to measure resistance. Coil resistances are usually in the tens of ohms. If there are four wires, it's easy enough. If there are six, there is a center tap, so you will get multiples of two in your measurements of resistance. A full coil is represented by the largest resistance you measure. The center tap should be half the resistance to either outer lead.
  2. Hook the outer leads of one coil up to either M1, M2, M3, or M4 on the motor shield, and the other coil up to the adjacent M pair. If you have center tap leads, gang them into the middle pin for ground. Order doesn't matter except to determine direction of rotation, which you may determine empirically. Reversing one coil reverses the motion. Reversing both gets you back to where you started. (See this picture for clarification).
  3. Figure out or guess the number of steps per revolution. Sometimes this is printed on the casing. Common numbers are 48, 100, 200, 400 steps per revolution (or S/R). But sometimes this is counted as half-steps, which we'll be on the lookout for.
  4. Arrange an external power supply to run the stepper. A terminal block on the shield accepts input, and the adjacent jumper is to be removed if the external source is used. Initially, set up for 5 V to come in externally, although the specific motor you use may want a higher voltage (or possibly lower).
  5. Make a program that has in the preamble: #include <AFMotor.h> and the declaration: AF_Stepper stepper(# S/R, port);, where the arguments are the steps per revolution of your motor, and the port is either 1 (for M1/M2 terminal block) or 2 (for M3/M4). Here, stepper is just a variable/handle name, and can be anything you want to describe the motor you are setting up (e.g., later may call it something like steering, theta_motor, etc.).
  6. In the setup() block, set the motor speed for multi-step moves by something like: stepper.setSpeed(30);. In this case, we get 30 RPM. I would be hesitant about pushing a stepper much beyond 500 or 1000 RPM (dep. somewhat on steps/rev).
  7. Now in the main loop(), all motion will be handled by the command: stepper.step(NSTEPS, DIRECTION, STEP_TYPE), where stepper is again just the name/handle for your particular stepper, as instantiated above. NSTEPS is integer the number of steps you want it to move. DIRECTION is either FORWARD or BACKWARD, and STEP_TYPE can be SINGLE, DOUBLE, INTERLEAVE, or MICROSTEP.
  8. The only other thing you may want to know is that stepper.release() turns off all coils, putting the motor in a free state.

NSTEPS is straightforward, as is FORWARD vs. BACKWARD (though these are somewhat arbitrary, depending on your coil polarity/hookup). The type of step deserves some elaboration, though.

SINGLE turns on one coil at a time, grounding one side and putting the other at the supply voltage. Each step therefore jerks the motor to a slightly different position. The sequence of activated pins on the terminal strip (numbering 1–4 downward on left, ignoring ground; see this diagram for clarification) is 3, 2, 4, 1, repeating.

DOUBLE has two coils on at once, and therefore consumes twice the current, providing twice the torque. The rotor position will be halfway between the steps seen in the SINGLE scheme. Coils are turned on as follows: 1/3, 3/2, 2/4, 4/1. In the second step, when leads 2 and 3 are energized, the rotor will be between the first and second positions in the single sequence above. And so it continues along the sequence. Note that the steps are the same size as in SINGLE mode.

INTERLEAVE performs a half-step sequence, merging the two sequences above. It therefore takes twice as many steps to complete a revolution. One has finer control, and the power will be between that of SINGLE and DOUBLE modes, in general. But if you park on a double-coil position for a while, you're at twice the power than if you happen to park on a single coil position. The sequence is: 1/3, 3, 3/2, 2, 2/4, 4, 4/1, 1, and repeats. You can see that the rotor is more gently walked along the sequence in smaller nudges.

We will leave off detailed discussion of Microstepping for now. Suffice it to say that transitions from one step to the next are handled by PWM ramping of the signal levels to make a smooth handoff to the next step.

Actual Exercise

Now you have the nuts and bolts defined for you, you're ready to do something with the motor.

The first thing you should try is moving the motor by the number of steps (SINGLE type) that you suspect makes a full revolution. Put a mark or tape or cardboard or something on the shaft to let you see the revolutions, and see if you can get it precisely back to the same place. Put a delay in the loop long enough to judge position, and perhaps alternate back and forth until you are in the right ballpark. When it looks pretty good, you can chop out the reverse section and see if repeated forward moves accumulate error. You should know after a few revolutions. But if you run for several minutes you'll develop an appreciation for what a stepper delivers: confident positioning time after time, never losing a step.

Now you can do one of several things for you stepper "demonstration." The point is to get you to use the stepper in some way that is informative to you, and potentially useful down the road. You can deviate from the following suggestions, but just make sure your task is not too trivial to count. Run the idea by a TA/prof for approval. Some possible tasks include:

To Turn In

Have a TA/prof check the behavior of your creation, and print out the program for submission. Indicate what kind of motor you used and how many steps you found it to have. Make a block diagram of your stepper configuration.

A Word of Caution

The motor shield can use most of the Uno's pins. It is not easy to find info on which pins are unavailable when the motor shield is in use. Here is an excerpt (several corrections from original!) detailing the pin usage:

All 6 analog input pins are available. They can also be used as digital pins (pins #14 thru 19)

Digital pin 2, and 13 are not used.

The following pins are in use only if the DC/Stepper noted is in use:
Digital pin 11: DC Motor #1/Stepper #1 (activation/speed control)
Digital pin 3: DC Motor #2/Stepper #1 (activation/speed control)
Digital pin 6: DC Motor #3/Stepper #2 (activation/speed control)
Digital pin 5: DC Motor #4/Stepper #2 (activation/speed control)

The following pins are in use if any DC/steppers are used
Digital pin 4, 7, 8 and 12 are used to drive the DC/Stepper motors via the 74HC595 serial-to-parallel latch

The following pins are used only if that particular servo is in use:
Digital pin 10: Servo #1 control
Digital pin 9: Servo #2 control

Exercise 4: DC motor

Almost there. The last type of motor we will look at is a DC motor. These are very simple, but can easily exceed the capabilities of the shield. The H-bridge use on the shield can only handle loads up to 0.6 A. This may sound like a lot, but you'd be surprised, when it comes to motors.

Now that you've seen the stepper example using the motor shield and associated library, it will be very easy to run a DC motor. Here's what you need to do:

  1. Before doing anything else, set make sure the power supply is set to a current limit of 0.6 A so the motor shield is not exceeded.
  2. Verify the voltage needed to run the motor. Ideally, a label will tell you, or a model number may let you look it up online. Barring this, hook it up to a power supply and slowly ramp up voltage (make sure the current limit setting on the power supply is not preventing you from reaching operating state). You'll get a sense for how hard you might drive the motor, but I would be cautious about exceeding the initial-turn voltage by a large factor. Don't destroy the motor trying to figure out its name. If possible, monitor how much current is demanded by the motor when running at speed. If this is well under 0.6 A, then it is safe to use with the motor shield.
  3. Hook up a motor to M1, M2, M3, or M4. Polarity will determine direction of the motor spin.
  4. Make a program that has in the preamble: #include <AFMotor.h> and the declaration: AF_DCMotor mymotor(port);, where the port is 1, 2, 3, or 4 according to M1, etc.
  5. In the setup() block, set the motor speed as a fraction of the maximum (255) by something like: mymotor.setSpeed(200);. The setSpeed() bit really just sets up PWM to control the voltage level output to the motor, as a fraction of the supply voltage.
  6. To run the motor, just say mymotor.run(DIRECTION), where DIRECTION can be FORWARD, BACKWARD, or RELEASE. Of course the polarity of the hookup will also have a say in what "FORWARD" means.

DC motors are not truly controllable in terms of speed, as this depends on the load the motor sees. But the PWM control exerted by setSpeed() at least provides variable speed capability at a given load. Note that at the lower end of the range, motors may decide to simply stall.

Actual Exercise

So what do you need to do? Pretty simple for this one. Make a program that ramps up a motor's speed over something like five seconds, than ramps it back down again, in a repeating pattern. Try to hit the max speed and something close to a minimum speed that reliably does not stall (so give a little margin on the low end). Turn in the code that made your oscillating speed motor and have a TA/prof check the functionality of the code. Also include a block diagram.


Back to Phys 124 Lab Information Page