You are on page 1of 21

Stepper Motor

Mission Mapping Software

In this lab, you will learn more about the Adafruit motor shield and how it can be used to control
a stepper motor. Your work with the IR sensors will also continue as you teach your rover how
to map the terrain surrounding it, equipping it with sufficient knowledge to navigate around
possible obstructions, and finally reach the desired plaques of interest.

Table of Contents
1
2

3
4
5

Reading
1.1
References
Homework and Mission
2.1
Homework
2.2
Mission
2.3
Documentation
Lab Checklist
Parts
How it Works
5.1
General
5.2
Construction
5.3
Unipolar vs. Bipolar
5.4
Movement
5.4.1
Single
5.4.2
Double
5.4.3
Interleave
5.4.4
Microstep
Lab Experiments
6.1
Gyro Calibration
6.2
Horizontal Alignment of the Scan Platform
6.3
Mapping Experiment
6.3.1
Documentation
Software
7.1
Gyro Calibration Application
7.2
Mapping Software Application

7.3

Find Objects Software Package


7.3.1
findObjects Global variables
7.3.2
Subroutine findObjects()
7.4
Verify Software Package
7.4.1
verify Global variables
7.4.2
Subroutine verify()
7.5
Utility Functions
7.5.1
Function stepTurret()
7.5.2
Function arcSine()

Reading

Your reading this week is Chapter 10 Serial Communications Sections 10.1


and 10.1.2 Serial Peripheral Interface (SPI).

Most of the material in this document on the SPI subsystem can be found in
Chapter 18 The Serial Peripheral Interface (SPI) of the ATmega328P Datasheet.
We will be looking at stepper motors and the SPI serial communications as they are
implemented by the Arduino and the Adafruit Motor Shield. Here is the motor shield schematic
http://www.ladyada.net/make/mshield/download.html
and here is the pdf documenting the shield and how to control a stepper motor (pages 25 and
26) http://www.robotshop.ca/content/PDF/adafruit-motor-shield-arduino-user-guide.pdf

1.1 References
1. Atmel AVR Micrcontroller Primer:Programming and Interfacing, by Barrett, Section 6.4
DC Motor Speed and Direction Control
2. HSI Stepper Motor Theory and Stepper Motor are good recources, among many on the

web, for learning about Stepper Motors.


3. Stepper Motor Basics - Introduction to Stepper Motors.
4. Interface Electronics - Ricky's World
5. YouTube Video - Motorola Stepper Motor Control IC
6. Atmel application notes doc7672.pdf (Sensor-based Control of Three Phase Brushless
DC Motors)
7. Parallax 12-Volt Unipolar Stepper Motor
8. Stepper Motor - Wikipedia
9. Identifying Stepper Motor wires
10. http://www.netrino.com/Embedded-Systems/How-To/PWM-Pulse-Width-Modulation
11. http://www.ducttapeeng.com/smd/smd11.htm - disassembly
12. http://www.stepperworld.com/Tutorials/pgBipolarTutorial.htm - sequences

Homework and Mission

2.2

Mission

Before your rovers can travel to points of interest (the plaques), it needs to be able to pick them
out from other terrain features (walls, cabinets, desks, chairs, etc.). At the end of this lab you
should have completed a...
IR Mapping Experiment - the Difference Map
Software with associated documentation to identify targets within the field-of-view of the
rover.
As a necessary precondition for completing these experiments, the scan platform and IR
rangers will need to be aligned horizontally.

2.3

Documentation

Summarize your experimental results and equation(s) in the subsection named IR Sensors
within the Hardware Build section of your Project Document. This subsection should include a
discussion of the modifications you made to the indoor mapping experiment in order to achieve
success on the test site.

Lab Checklist

The checklist is filled in by the instructor at the beginning of next weeks lab.
Horizontal Alignment of the scan platform with tilt calculation

IR Mapping Experiment

Graphical results with comments from running makeMap program are included in the IR
section of the Project Document.
Target Location Algorithm added to the Software Code Section.

Results from running your findObjects software to identify targets within the field-of-

view of the rover.


Rover successfully completes the mission

Parts

For this lab, we will need the following essentials...

Solderless breadboard

Sharp
GP2Y0A710YK0F
Long Range IR Sensor
$19.50

Sharp GP2Y0A02YK0F
Medium Range IR
Sensor $12.50

Bourns Inc. 10.0


