Software documentation¶
Getting started¶
A guide for the electronics and mechanics team, when they need to test.
First of all, you’ll want to get a copy of the code. We’re using git for version control, so you can get that like this on the command line:
$ cd ~/idp_shared/<yourcrsid>
$ git clone ~/idp_shared/Common/repo.git
Initialized empty Git repository in /groups/IB/idp/idp-l205/efw27/repo/.git/
$ cd repo
After you’ve done this once, you should type the following every time the software team change the code:
$ cd ~/idp_shared/<yourcrsid>/repo
$ git pull
Useful programs¶
The following launches a keyboard interface for remote controlling the robot. Upon startup, it describes the key-mapping:
$ ./test t_remote
To test the competition code, use:
$ ./test t_all
Which allows you to enter the main routine at any point in the sequence
Calibration¶
To calibrate the eggsensor:
$ ./test dev/t_eggsensor_calib
constructed
initialized
Try and vary the ambient light while sampling
Place over brown egg, and hit enter
This program will expect you to place each egg until it in turn, and will take samples. Do this on the conveyor. Make sure to sample the edges of eggs as well as the centers. Also, spin the creme egg.
Running this will regenerate the egg_stats.cc
file. To check the calibration, run the following, which will show which eggs are being read:
$ ./test t_eggidentify
none
none
brown
...
When things go wrong¶
You’ll get errors if things aren’t working. A common one is:
terminate called after throwing an instance of 'LinkError'
what(): Host not found on network
./test: line 1: 22780 Aborted tests/$1.wifi
If this occurs, the robot is probably not yet powered. Wait for the blue LED. If all fails, pull the plug on it and try again.
Another one is:
terminate called after throwing an instance of 'PortError'
what(): Port P1 disconnected.
./test: line 1: 22780 Aborted tests/$1.wifi
Which indicates a missing or broken electronics board. You can debug further with:
$ ./test t_conns
constructed
initialized
Testing P1... Connected
Testing P2... Connected
Testing P3... Disconnected
If all fails, then the controller itself probably needs its power taken away.
TL;DR: turn it off and on again
Building the docs¶
This documentation is autogenerated. Building it is slightly involved, and won’t work on the department computers. It requires python and doxygen:
$ pip install breathe sphinx_rtd_theme # first time only
$ cd docs
$ doxygen
$ make html # or make.bat html on windows
The docs will be placed in docs/_build/html
.
Line following algorithm¶
-
void
followUntil
(Robot &r, float distance, linefollowTerminator *terminator = & until_junction)¶ Follow a line until an event.
For example:
followUntil(robot, 0.6, until_junction) // follow the line to a junction 60cm away followUntil(robot, 0.2, until_xjunction) // follow the line to a cross-junction 20cm away followUntil(robot, 0.2, until_bumper) // follow the line until the bumper is pressed 20cm away followUntil(robot, 0.2, NULL) // follow the line for exactly 20cm
- Parameters
r
: A reference to a Robotdistance
: The expected distance to drive, in meters, before the event occursterminator
: A function taking(Robot&, const LineSensors::Reading&)
that returns true when the robot should stop. If NULL, stop afterdistance
has been travelled
- Exceptions
LineLost
: The target line couldn’t be found, recovery failed.Timeout::Expired
: It’s taking more than 25% longer than expected to reach the target
-
void
turnAtJunction
(Robot &r, int turns, bool goForward = true)¶ Turns the robot at a junction.
- Parameters
r
: A reference to a Robotturns
: The number of 90 degree turns to go through, counter-clockwise being positive.goForward
:false
if the robot already has its wheelbase over the junction
- Exceptions
LineLost
: The target line couldn’t be found, recovery failed.
Color classification¶
The egg sensor reads four variables describing the egg. A range of similar eggs can be sampled to calibrate the sensor. From these readings, a normal distribution can be fitted to each variable and egg. Considering covariances, we can then generalize to a 4-variable normal distribution for each egg.
To identify the egg, the find the normal distribution with the highest probability density at a given point in variable-space.
The following steppable animation shows how this works for just two variables (red and blue).
The conversion of the raw recorded data to a set of normal distribution parameters is done with a small python script, that leverages the numpy numeric toolkit, and generates the egg_stats.cc file.
Api documentation¶
-
enum type
EggType
¶ Values:
-
std::array<MultivariateNormal<4>, EGG_TYPE_COUNT>
egg_stats::
expectations
¶ We model each egg as a normal distribution over all readings for that egg.
The four variables of the distribution are the red, blue, white, and ambient components of the reading
The parameters for these models are in egg_stats.cc, which is auto-generated by a python script from a set of calibration readings
- template <int N>
- struct
Represents a generalized normal distribution over N variables, described by the mean and covariance matrices.
Public Functions
-
double
MultivariateNormal::
mahalanobisDistanceSq
(Matrix<float, N, 1> value) const¶ generalization of \( \frac{x - \mu}{\sigma}^2 \) to N variables
-
double
Hardware access layer¶
To ensure hardware is operated correctly, each independant electronic subsystem is encapsulated in a class. This also allows us to make meaningful constructors and destructors, such as: setting up ports for inputs; turning off LEDs at shutdown; driving a motor slowly to hold the deliverer at startup.
These all get wrapped in a single Robot
instance, with members as
follows.
- struct
Actuators¶
Things which cause parts of the robot to move
- class
Interface to the two-wheeled drive system.
Inherits from Device
Public Functions
-
Drive::
Drive
(RLink &r, Configuration c = Drive::_defConfig)¶ Initialize a drive over a connection.
- Parameters
r
: the link to the robotc
: the drive geometry and speeds, used to populate Drive::maxSpeeds
-
void
Drive::
move
(move_args args)¶ Should ensure that abs(args.forward) + abs(args.steer) <= 1
- Parameters
args.forward
: non-dimensional linear speed: 1 is full speed forwards, -1 is full speed backwardsargs.steer
: non-dimensional rotational speed: 1 is full speed CCW
-
Timeout
Drive::
straight
(float dist, float speed = 1)¶ Move in a straight line, and return a timeout indicating expected completion.
-
Timeout
Drive::
turn
(float angle, float speed = 1)¶ Turn an angle on the spot, and return a timeout indicating expected completion.
-
void
Drive::
setWheelSpeeds
(float left, float right)¶ low-level motor access. Speeds should be between 1 and -1
-
void
Drive::
stop
()¶ shorthand for no motion
Public Static Functions
-
uint8_t
Drive::
convertSpeed
(float s)¶ convert floating point speed to sign/magnitude
- struct
Describes the physical configuration of the robot.
- struct
struct indicating maximum speeds, built from a Configuration
-
- class
Interface to the egg-grabbing arm of the robot.
Inherits from Device
- class
Interface to the runner holding the eggs, its indicator LEDs, the light gate that verifies the presence of an egg, and the bucket at the end of the runner which delivers the eggs into their cups.
Affectionately known as the courier, as it carries things
Inherits from Device
Public Functions
-
void
Courier::
recordEggAdded
(EggType e)¶ Indicate that a new egg has been added to the rail.
This updates the internal record of currently-held eggs, and turns on the appropriate LEDs.
-
void
Courier::
unloadEgg
()¶ Unload the egg at the bottom of the stack, updating state and LEDs.
-
int
Courier::
volume
() const¶ The number of eggs on the rail.
-
bool
Courier::
eggDetected
() const¶ if an egg is at the bottom of the courier
-
void
Sensors¶
Things which give the robot information about its surroundings
- class
Interface to the LEDs and LDR comprising the egg sensor.
Includes the algorithm for identifying eggs
Inherits from Device
- struct
Public Members
-
uint8_t
EggSensor::Reading::
r
¶ reflection from red LED
-
uint8_t
EggSensor::Reading::
b
¶ reflection from blue LED
-
uint8_t
EggSensor::Reading::
w
¶ reflection from white LED
-
uint8_t
EggSensor::Reading::
a
¶ ambient reading
-
std::array<float, EGG_TYPE_COUNT>
EggSensor::Reading::
probabilities
¶ “distances” to each egg. Lower values indicate greater likelihood
-
uint8_t
- class
Interface to the three front-mounted line sensors.
Inherits from Device
- struct
Public Members
-
bool
LineSensors::Reading::
lsl
¶ left sensor reading
-
bool
LineSensors::Reading::
lsc
¶ right sensor reading
-
bool
LineSensors::Reading::
lsr
¶ center sensor reading
-
bool
LineSensors::Reading::
lsa
¶ arm sensor reading
-
float
LineSensors::Reading::
position
¶ Line position, where between -1 and 1, with left positive.
+-Inf and NaN indicate a lost line
-
bool
- class
Interface to the limit switch bumper on the front of the robot.
Inherits from Device
- struct
For ease of debugging, some of these readings have ostream <<
overloads, to
allow:
std::cout << robot.ls.read() << std::endl
Low level¶
All of the above classes use the following utility classes to interface with the hardware.
- class
Wraps robot_link to indicate failures by throwing a LinkError object.
Inherits from robot_link
- class
Base class for all devices which require a link to the robot.
Subclassed by Arm, Bumper, Courier, Drive, EggSensor, LineSensors, Port
-
type
port::
Name
¶ An enum of port names, from
P0
toP7
, andPA0
toPA7
- class
Interface to a set on pins on a particular port.
Allows masking of pins, to allow multiple
Device
s to share a I2C port without interfering with each other’s bitsProvides operator overloading for simple use:
Port sensor(rlink, port::P2, 0xF); // bottom 4 bits of port 2 uint8_t reading = sensor; // read sensor sensor = 0x42; // write to sensor
Note that conversion to an int will return the current input, which is not necesarily the previous output
Inherits from Device
Public Functions
-
Port::
Port
(RLink &r, port::Name p, uint8_t mask = 0xFF)¶ Create a port over the connection
r
, using the port with addressp
.Optionally specify a set of bits
mask
to restrict the scope of this instance to. Throws PinsDoublyMapped if multiple instances attempt to use the same ports
-
Port::
operator uint8_t
() const¶ Read a word to the port, keeping only the bits specified in the mask.
-
void
Port::
operator=
(uint8_t val)¶ Write a word to the port, touching only the bits specified in the mask.
-
Exceptions¶
To prevent errors silently occuring without being noticed (or worse, error codes being handled as values), exceptions are used for all critical errors. These all derive from std::exception, and implement the const char* what() member to give a brief summary of the error to the programmer, to allow them to fix the appropriate electrical/network problem.
- class
Thrown when an RLink command or request goes wrong.
Contains the original error code
Inherits from exception
Subclassed by PortError
Public Functions
-
virtual const char *
LinkError::
what
() const¶ override of std::exception::what()
-
virtual const char *
- struct
Specialization of LinkError, thrown when an I2C error occurs when accessing a port.
Typically implies loss of electrical connection
Inherits from LinkError
Public Functions
-
virtual const char *
PortError::
what
() const¶ override of std::exception::what()
-
virtual const char *
- struct
Specialization of LinkError, thrown when an I2C error occurs when accessing a port.
Typically implies loss of electrical connection
Inherits from exception
Utilities¶
- class
Class for keeping track of expected times for operations.
Example usage:
using namespace std::literals::chrono_literals; Timeout timeout(2s); try { doAThing(); timeout.check(); do { keepGoing(); timeout.check(); } while (stillGoing()) } catch(Timeout::Expired) { std::cout << "took too long" << std::endl;
Public Functions
-
Timeout::
Timeout
(duration_type duration)¶ create a timeout
duration
in the future
-
Timeout::
Timeout
(clock::time_point end)¶ create a timeout ending at
end
-
void
Timeout::
wait
() const¶ wait for the timeout to expire
- class
Inherits from exception
-
- class
Heirarchical logger, use to produce indented logs.
- class