0% found this document useful (0 votes)
10 views

Lab Exercise 5 - Motion and Distance

Uploaded by

jackrd3636
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
10 views

Lab Exercise 5 - Motion and Distance

Uploaded by

jackrd3636
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 13

Lab Exercise 5: Motion and Distance

Jack Donovan
Aaron Wilson

University of Vermont, Department of Electrical Engineering

CMPE 3815: Microcontroller System

Lab Exercise 1:

One of the many forms of motion control is a servo motor. A servo motor is essentially a
DC motor with an embedded closed loop feedback system. The DC motor is controlled with a
PWM signal and is attached to a potentiometer. This potentiometer feeds back to the
microcontroller to record the current position. The onboard embedded software can use this
information to adjust for errors. The servo had an embedded gear reduction to produce higher
torque and not have the DC motor running at very low RPMs.
For this exercise we decided to use the joystick to control the servo motor. Initially, we
were gonna have the joystick control the speed of the servo, but we decided to control the
position instead (much simpler). We use a function to analogRead() the pin attached to one of the
joystick’s axis’ and then map the 10 bit reading to the range of the servo (180 degrees).
As the PWM control of the servo can be quite complicated, we used a built in arduino
library function to control the servo. To initialize you simply create a Servo object and attach the
control pin to the object. Then, it is as simple as using servo.write() with a position to drive the
servo to the desired position. The only errors we had in the programming of this was thinking the
joystick reads back negative values and the servo uses negative positions (neither do that).
Thankfully, with the use of constants that was an easy fix.
/**
Microcontroller Systems Lab 5
Part 1
Jack Donovan
Aaron Wilson

Reads a joystick so command a servo position


**/
#include <Servo.h>

const int servoDataPin = A0;


const int joystickPin = A1;
Servo myServo;
const int servoRange = 180;

void setup() {
// attached data pin for servo
myServo.attach(servoDataPin);
pinMode(joystickPin, INPUT);
Serial.begin(9600);
}

void loop() {
// read the joystick, command position
static int position = 0;
position = readJoyStick(joystickPin, servoRange);
myServo.write(position);
}