K Potentiometer
Digikey 3310Y-001103L-ND

4.7 K resistor

10uF Capacitor

680 ohm resistor

LED

In addition to our essentials, we will need some measuring equipment and supplies to complete
this lab...

Tape Measure
(inches and cm)

Laser Pointer

Level

You will also need your breadboard wire bundle plus half-size breadboard.

Electrical Tape

How it Works

The best discussion on how stepper motors work can be found on Wikipedia under Stepper
motor. To learn how to use these in the Arduino IDE look here. Also see AdaFruit Make it Work
under the Stepper section.

5.1

General

Stepper motors can be salvaged from obsolete disk drives and ink jet printers. The motors from
3.5" floppy motors are not suitable for this lab. Bipolar motors have 4 wires and unipolar motors
have 5,6 or 8. Bipolar motors generally have a larger torque and smaller step angle when
compared to unipolar stepper motors. You can find common phase leads by using a ohmmeter
to measure resistances between leads, common phase leads will have low resistances in
around 30 ohms.
Stepper motors can be broken down into 3 categories.
1. Variable reluctance stepper- magnetic flux seeking the lowest reluctance path through a
magnetic circuit.
2. Permanent magnet stepper- has a cylindrical permanent magnet rotor.
3. The hybrid stepper- combination of variable reluctance and permanent magnet steppers
Source: http://www.stepperboard.com/MotorConnections.htm

5.2

Construction

An inductive motor like our stepper motor has two major components: a stator and a rotor.
The rotor is the magnetic armature of the stepper motor and is the moving part of the stepper
motor. The rotor consists of bearings, magnetic shaft and poles. This cylindrical shaft contains
permanent magnets which interact with the stator. The stator is the external part of the inductive
motor that does not move. The stator contains the bearing housing, the stator coils and the
stator poles. (Follow this link for a disassemble). A stepper motor is a type of motor whose
circular rotation of the rotor is divided into smaller discrete steps. The number of steps a
stepper motor takes in order to make one full rotation of the rotor is fixed and is determined by
the number of poles inside the motor. Each step turns the rotor a certain number of degrees.
Smaller step angles are obtained by adding more poles on both the rotor and stator. Both
unipolar and bipolar stepper motors are constructed this way while the main difference lies in

the wiring of the coils.

Souce: Motors Guide


Source:HSI Stepper Motor Theory

5.3

Unipolar vs. Bipolar

Unipolar stepper motors are designed to have a canter tap which is common to two coils
working together. The positive voltage is then applied to the common tap and the nodes a and
b are alternately grounded to produce changes in polarity to the magnetic field. You can check
the direction of the field by using the equation B=IxR (this is greatly simplified for our purposes)
where B is the magnetic field, I point in the direction of positive current flow, and R is in the
direction of where you want to measure the magnetic field at. For example if 1 is positive, a is
grounded, and b is open (high impedance) current flows from 1 to a in Figure 1 and the direction
of the magnetic field flows out at the left end and comes in at the right end (Figure 2 is meant to
clear up which way is north or south. If the magnetic field is outgoing it is south while north is on
the receiving end). If the current flows from 1 to b,while a is high impedance, then the polarity is
reversed.
Figure 1

Figure 2

From:http://www.cs.uiowa.edu/~jones/step/types.html

From:http://en.wikipedia.org/wiki/
File:Dipole_field.svg

A bipolar motor has no center tap and the current must flow from a to b or from b to a. We must
reverse the current in order to reverse the magnetic field as opposed to switching the ground.
This requires a more complex design to handle and is usually left to an H-bridge to configure.

5.4

Movement

The stepping sequence of a bipolar stepping motor can be broken down into:
1. Step mode: Full step (one-phase or two-phase), Half Step (eight-phase), Micro-stepping
(not used in the lab).
2. Misc factors: Power, torque, step angle and accuracy.
The type of stepping sequence that is used is dependent on the type of application of the motor.

Source: Stepper World


For the Adafruit Motor shield we can have four different modes of activation. These modes are
Single, Double, Interleave, and Microstep. For a GIF animation showing these stepper modes
visit CNC Router Source.

5.4.1 Single
This mode refers to the single-coil activation aka the Wave Drive, One-Phase activation of the
motors. See GIF animation. For the ROB-09238 this gives you a step of 1.8o.

