Autonomous Flexibity

Creating Flexible, Script-Controlled
Autonomous Software
My Name: Chris Hibner
Mentor FRC 51 - Wings of Fire
 Control
Systems Engineer
 Involved with FIRST for a LONG time
 Plenty of industry experience
 Cool Degrees (Go Blue!)
chiefdelphi.com: “Chris Hibner”
Why should I care about this?
1. Flexibility: do you really know what the
optimal autonomous routine is?
2. Fast changes: no need to compile and
deploy code.
3. “Building Block” method: easy to break the
problem into small, manageable chunks.
4. Expandability: easy to add more features if
you deem necessary.
 It
is not a magic bullet to solve all of your
autonomous problems.

It is simply a method of organizing your software.
 The
method presented here is not the only
way to accomplish scripted autonomous
 Most likely, it is not the best way.
 It is a fairly simple way (and highly
effective).
 The


“Primitive”, or building block.
It is a single, simple move that you program your
robot to do – usually a driving maneuver.
Think of it as a toolbox or a bag of tricks
 What
are some primitives that you would
want in your autonomous software?
Ex:
1.
2.
3.
4.
5.
Delay / Do Nothing
Drive straight
Turn in place
Go to X,Y coordinate
etc.
 How
to transition from one primitive to the
next?



Exit conditions must be defined for each primitive
What would be the exit conditions for the
primitives we decided on?
CAVEAT: What if you can’t get to the exit condition?
 What


parameters are needed by the primitives?
Operating parameters (heading, distance, power,
etc.)
Exit Conditions
 Each
primitive is like a function or class.
 Parameters are passed to the primitive like
arguments to a function

Ex: straight(heading, distance, power)
 The
primitives are selected and the
parameters are passed to the primitive via a
simple script.

Therefore: no need to change your software: just
change the script!
 Each
primitive is assigned a unique ID number
(enumeration).
 Each primitive has numeric parameters.
 Since we only need numeric data, a matrix (2-D
Array) can be used to represent the script.
 Each column of the script is one primitive




1st entry: primitive ID
2nd entry: parameter 1
3rd entry: parameter 2
Etc.
 Number
of entries in each column depends on
the maximum number of parameters.
 The
script is a matrix (2-D Array)
 Each column represents one primitive
 Example:
1st primitive
1st column:
Starting position
ID
param1
param2
.
.
.
.
0
261
203
0
0
2
0
1
0
15
0.5
0
0
0.4
0
0
250
0.5
0
0
0.4
2
10
500
1
0
0
0.4
2
10
1500
0.5
0
1
0.4
 Example
script means the following:
 Column 1: Start at Hdg = 0; X = 261; Y = 203
 Column 2: Drive Straight (ID 1), Hdg = 0, for
15 inches, power = 0.5, Roller at 0.4.
ID
Hdg
dist/time
power
kick
roller
0
261
203
0
0
2
0
1
0
15
0.5
0
0
0.4
0
0
250
0.5
0
0
0.4
2
10
500
1
0
0
0.4
2
10
1500
0.5
0
1
0.4
 Column
3: Do Nothing (ID 0) for 250 msec.
 Column 4: Hold Position (ID 2), Hdg = 10 deg,
for 500 msec, Max power = 1.0.
 Column 5: Hold Position, Hdg = 10 deg, for
1500 msec, kick ball
ID
Hdg
dist/time
power
kick
roller
0
261
203
0
0
2
0
1
0
15
0.5
0
0
0.4
0
0
250
0.5
0
0
0.4
2
10
500
1
0
0
0.4
2
10
1500
0.5
0
1
0.4
 The
script can be as long or as short as you
want. Each script can be different.
0
1
0
2
261 0
0 10
203 15 250 500
0 0.5 0.5 1
0
0
0
0
2
0
0
0
0 0.4 0.4 0.4
 The