int readJoyStick(int pinJoyStick, int range) {


// read analog pin from joystick, map it to our range
int read = analogRead(pinJoyStick);
Serial.println(read);
read = map(read, 0, 1023, 0, range);

return read;

Lab Exercise 2:

This exercise involved using an ultrasonic sensor to print out the distance it read to an
LCD screen. Thankfully, we previously displayed the distance from an ultrasonic sensor onto a 7
segment display as part of the free task. For this we simply had to scavenge our code for the
ultrasonic sensor and code for an LCD and shove it together.
Reading the distance from an ultrasonic sensor is fairly straightforward. The sensor
consists of a trigger pin and an echo pin. Holding the trigger pin high for 10 microseconds then a
very fast ultrasonic burst out from it. When this pulse is sent the echo pin goes high, then it goes
low when the sensor, well, senses the return of the ultrasonic pulse after it bounced off an object.
The duration the echo pin was high can be returned from the pulseIn() function. Thankfully, we
know the speed of sound at sea level in normal conditions really well (I am in a gas dynamics
class with a midterm coming soon I do not want to think about the speed of sound right now).
Since we know the time the pulse took and the velocity of the pulse, we can calculate the
distance of the object.
As this sensor can read very fast, we use the following code to smooth out what we send
to the LCD:
if (millis() - timeSinceLastDisplay > delayTime) {
distance = findDistance(triggerPin, echoPin);
timeSinceLastDisplay = millis();
}
The LCD uses the lcd.print() function as detailed in previous reports. We did not end up
using the loading bar but we displayed the distance to the screen.

/**
Microcontroller Systems Lab 5
Part 2
Jack Donovan
Aaron Wilson

Prints distance from ultrasonic sensor to an lcd, with accompyaning bar


indicating distance
**/

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
// UltraSonic Pins
const int triggerPin = A2;
const int echoPin = A3;
// Sensor Refresh Rate
const int delayTime = 500;
// LCD Stuff
LiquidCrystal_I2C lcd(0x27,16,2); // set the LCD address to 0x27 for a 16
chars and 2 line display
// partial bars for loading bar
byte bar1[8] {B10000,
B10000,
B10000,
B10000,
B10000,
B10000,
B10000,
B10000};
byte bar2[8] {B11000,
B11000,
B11000,
B11000,
B11000,
B11000,
B11000,
B11000};
byte bar3[8] {B11100,
B11100,
B11100,
B11100,
B11100,
B11100,
B11100,
B11100};
byte bar4[8] {B11110,
B11110,
B11110,
B11110,
B11110,
B11110,
B11110,
B11110};
// grab each appropriate bar
byte* cols[4] = {bar1, bar2, bar3, bar4};

void setup() {
// Ultrasonic sensor pins
pinMode(triggerPin, OUTPUT);
pinMode(echoPin, INPUT);
// Serial Monitor
Serial.begin(9600);
// LCD Stuff
lcd.init();
lcd.backlight();
for (int i = 1; i < 5; i++) {
lcd.createChar(i, cols[i-1]);
}
}

void loop() {
static unsigned long timeSinceLastDisplay;
static int distance = 0;
static int numFullBars = 0;
static int partialBar = 0;
// want to only grab a new distance every so often, no delay is too fast
if (millis() - timeSinceLastDisplay > delayTime) {
distance = findDistance(triggerPin, echoPin);
timeSinceLastDisplay = millis();
}
lcd.setCursor(0,0);
lcd.print("Distance: ");
lcd.print(distance);
lcd.setCursor(14,0);
lcd.print("cm");

//lcd.setCursor(0,1);
//numFullBars =
}

// takes pins for the sensor, gives back the distance


int findDistance(int pinTrig, int pinEcho) {
int duration = 0;
// fire the trigger pin (but make sure its LOW first)
digitalWrite(pinTrig, LOW);
delayMicroseconds(2);
// must hold trigger pin high for 10 microsconds for the sensor's IC to
send out the high frequency pulse towards our object in question
digitalWrite(pinTrig, HIGH);
delayMicroseconds(10);
digitalWrite(pinTrig, LOW);
// pulseIn() returns the duraction of a pulse on a certain pin, in this
case our ECHO pin
// the echo pin is on for exactly how long it took for our singal to get
back (its a radar basically)
// pulseIN must be called a few dozen microseconds before said pulse,
but should be good. The onboard IC takes a bit to send the ultrasonic pulse
duration = pulseIn(pinEcho, HIGH);
// distance = speed*time; also divide by two since the pulse travels the
distance twice to get back to the sensor
// micro = 10^-6, speed of sound = 343 meters/second; so divide by 10^3
to get millimeters
return ((duration * 0.343) / 2);
}

Free Task:

For the free task Aaron and I settled on attaching the ultrasonic sensor to a servo and
“mapping” the surroundings to an LED matrix. The LED matrix is 8x8 and uses SPI to
communicate with the board. As it is 8x8, there are 8 “bars” to display a distance level and 8
levels to each bar. As there are 180 degrees in the servo and 8 possible bars, the bar sweeps in 22
degree windows, takes a running average of the distance in that range, and displays it as a bar on
the matrix. The code is simply looping through each window and in each window, looping
through all 22 degrees and using the following code to get a running average and check for
errors:
if (distance < 0 || distance > maxRange) {
distance = maxRange;
}
// only take running average if this isn't the first value
if (j != 0) {
distance = (distance + prevDistance) / 2;
}
// honestly don't need this but wanted to be sure we weren't hitting weird
stuff with no distance
if (distance == 0 ){
distance = 1;
}

The LED matrix is a bit funny. We ended up using the “LEDControl.h” library which was
pretty simple after some examples and documentation reading. The setup was copied from
documentation examples but seems to create on object with the pinout, set the intensity, tell it to
not shut down (interesting), and clear the display. The following command can write a byte to
any row in the array:
lc.setRow(0,i,bar[distance]);

The zero seems to be the address of the matrix, the second argument is the row, and the
third is the byte to be written. The array “bar” stores 9 different bytes, each a different length of
bar, and a blank bar. The distance value in the line above was mapped to a value between 0 and 8
so it can fit on the matrix.
Only real errors were with large/negative distances (which was fixed by the conditionals
above) and forgetting the pinMode() AGAIN (this was especially sad when we figured out what
was wrong). We also needed to add a clearDisplay() at the top of loop() to get rid of any
straggling LEDs.
/**
Microcontroller Systems Lab 5
Free Task
Jack Donovan
Aaron Wilson

An ultrasonic sensor attatched to a servo scans the full range of the servo. For
each row in an LED matrix,
it averages a bunch of distances in that window and prints a bar corresponding to
that distance

Found LED library here: https://docs.arduino.cc/libraries/ledcontrol/


Examples found here:
https://www.instructables.com/DIY-Customized-8x8-LED-Matrix-Tutorial-MAX7219-Mee/
**/

#include <Servo.h>
#include "LedControl.h"
const int servoDataPin = A0;
Servo myServo;
const int servoRange = 180;
// UltraSonic Pins
const int triggerPin = A2;
const int echoPin = A3;
// LED matrix size
const int numRows = 8;
const in numCols = 8;
// How many degrees per row of led matrix
const int clicks = 180 / 8;
// max distance we want to check at
const int maxRange = 250;
// led controll library object
LedControl lc=LedControl(6,7,5,1);
// array of loading bar bytes
byte bar[9] {B00000000, B10000000, B11000000, B11100000, B11110000, B11111000,
B11111100, B11111110, B11111111};

void setup() {
myServo.attach(servoDataPin);
// LED initialization
lc.shutdown(0,false);
lc.setIntensity(0,1);
lc.clearDisplay(0);
Serial.begin(9600);
// forgetting these SUCKS
pinMode(triggerPin, OUTPUT);
pinMode(echoPin, INPUT);
}

void loop() {
int position = 0;
int prevDistance = 0;
int distance = 0;
// make sure display is blank and servo is homed.
lc.clearDisplay(0);
myServo.write(0);

for (int i = 0; i < numRows; i++) {


// this loop runs over each angle in each window that goes to each row in the
matrix
for (int j = 0; j < clicks; j++) {
distance = findDistance(triggerPin, echoPin);
Serial.print("Interim Distance: ");
Serial.println(distance);
// next three conditionals make our value nice + takes a running average
if (distance < 0 || distance > maxRange) {
distance = maxRange;
}
// only take running average if this isn't the first value
if (j != 0) {
distance = (distance + prevDistance) / 2;
}
// honestly don't need this but wanted to be sure we weren't hitting weird
stuff with no distance
if (distance == 0 ){
distance = 1;
}
position++;
myServo.write(position);
//Serial.println(position);
prevDistance = distance;
Serial.print("Running Avg Distance: ");
Serial.println(distance);
}
// map the distacne to length of row
distance = map(distance, 0, maxRange, 0, numCols);
Serial.print("Average Mapped Distance: ");
Serial.println(distance);
//delay(1000);
// print appropriate "distance bar"
lc.setRow(0,i,bar[distance]);
}
}
// takes pins for the sensor, gives back the distance
int findDistance(int pinTrig, int pinEcho) {
int duration = 0;
// fire the trigger pin (but make sure its LOW first)
digitalWrite(pinTrig, LOW);
delayMicroseconds(2);
// must hold trigger pin high for 10 microsconds for the sensor's IC to send
out the high frequency pulse towards our object in question
digitalWrite(pinTrig, HIGH);
delayMicroseconds(10);
digitalWrite(pinTrig, LOW);
// pulseIn() returns the duraction of a pulse on a certain pin, in this case
our ECHO pin
// the echo pin is on for exactly how long it took for our singal to get back
(its a radar basically)
// pulseIN must be called a few dozen microseconds before said pulse, but
should be good. The onboard IC takes a bit to send the ultrasonic pulse
duration = pulseIn(pinEcho, HIGH);
// distance = speed*time; also divide by two since the pulse travels the
distance twice to get back to the sensor
// micro = 10^-6, speed of sound = 343 meters/second; so divide by 10^3 to get
millimeters
return ((duration * 0.343) / 2);
}

NOTEBOOK:

You might also like