5.4.2 Double
This mode refers to the double-coil activation aka the Full Step, Two-Phase activation of the
motors. See GIF animation. For the ROB-09238 this gives you a step of 1.8o.

5.4.3 Interleave
This mode refers to the single-coil/double-coil aka the Half Step activation of the motors. See
GIF animation. For the ROB-09238 this gives you a step of 0.9o.

5.4.4 Microstep
The micro-stepping mode is the most complex of all the stepping modes. That is why some
stepper drivers only offer full and half step modes. Micro-stepping is when the current applied
to each winding is proportional to a mathematical function, providing a fraction of a full step.
The most common divisions are 1/4th, 1/8th, 1/10th, etc. However, there are some drivers that
provide up to 1/256th of a full step. Micro-stepping provides greater resolution and smoother
motor operation. This is very advantageous as it reduces the need for mechanical gearing when
trying to achieve high resolution. However, micro-stepping can affect the repeatability of the
motor. (source: CNC Router Source).

Lab Experiments

To accomplish our objectives, the lab consists of a number of experiments.


Do Not Forget
Unless otherwise indicated, all experiments may be run with fully charged battery or from
an external source (USB or Adapter).
Please, include all experimental setup and results in your lab notebook.

6.2 Horizontal Alignment of the Scan Platform


In this part of the lab we are going to make sure your rover is mission ready by checking the
horizontal alignment of the scan platform.
The following steps assume you have incorporated a reliable method for adjusting perpendicular
alignment of the scan platform with respect to the base and parallel alignment of IR ranger with
respect to the platform. Specific design recommendation include using screws to attach your
stepper motor to the base and to include a screw for adjusting the tilt (i.e., pitch) of the long
range IR sensor. The Sharp GP2Y0A710YK0F conveniently provided a mounting hole for pitch
adjustment. Further the electrical wires running from the base to the platform must allow for the
platform to rotate at least 180 degrees in any direction.
1. Attach your laser pointer to the scan platform and co-align with the IR ranger - not
the side. We are currently not sure if the best location is directly over the IR source or
sensor.

2. Place your rover on the raised platform at the front of the lab. Using your level, find a
relatively flat and level part of the floor. After placing your rover at this location, again
using your level, verify that the base of the rover is level to the floor.

3. Using your triangle adjust the stepper motor mount so the shaft of the stepper motor is
perpendicular to the base. This assumes that any adapters you have attached to the
shaft of the stepper motor are also aligned. Verify this alignment for all 360 degrees of
rotation.
4. Using the triangle and level adjust the scan platform/IR sensor so it is perpendicular
to the shaft/mounting adapter of the stepper motor and parallel to the floor for all 360
degrees of rotation. It is critical that the IR sensor not be tilted with respect to the axis of
rotation.

5. Have the rover run the scan platform demonstration sequence from last week.
6. Approximately locate the laser beam's maximum and minimum height from the floor.
7. Place a target at these two locations 4 meters from the rover. You may have to reorient
the rover to be able to locate the targets on the platform.
8. If required, repeat steps 2 through 7, until the laser beam stays approximately level to
the floor during its 360 degree scan.
Once you feel the scan platform is mission ready, program the rover to move one meter and run
the scan platform demonstration sequence from last week. Locate the minimum and maximum
height. Do not move the scan platform by hand - we are trying to replicate the real-world that
the rover will encounter during the mission. Place targets as far away as you can at these two
locations and record the beam height, distance, and the rotation angle from the home position
(straight ahead). Tell your rover to move approximately 1 more meter, and again have the rover
run the scan platform demonstration sequence. Record beam height, distance, and the rotation
angle.

Have the rover move an additional meter and repeat the sequence.
After running these experiments calculate the maximum angle that the floor could be tilted, so
the laser does not hit the floor or go over an 11 inch high target.
Rotation Angle

Distance to Target

Beam Height

Signature/Date

Test 1
Test 2

6.3 Mapping Experiment