file.
2
2
10 0
1500 1000
0.5 1
0
0
1
0
0.4 0.4
1
7
5
6
2
2
2
0 391 391 0.3 -77 -77 -77
65 174 174 500 1000 1000 500
0.5 0.75 0.65 0.2 2
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
-0.3 0
0
0
0
0
0
script is stored on the cRIO as a .CSV
First column is used to tell the autonomous program where the robot is starting (Heading and X and Y Coordinates). See be
use as many primitives as you wish
Primitive ID:
Desired X:
Desired Y:
Desired Heading:
Power Level or Time:
Desired Elevator:
Desired Arm:
Upper Claw PWM:
Lower Claw PWM:
Reserved:
0
410
222
0
0
0
0
0
0
0
1
470
200
0
0.5
90
70
0
0
0
Primitive ID Quick Key:
0 Delay/Coast
1 Drive to XY full speed
2 Drive to XY gradual approach
3 Hold XY Position
4 Turn to heading
5 Drive Timed Open Loop
6 Line Follow
2
480
200
0
0.5
90
70
0
0
0
2
485
200
0
0.5
90
70
0
0
0
3
485
200
0
1000
90
70
-0.6
-0.6
0
1
480
200
0
0.3
90
70
-0.6
-0.6
0
2
425
175
0
0.5
0
-100
0
0
0
3
420
175
0
1000
0
-100
0.6
0.6
0
3
425
175
0
50
0
60
0.5
-0.5
0
2
480
150
0
0.5
90
70
0
0
0
2
485
150
0
0.5
90
70
0
0
0
 Column
index is the key! – this selects the
primitive and parameters from the matrix.
0
261
203
0
0
2
0
1
0
15
0.5
0
0
0.4
0
0
250
0.5
0
0
0.4
2
10
500
1
0
0
0.4
2
10
1500
0.5
0
1
0.4
 Use
a “Case Structure” or “switch/case”
 Each “Case” <==> one primitive
 Each case is numbered: set each case
number to the primitive ID you selected.
 In each case, put your code for that primitive
(or call a function for the primitive) – don’t
forget the exit condition logic in your code.
 In each primitive, when you reach the exit
condition, increment the array column index.

After incrementing the index, the next primitive
happens automatically – like magic
 ColumnIndex
1
0
15
0.5
0
0
0.4
= 1:
ColumnIndex = 2:
0
0
250
0.5
0
0
0.4
 In
your software, when you reach the exit
condition of one primitive:

Increment ColumnIndex (ColumnIndex++)
 Next
primitive will start “automagically”
 Cycling
0
261
203
0
0
2
0
ColumIndex:
through the primitives:
1
0
15
0.5
0
0
0.4
1
0
0
250
0.5
0
0
0.4
2
10
500
1
0
0
0.4
2
3
2
10
1500
0.5
0
1
0.4
4
// atnArr is the autonArray
// ind is the column index
1
0
15
0.5
0
0
0.4
switch (atnArr[0][ind])
{
case 0:
ind = delay(atnArr[1][ind],atnArr[2][ind]);
break;
case 1:
ind = straight(atnArr[1][ind],atnArr[2][ind]);
break;
Etc...
uint8 ind = straight(float desiredHdg, float dist)
{
const float speed = 0.7;
float turn = PID(desiredHdg, Hdg);
rightDrive = (speed + turn);
leftDrive = (speed – turn);
// exit condition:
if (encoderDist >= dist)
{
ind++;
}
return ind;
}
 Separate
2-D array into each row:
 Index
into each parameter via the Index:
 Use
Case Structure (C++: switch/case)
 Each case is a primitive.
 Number each case with the primitive ID.
 In each case, put your code for that primitive
– don’t forget the exit condition logic.
 Start autonomous with array index = 0 or 1
(depending if you use the first column for
starting position).
 In each primitive, when you reach the exit
condition, increment the array index.
 The next primitive starts automatically.
 cRIO
file structure:
 How
 Use
to read a file in the cRIO:
Read From Spreadsheet File.vi
 AutonArray is our 2-D array
 Getting

the scripts to the cRIO: FTP
FileZilla is free
 Let’s
make a script for our autonomous code
and run it in simulation.
 Shameless
here.
plug for tomorrow’s presentation
1.
2.
3.
4.
Create your autonomous code in a sub-vi.
Put your sub-vi in
AutonomousIndependent.vi
Hook up inputs (sensor readings) and
outputs (motor commands) to your sub-vi.
Wrap a “while loop” around everything.
(That’s all there is to it)
 Why:
Add flexibility / fast autonomous changes
 How: Determine your primitives
 Determine primitive parameters – don’t forget
exit conditions.
 Create Case Structure – one case for each
primitive.
 Use 2-D array as a script to control the
autonomous software
 Primitive is determined by the column index.
When you exit one primitive, increment the
column index and the next primitive starts
automatically.
 Spreadsheet
program, such as Excel or
OpenOffice Calc
 FTP software (such as FileZilla)
 Simulation program is nice to have.

2nd shot at shameless plug
 Presentation
material and sample software
will be posted on chiefdelphi.com in CDMedia/Papers area.
 Feel free to send me a PM on
chiefdelphi.com : “Chris Hibner”