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

Public Functions

Public Members

Drive Robot::drive
Arm Robot::arm
LineSensors Robot::ls
EggSensor Robot::detector
Courier Robot::courier
Bumper Robot::bumper

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 robot
  • c: 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 backwards
  • args.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 Members

Speeds Drive::maxSpeeds

The maximum speeds the robot is able to acheive.

Public Static Functions

uint8_t Drive::convertSpeed(float s)

convert floating point speed to sign/magnitude

struct

Describes the physical configuration of the robot.

Public Members

float Drive::Configuration::radius

wheel radius, in m

float Drive::Configuration::spacing

distance between centers of wheels, in m

float Drive::Configuration::rpm

motor speed, in rpm

struct

struct indicating maximum speeds, built from a Configuration

class

Interface to the egg-grabbing arm of the robot.

Inherits from Device

Public Functions

Arm::Arm(RLink &r, port::Name name)
void Arm::up()
void Arm::down()
void Arm::open()
void Arm::close()
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.

EggType Courier::egg(int n) const

type of the egg n from the bottom

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

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

Public Functions

EggSensor::EggSensor(RLink &r, port::Name port)
EggSensor::Reading EggSensor::read(int samples = 5)

read the sensor, taking an average over multiple samples

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

EggType EggSensor::Reading::bestGuess

shorthand for most likely egg type

class

Interface to the three front-mounted line sensors.

Inherits from Device

Public Functions

LineSensors::LineSensors(RLink &r, port::Name p)
LineSensors::Reading LineSensors::read()
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

class

Interface to the limit switch bumper on the front of the robot.

Inherits from Device

Public Functions

Bumper::Bumper(RLink &r, port::Name port)
Bumper::Reading Bumper::read()
struct

Public Members

bool Bumper::Reading::left

left switch is pressed

bool Bumper::Reading::right

right switch is pressed

float Bumper::Reading::position

1 for left, -1 for right, 0 for straight, and NaN for not pressed

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.

Wraps robot_link to indicate failures by throwing a LinkError object.

Inherits from robot_link

Public Functions

void RLink::initialise()

Initialise the link by the most appropriate method for the location the code is running.

void RLink::command(command_instruction cmd, int arg)

Send a command to the robot.

int RLink::request(request_instruction req)

Request data from the robot.

uint8_t RLink::status()

Get the status register, a bitfield containing {comm_err, i2c_err, es_trig, es_mode, moving, ramped, _, _}

Does not throw LinkError

class

Base class for all devices which require a link to the robot.

Subclassed by Arm, Bumper, Courier, Drive, EggSensor, LineSensors, Port

Protected Attributes

RLink &Device::_r

internal reference to a robot connection

type port::Name

An enum of port names, from P0 to P7, and PA0 to PA7

class

Interface to a set on pins on a particular port.

Allows masking of pins, to allow multiple Devices to share a I2C port without interfering with each other’s bits

Provides 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 address p.

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()

Public Members

const link_err LinkError::err

The original error code.

const bool LinkError::is_fatal

Whether the error is marked as fatal by robot_link.

const bool LinkError::is_i2c

If true, indicates that the error has no code, and is instead a bus error.

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()

Public Members

const port::Name PortError::port

the disconnected port

struct

Specialization of LinkError, thrown when an I2C error occurs when accessing a port.

Typically implies loss of electrical connection

Inherits from exception

Public Members

const port::Name PinsDoublyMapped::port

the port causing the issue

const uint8_t PinsDoublyMapped::pins

the mask of pins that have already been allocated