Run the Arduino mapping program provided in the software section of this document. The
program rotates one half-step (INTERLEAVE) and runs an IR measurement test sequence
(function statPak). The program repeats this sequence until the rover has completed a 360
degree scan of the room. The software has been designed to support most of your stepper
motors, this means a step size of 0.9 degrees and 400 test points. If needed, update these
variables for your stepper motor. Also set the analog input pin (sensorPin) as required by your
design.
Before running the mapping experiment...
1. Verify that you have completed everything on the Baseline IR Calibration checklist specifically, Step 1: Wire the Circuit and Step 2: Setup the Test Fixtures.
2. You will be running the mapping experiment with the laser ON. You should verify that the
laser does not invalidate your baseline calibration data. Tape the laser on the top of the
IR ranger (not the side). Tell me if the results are better with the laser over the IR source
or sensor.
3. Verify that the Horizontal Alignment of the Scan Platform is complete. Be sure the wires
running from the base to the scan platform can support at least 180 degrees of rotation.
Place the rover at the front of the lab, as defined by the instructor and make a 360 degree map
of this location. Place six (6) plaques as required by the Mission Plan. Include targets within the
range of both IR sensors.

Using your compass, string, and ruler measure the rotation angle and
distance of the targets relative to the IR sensor(s). Record the location (angle and distance)

of these plaques in your lab notebook. You may also want to take a picture(s) and/or video for
future reference. As you can see in the figure below, the photo makes a nice background for
displaying the results of your mapping experiments.
I recommend running with the laser ON in order to record when the IR is looking at a target.
Download and run the program. Launch the terminal program (warning: opening or closing
the terminal program during a scan will effect your experimental results). You should see the
message "in setup," followed by "press any key to start scan." Press any key to
start the scan.
Record in your lab notebook the steps at which the laser hits a target.
After the scan platform has mapped 180 degrees, spun 360 degrees, and completed the next
180 degree scan, you should see the message "data set complete," followed by "press
any key to start scan." Remove the plaques from the scan area and press any key to
start the second scan.
Stop the program after the scan platform has completed two full mappings as previously defined
(with and without plaques).
Cut and Paste your results into a text file. Import this text file (comma delimited) into an Excel
spreadsheet. Add columns translating test values into distances. For both mappings, add
a column named sample difference and have Excel calculate the difference in the average
distance from each measurement (dn - dn-1). Next add a column named mapping difference and
have Excel calculate the difference in the average distance for each sample angle (with and
without plaques). You are welcome to download my Excel spreadsheet and use it as a template
for recording your data.

6.3.1 Documentation
Document your experimental results and subsequent calculations in the subsection named IR
Sensors within the Hardware Build section of your Project Document.

7 Software
7.1 Gyro Calibration Application
7.2 Mapping Software Application
The following program requires utility functions getRange and ReadADC located in the "Utility
Functions" Section of Lab 4.
/*
*
*
*
*
*
*
*

Mission Mapping Software


Begins by...
note: word is equivalent to unsigned int, which is equivalent to uint16_t
By Gary Hill

* March 27, 2010


*/
#include <stdint.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
/*
* The range data needs to be unsigned int
*
* rangedata.h should look like this:
* const int range_length=1024;
*
* const unsigned int range_data[] PROGMEM = {
* 437, 437, ...
* };
*
*/
#include <AFMotor.h>
#include "rangedata.h"
byte sensorPin=4;
// 400 entries x 2 bytes/entry = 800 bytes, ATmega328P has 2,048 bytes of SRAM
int map_data[400];
AF_Stepper motor(200, 1);
// instantiate a 1.8 degrees/step stepper motor
void setup()
{
motor.setSpeed(10);

// 10 rpm

Serial.begin(9600);
Serial.println("in setup");
analogReference(EXTERNAL);

// where Vref is 3.3V

motor.release();
makeMap();

// generate a difference map

}
void loop()
{
}
/*
* Make a Difference Map
*/
void makeMap()
{
int dn = 0;
tweak();

// adjust IR Ranger zero angle

// take 200 measurements and 199 steps (stops at 179.1 degrees clock-wise)
for (int i = 0; i < 200; i = i++) {
dn = readADC(sensorPin);
map_data[i] = pgm_read_word(&range_data[dn]);
// Serial.println(map_data[i]);

motor.step(1, FORWARD, INTERLEAVE); // 0.9 degrees/step


delay(60);
// @ 10 rpm, this should take 15 ms + 45 ms margin
}
// rotate counter clock-wise 399 steps (stops at 180 degrees clock-wise)
// 0.9 degrees/step x 399 steps = - 359.1 degrees
motor.step(399, BACKWARD, INTERLEAVE);
delay(10000);
// @ 10 rpm, this should take 6 seconds + 4 second margin
// take 200 measurements and 199 steps (stops at 359.1 degrees clock-wise)
for (int i = 0; i < 200; i = i++) {
dn = readADC(sensorPin);
map_data[i + 200] = pgm_read_word(&range_data[dn]);
// Serial.println(map_data[i + 200]);
motor.step(1, FORWARD, INTERLEAVE); // 0.9 degrees/step
delay(60);
// @ 10 rpm, this should take 15 ms + 45 ms margin
}
// cancel extra step
motor.step(1, BACKWARD, INTERLEAVE);
Serial.println("initial mapping complete");
Serial.println("add targets and enter go");
tweak();

// adjust IR Ranger zero angle

// take 200 measurements and 199 steps (stops at 179.1 degrees clock-wise)
for (int i = 0; i < 200; i = i++) {
dn = readADC(sensorPin);
map_data[i] = map_data[i] - pgm_read_word(&range_data[dn]);
Serial.println(map_data[i]);
motor.step(1, FORWARD, INTERLEAVE); // 0.9 degrees/step
delay(60);
// @ 10 rpm, this should take 15 ms + 45 ms margin
}
// rotate counter clock-wise 399 steps (stops at 180 degrees clock-wise)
// 0.9 degrees/step x 399 steps = - 359.1 degrees
motor.step(399, BACKWARD, INTERLEAVE);
delay(10000);
// @ 10 rpm, this should take 6 seconds + 4 second margin
// take 200 measurements and 199 steps (stops at 359.1 degrees clock-wise)
for (int i = 0; i < 200; i = i++) {
dn = readADC(sensorPin);
map_data[i + 200] = map_data[i + 200] - pgm_read_word(&range_data[dn]);
Serial.println(map_data[i + 200]);
motor.step(1, FORWARD, INTERLEAVE); // 0.9 degrees/step
delay(60);
// @ 10 rpm, this should take 15 ms + 45 ms margin
}
// cancel extra step
motor.step(1, BACKWARD, INTERLEAVE);
Serial.println("difference mapping complete");
}

