ENGR-2350 Embedded Control Lab04: Driving Around
Embedded Control Laboratory 4
Driving Around
SIMULATED LABORATORY
→ Readings
• Lab Manual: Chapter 7 - Control Algorithms
→ Laboratory Goals
General
• Provide an introduction to developing an autonomous system using proportional control tech-
niques informed by sensors.
Hardware
• ...
Software
• ...
→ Motivation
In lab 3, the tools needed for building a Smart Car capable of autonomous control were developed. In this
lab, these tools will be combined to achieve a specific goal without user intervention.
Revision: 1.0 1 ENGR-2350: Spring 2020
ENGR-2350 Embedded Control Lab04: Driving Around
→ General Lab Description
This lab consists of using the Ranger and Compass sensors to inform an algorithm to drive the Smart Car
from a starting position to an end position while interacting with an obstacle. The start and end positions
used by the simulator are procedurally generated using the student’s RIN number, which should be given
at the top of their code (see template code). The car also has a third I2C device connected to it, the
“wireless actuator.” The ranger is pointing horizontally forward of the car in order to detect the obstacle
approaching.
The algorithm for this lab should have the Smart Car start driving directly towards an obstacle. This
requires the car to turn towards that heading and continue following that heading until it approaches the
obstacle. When approaching the obstacle, the car should start slowing down and stop at 60 cm. The car
should reverse with the same proportionality if closer than 60 cm. The distance at which the car starts
slowing down is controlled by the proportional gain constant. When the car reaches a stop, it should (a)
continue to monitor the distances between it and the obstacle, and adjust, (b) tell the wireless actuator to
start (discussed below), and (c) check the state of a pushbutton. Once the pushbutton has been pressed,
the car should first tell the wireless actuator to stop and then start a maneuver to drive around the obstacle:
the car should reverse and turn in either direction (your pick) using the maximum or minimum pulsewidth.
The car should reverse for a fixed amount of time (again, your pick), then drive straight forward for a
fixed amount of time (your pick), and then follow a heading that will take the car to the end position. The
simulation will stop and indicate success when the car completes the course.
Throughout the process as described above, the motor speed should always be a function of the ul-
trasonic ranger’s reading except for when reversing after the button press. Likewise, the steering should
always be a function of the compass except for when maneuvering around the obstacle.
Determination of the initial and final heading values, as well as the reverse/forward maneuvering tim-
ings, should be informed from the simulation (trial and error). You will need to run the simulation at least
once with non-working code to determine the initial guesses for the heading requirements. Additionally,
the pushbutton pin will also be given within the simulation.
A slide switch (P3.0) should be configured to enable/disable both the drive motor and the steering
servo. The crossbar should be specified the same as done in Lab3, with the servo connected to CEX0 and
the drive motor on CEX2. The LED and light sensor are not used.
The ranger and heading values as well as the motor and servo pulsewidths should be outputted and
stored for plotting and analysis in the end-of-semester “Summary Report.” Additionally, the timing of
each output should be either given or known in order to interpret the data properly.
→ Wireless Actuator
The so-called “wireless actuator” is an I2C device (address 0x42) that wirelessly connects to a control
system on another device. The registers contained within the device are described in the table below. The
Start/Stop register which must be used in the control algorithm, will start the actuator if 0x01 is written
to it. Stopping the actuator consists of writing 0x00. Any other value will be discarded. What does it do?
You’ll find out.
Revision: 1.0 2 ENGR-2350: Spring 2020
ENGR-2350 Embedded Control Lab04: Driving Around
Register Write Function Read Function
0 Change ID Read ID
1 Start/Stop Software Revision
2 - Current Speed (-128-127)
3 - Current Direction (0-255)
→ General Lab Guidance
• The laboratory functionality as described previously can be easily broken into several smaller pieces
to produce an algorithm. This code written for this can be approached in several ways. Two possible
methods are discussed in the following section, though another other method that achieve the end
goal is acceptable as well. The pre-lab pseudocode should reflect these “smaller pieces.”
• Detection of the “stop” condition in the described algorithm should be done through monitoring the
pulsewidth of the drive motor. Considering that a perfect stop may never be achieved, it is suggested
that a small range of pulsewidths around the neutral position be considered “stopped.”
• Since this laboratory is an individual exercise, template code is provided to as a starting point for
implementation of the ranger, compass, motor, and servo codes.
• Ensure that your RIN is added at the top of your code. If using the template code, replace the
placeholder value. If writing from scratch or continuing from Lab3-3, implement the define statement:
#define RIN xxxxxxxxx // Must be above #include"C8051_SIM.h"
• The proportional gain constants for the motor and servo should be selected to provide smooth
operation of the car. Note that both the simulated ranger and compass sensor values have random
noise (gaussian). Gain values which are too large will overreact to this noise. Too small gain values
will not allow the car to operate properly.
• In addition to the random noise applied to the compass, the simulated magnetic field also has broad
variations. The “north” arrow in the simulator may be dragged around to indicate the magnetic field
at a specific point.
• It is your responsibility to ensure that all goals of the lab are implemented completely. The car must
approach the obstacle to be considered successful. The simulation does not check this.
• Storing the printf() output to file may be done by adding this define to your code:
#define SAVETOFILE "FILENAME.csv" // Must be above #include"C8051_SIM.h"
Note that the terminal will not print out anything with this define active except for the C8051_SIM.h
version number and a save-to-file warning. The file will be saved in the directory where the program
is compiled to (usually in ProjectFolder\bin\Release\). Warning : This file is overwritten each time
the program is run.
• Thanks to a student patch, getchar() is now available for use if desired. UPDATE: Not available
on Windows!
Revision: 1.0 3 ENGR-2350: Spring 2020
ENGR-2350 Embedded Control Lab04: Driving Around
→ Sample Code Topologies
Method 1: Linear Progression
This code topology consists of running chucks of code in a prescribed order. Each chuck of code, referred to
as a “mode” here, is self contained and performs all necessary functions of the system. This method may
be more intuitive for simple systems; however, the implementation may become messy and cumbersome
as the system complexity increases. Below is an example implementation using functions for each mode:
void main(void){
...
mode1();
mode2();
...
modeDone();
}
void modeN(){
while(1){ \\ Run this mode until next mode needed
\\ Do stuff that happens in every mode
\\ Do modeN stuff
if(???){ \\ Check if mode is complete
break; \\ or return;
}
}
}
Method 2: Finite State Machine
This code topology consists of running the same while(1) loop over the entire course of the car driving.
The active “state” of the system is tracked and functionality needed in each state is activated through a
set of if/else statements or a switch statement. In each state, the conditions to advance to the next state
are checked and the state is changed as necessary.
Example using if/else statements:
unsigned char state = 0;
...
while(1){
\\ Do stuff that must happen every time
\\ For example: Reading sensors
if(state == 0){
\\ do state 0 stuff
\\ check for state change
}else if(state == 1){
\\ do state 1 stuff
Revision: 1.0 4 ENGR-2350: Spring 2020
ENGR-2350 Embedded Control Lab04: Driving Around
\\ check for state change
\\ Add more states as needed
}else if(state == n){
\\ done. Don’t do anything?
}else{
\\ Handle situation if state unknown
\\ This can usually be omitted
}
}
Example using switch statement:
unsigned char state = 0;
...
while(1){
\\ Do stuff that must happen every time
\\ For example: Reading sensors
switch(state){
case 0:
\\ do state 0 stuff
\\ check for state change
break;
case 1:
\\ do state 1 stuff
\\ check for state change
break;
\* Add more states as needed *\
case n:
\\ done. Don’t do anything?
break;
default:
\\ Handle situation if state unknown
\\ This can usually be just a break
break;
}
}
Revision: 1.0 5 ENGR-2350: Spring 2020