/*
* Terminal adjust of starting angle
* Enter the plus or minus character (+/-) and the number of steps (n = 1 to 9).
*/
void tweak(){
char ch;
// used by tweak
Serial.println("enter +n, -n, or go where n = 1-9 steps and go = start scan");
while(1)
{
while (Serial.available() <= 1) {}
// do nothing
// send data only when you receive data:
if (Serial.available() > 1) {
// read the incoming byte:
ch = Serial.read();
// Serial.println(ch, HEX);
if ( ch == 0x2d ) {
Serial.print("minus ");
ch = Serial.read();
ch = ch - 0x30;
Serial.println(ch, HEX);
// 0.9 degrees/step x 399 steps = - 359.1 degrees
motor.step(ch, BACKWARD, INTERLEAVE);
} else if ( ch == 0x2b ) {
Serial.print("plus ");
ch = Serial.read();
ch = ch - 0x30;
Serial.println(ch, HEX);
motor.step(ch, FORWARD, INTERLEAVE); // 0.9 degrees/step
} else if (ch == 0x67 ) {
ch = Serial.read();
delay(250);
Serial.println("scanning...");
return;
} else {
ch = Serial.read();
Serial.println("unknown entry");
}
}
}
}

7.3

Find Objects Software Package

The following program requires utility functions getRange and ReadADC located in the
shared "Utility Functions" Section of this document.

7.3.1 findObjects Global variables


Place these variable declarations at the top of your program.
// In order to quickly change the number of steps we must use define
// and not a constant, as the arduino ide doesn't like variables

// initializing the array length


#define map_length 400
#define plaque_array_size 20
// findObjects variables
int numPlaques=6;
int sensitivity=15; // difference in distance (cm) of mapping data for a
// plaque to be suspected
int minWidth=2;

This software program assumes that makeMap has been called and has generated a 400 entry
array.
// 400 entries x 2 bytes/entry = 800 bytes, ATmega328P has 2,048 bytes of
SRAM
// and 1,024 bytes of EEPROM
int map_data[map_length];

If you simply want to test findObjects add the following array declaration.
int map_data[]=
{-8,14,18,7,18,85,147,200,197,174,55,0,-54,1,-14,10,6,-1,4,6,10,36,49,66,58,135,-110,-3,0,10,1,-1,6,2,2,1,18,53,50,45,43,39,25,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,18,17,20,19,16,16,16,9,13,-3,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,-1,0,0,-1,0,0,0,0,-1,0,0,3,0,31,79,97,100,103,111,118,122,131,137,140,34,7,5,-3,-10,14,-9,7,9,15,0,0,0,0,0,0,0,0,0,0,0,17,42,52,-10,15,25,3,46,12,87,179,224,288,76,108,125,32,0,-1,-7,-12,0,7,-9,-5,0,-11,12,-10,-3,4,1,-2,-14,6,2,12,30,40,-27,5,23,-19,6,5,-15,-46,-17,-97,23,93,32,101,21,3,0,0,0,0,0,0,0,-4,-1,3,29,52,-2,-13,0,83,0,0,0,-2,0,0,0,12,94,-143,-309,-71,-69,-27,37,139,265,148,4,77,197,0,1,0,264,72,0,77,135,243,0,15,11,16,2,-242,320,-205,1,5,8,10,0,-1,-1,0,0,-8,15,9,0,-16,-292,-125,-239,-8,-11,2,0,0,-1,0,40,0,0,-1,82,0,76,206,4,0,2,9,0,0,-2,4,0,-9,6,4,4,-4,1,0,0,0,0,0,0,0,0,0,0,0,0,-20,0,6,2,1,1,0,-7,2,0,1,1,-5,-2,-1,10,14,6,-2,12,7,5,-4,1,1,-16,14,16,0,0,15,8,0,-7,21,0,0,2,0,0,0,0,0,0,0,1,2,-1};

7.3.2 Subroutine findObjects()


void findObjects(){findObjects(map_length);}
void findObjects(int mapEnd){
Serial.println("finding objects");
boolean plaqueDetected=false; // flag determining recording status
// false means that there is currently no plaque detected,
// true means a plaque is being evaluated
int gapCounter=0;
int gapTolerance=1;
// starting index of a suspected plaque (see sensitivity)
int beginning=0;
int ending=0;
// ending index of a suspected plaque
int p_Idx=0;
// index of a detected plaque
// makeMap(mapEnd);
for (int i = 0; i < map_length; i++){

// don't stop detecting plaques

// if the difference is greater than (15), and we're not already recording,
// then start recording plaque length
if((map_data[i]>=sensitivity)&!plaqueDetected){
beginning = i;
// The previous gap count could be moved in code for different effects.
// It is placed here so that it counts the total length of gaps in a
// signal as opposed to any individual gap in a signal ie: for a
// tolerance of 2 10101011 won't pass.
gapCounter = 0;
plaqueDetected=true;
}
if((map_data[i]<sensitivity)&plaqueDetected){
gapCounter++;
// if the value falls below (15) dont count
ending = i - gapCounter;
// the extra gap in the ending of the plaque
if(gapCounter > gapTolerance) {
// only stop after the gap has exceeded
plaqueDetected=false;
// the tolerance
if(ending-beginning >= minWidth){ // if plaque was wide enough count it
p_angle[p_Idx]= (ending + beginning)/2; // save the angle as the
//Serial.print(p_Idx);
// midpoint of the beginning and
end
//Serial.print(": ");
//Serial.println(p_angle[p_Idx]);
p_Idx++;
// move to the next array location
}
}
}
}
verify(p_Idx);

// manual override y/n of detected plaques

}
// else gapCounter=0; // place the reset to gapCounter here if you'd like
// to clear it after the end of every gap

7.4

Verify Software Package

Needs to be modified to write final list to EEPROM


The verify function allows the user to approve/disapprove plaques found by findObjects. It also
recovers distance-to-plaque data destroyed by makeMap in order to reduce SRAM overhead.

7.4.1 verify Global variables


Place these variable declarations at the top of your program.
// verify constants and variables
#define plaque_array_size 20;
int p_angle[plaque_array_size];
int p_dist[plaque_array_size];

// 12 *2 = 24 bytes

int p_length = 0; // number of verified plaques, may be less than


// actual array size if some plaques were not approved

7.4.2

Subroutine verify()

void verify(int numDetected){


char userIn;
int angle;
// current angle to detected but not verified plaque
int dist;
// current angle to detected but not verified plaque
boolean valid; // used to see if user input is valid
Serial.println("Please manually verify with a y/n if this is a
plaque");
Serial.print("This is out of: ");
Serial.println(numDetected);
Serial.println("Angle:Distance");
p_length = -1;

// initialize number of verified plaques

for (int p_Idx = 0; p_Idx < numDetected; p_Idx++){


valid=false;
// angle is a interleave number of steps NOT degrees or radians
angle = p_angle[p_Idx];
// This assumes FORWARD is CW and BACKWARD is CCW
// This may not be a good assumption for your rover.
motor.step(angle,FORWARD,INTERLEAVE);
delay(60);
dist = getRange('L');
Serial.print(angle);
Serial.print(": ");
Serial.println(dist);
Serial.flush();
while(Serial.available()==0){}
valid = false;
while(!valid){
userIn=Serial.read();
if (userIn=='y'||userIn=='Y'){
p_length++;
p_dist[p_length] = dist;
p_angle[p_length] = angle;
valid=true;
} else if(userIn=='n'||userIn=='N'){
valid=true;
}
else {
Serial.println("Invalid input");
Serial.flush();
}

// now that the user has verified or disallowed this plaque


// return to home position.
motor.step(angle,BACKWARD,INTERLEAVE);
}
}
Serial.println("Done");
}

7.5 Utility Functions


The following utility functions are common to many of the programs you will be writing.

7.5.1 Function stepTurret()


This utility must replace all motor shield step commands to the stepper motor, including onestep
and step. Once replaced, lost_dog_counter will always contain the number of +/- steps needed
to return the turret to its home position.
int lost_dog_counter=0;
void stepTurret(int a_steps, int a_dir, int a_style)
{
if(a_style == SINGLE){
a_steps = 2 * a_steps;
}
if (a_dir == FORWARD){
lost_dog_counter += a_steps;
}
else{
lost_dog_counter -= a_steps;
}
if(a_steps==1){
motor.onestep(a_dir, a_style);
delay(motor.usperstep/1000);
}
else {
motor.step(a_steps, a_dir, a_style);
}
}

7.5.2

Function arcSine()

/*
* Find offset angle (in interleave steps) based on distance-to-target
* ref: http://www.nongnu.org/avr-libc/user-manual/
group__avr__math.html#g98384ad60834911ec93ac5ae1af4cf0a
* asin argument must be between -1 and 1, returned value is between
* -pi and pi (-90 and 90 degrees)
*
* INPUT
* Data
Argument
Description

* Type
Units
* double a_opp
cm
opposide side of a right triangle
*
(typically offset distance)
* double a_hyp
cm
hypotenuse of a right triangle
*
(typically dstance measured by ir ranger)
*
* OUTPUT
* returns angle
steptype
*
* note: if steptype is INTERLEAVE then a step is (0.9 degrees/step),
*
otherwise SINGLE is assumed (1.8 degrees/step).
*/
int arcSine(double a_opp, double a_hyp){
double d_x;
float d_angle;
d_x = a_opp/a_hyp;
if (-1 > d_x || d_x > 1) {
// domain error
digitalWrite(ledPin, HIGH);
Serial.print("domain error x = ");
Serial.println(d_x);
return(-1);
}
d_angle = asin(d_x)/radians_step; // calculate angle in degrees
return int(d_angle);

// convert to steps

7.6

EEPROM Functions

7.6.1 Ardunio Library Functions


The Arduino write and read functions are all you need to read and write a byte of data to
EEPROM

EEPROM.write(address, value)
Parameters
address: the location to write to, starting from 0 (int)
value: the value to write, from 0 to 255 (byte)
Example
#include <EEPROM.h>
void setup()
{
for (int i = 0; i < 512; i++)
EEPROM.write(i, i);
}
void loop()
{
}

EEPROM.read(address)
Parameters
address: the location to read from, starting from 0 (int)
Returns
the value stored in that location (byte)
Example
#include <EEPROM.h>
int a = 0;
int value;
void setup()
{
Serial.begin(9600);
}
void loop()
{
value = EEPROM.read(a);
Serial.print(a);
Serial.print("\t");
Serial.print(value);
Serial.println();
a = a + 1;
if (a == 512)
a = 0;
delay(500);
}

//Extension to EEPROM library by Tim Hirzel


#include<avr/EEPROM.h>
float readFloat(int address){
float out;
eeprom_read_block((void *) &out, (unsigned char *) address , 4 );
return out;
}
void writeFloat(float value, int address){
eeprom_write_block((void *) &value, (unsigned char *) address, 4);
}

You might also like