Tuesday, September 3, 2019

Middle School Robotics Classes with Johnny-Five


Last summer, I was offered the opportunity to hold robotics classes at a nearby middle school. I jumped at the chance because it would allow me to have complete control over the curriculum. I had already spent several years helping with a high shool's FIRST Robotics Competition (FRC) team, but I was starting to feel constrained by the rules and expectations of the games. This time, there would be no need to balance the students' fun and education with success at regional competitions.
   Not to say that there weren't downsides. While at least one other mentor was present to help the students, none of them had any previous experience with robotics. Classes were held in a normal middle school classroom with no access to any tools or parts. The school provided computers to all students, but they were locked-down Chromebooks that I couldn't install any additional software on.
   These conditions led us to use the Sparkfun Inventors Kit 4.0 as a base for the hardware. It's relatively affordable and comes with all the parts needed to assemble a simple driving chassis. The electronics include the RedBoard, which is Sparkfun's Arduino Uno clone, and a handful of sensors, LEDs, buttons, and switches. A nice printed manual with step-by-step instructions and lots of illustrations is also provided. We rarely used it in our classes, but it did provide inspiration and guidance when planning the projects. The only flaw was the flaky ultrasonic rangefinders, but those have since been upgraded in the new 4.1 version of the kit.
   Most of the students had already been introduced to Javascript programming in previous classes, so we wanted to keep using the language to program the RedBoard. The Johnny-Five Node.js library was the obvious solution for us due to its compatibility with a large range of peripherals and excellent documentation. There is also a convenient Chrome app that packages the library with a simple UI. We used this app all through the first round of classes, but frequent bugs and inability to save code to the filesystem drove me to adopt a different approach. I got out a stack of old laptops that I had accumulated over the years and installed Linux and Johnny-Five on them. Students would use the built-in text editor (either mousepad or gedit) to write code, save them to files on the desktop, and drag the files to a special icon that would invoke Johnny-Five to connect to the Arduino and run the program.


   After assembling the parts and software, the next big challenge was to think of an fun projects for the students. Middle school kids lose interest a lot faster than the high schoolers I was used to, especially after a long 6-hour day of classes. I initially started each class with a short slideshow on the technology relevant to the following project, but this failed to make much of an impression. Later, I began class with the first part of the project, and after their interested was piqued by the new sensor  or actuator, I would follow up with an explanation about it that would be needed to finish the rest.


   The projects increased in complexity until the students could assemble a driving robot that used an ultrasonic rangefinder to navigate. For the first course, the robot was supposed to follow a hand that was placed in front of it. This turned out to be a exciting way to physically interact with the robot and learn how to build up complex logic in Javascript. The fun and challenge both increased in the second course. The robot hardware ended up mostly identical, but the assigned task was to navigate through a simple walled course. Teams were encouraged to finish the course in the least amount of time. The sense of competition infused much more energy and focus into the students than ever before. I am still reluctant to admit it, but the prospect of winning or being the best is a crucial motivator for many people.


   Although it was hard work, I thoroughly enjoyed running my first robotics classes. My fellow mentors were extremely helpful and encouraging; the lessons wouldn't have been nearly as effective without their assistance. Though the students were sometimes hard to control, they were truly inspiring with the energy that they brought to the class. Some even engineered novel solutions that I had never considered and asked thought-provoking questions that led me down rabbit holes I wouldn't have otherwise explored. In all seriousness, I'm hopeful that this experience will encourage them to use technology to improve the future.

Wednesday, August 1, 2018

Introduction to Robotics Programming in C++

Despite many distractions and just plain lethargy, work still progresses at a slow pace on the FIRST Robotics Competition C++ learning framework that I introduced previously. I still think that it can provide an accessible and engaging experience for students learning robotics and programming in a way that will teach them how to contribute to the code on a real FRC robot. The RedBot still exists (though it's now sold with a black chassis), and the code that I'm writing to emulate WPILib for it is still here on GitHub. Now that it covers more of the WPILib API, I do want to do some major refactoring to improve the organization and modernize the C++. I also want to investigate integrating the project with GradleRIO somehow to make it easy for others to download and build it and its dependencies. First, though, I thought I should publicly demonstrate some of the framework's capabilities and give an example lesson based on it that starts with basic driving and builds up to following a line drawn on a flat surface.

Driving Forward


The first thing to do is to just make the robot move using its drive motors. In this example, the robot will drive forward by applying an equal amount of power to both motors when it's in Autonomous Mode. In Disabled Mode, it will stop the motors by setting the power to zero. The code to do so is below.

#include <WPILib.h>

class Robot : public frc::IterativeRobot
{
private:

  RedBotSpeedController myLeftMotor;
  RedBotSpeedController myRightMotor;

public:

  Robot() :
    myLeftMotor(0),
    myRightMotor(1)
  {
  }

  void AutonomousInit()
  {
    myLeftMotor.Set(0.6);
    myRightMotor.Set(0.6);
  }

  void DisabledInit()
  {
    myLeftMotor.Set(0.0);
    myRightMotor.Set(0.0);
  }
};

START_ROBOT_CLASS(Robot);

Deploy this program to the robot and enable Autonomous Mode to start the robot driving forward. Be sure to keep a finger on the Disable button so the robot doesn't drive off the table.


Once the robot starts moving, it may not keep a completely straight course, even though equal amounts of power are specified for both motors in the code. This will be addressed in later sections of this tutorial.

Breaking down the Code


Here's an in-depth analysis of the whole code.

#include <WPILib.h>

This includes the code libraries needed to make the robot perform actions as well as to retrieve data from the robot. In this example, we use the speed controller class defined in these libraries to set motor power. All programs for the robot need to begin with this line.

class Robot : public frc::IterativeRobot
{

This begins the robot class, which contains variables for robot parts and methods that perform actions with the variables. There are two main parts to this class declaration: the name of our class, which is simply "Robot", and the public derivation from the base class "frc::IterativeRobot". The Robot class derives from frc::IterativeRobot so that it can use the methods and variables already defined in it. Deriving from this class is also required for every robot program.

private:

  RedBotSpeedController myLeftMotor;
  RedBotSpeedController myRightMotor;

Here, the speed controller variables are declared inside the Robot class. The RedBotSpeedController class represents a controller for the drive motors on the robot. The main purpose of a speed controller in this program is to specify how much power should be applied to its motor. There are two objects of this class in our program: one for the left motor, and one for the right motor. These objects are declared in the "private" section of the Robot class so that nothing outside the Robot class can access them.

public:

  Robot() :
    myLeftMotor(0),
    myRightMotor(1)
  {
  }

Now the "public" section of the Robot class is started. In this section, methods and variables are accessible by code outside the class. The first thing defined here is the Robot class constructor, which is a special method that runs whenever a new object of the Robot class is created. The only thing this constructor does  is to construct the speed controller objects that we declared above. The speed controller constructors require a single numerical argument that specifies the channel on the main control board that they're connected to. In every robot program, the left controller must always be constructed with channel 0, and the right controller must always be constructed with channel 1. This ensures that whatever speed is set for the controller in the following code is applied to the correct physical motor.

  void AutonomousInit()
  {
    myLeftMotor.Set(0.6);
    myRightMotor.Set(0.6);
  }

This is the code that makes the robot move when Autonomous Mode is enabled. The method AutonomousInit is inherited from frc::IterativeRobot (from which this Robot class is derived from, as explained above) and is called once whenever the robot switches to Autonomous Mode from Disabled Mode. In the method's body, the speed controller objects are used to set a speed of 0.6 on both motors. Since 0.6 is a positive number, this will cause the robot to drive forward (a negative number would cause the robot to drive backwards). The robot will continue driving forward at this speed until a new speed is set on the controllers.

  void DisabledInit()
  {
    myLeftMotor.Set(0.0);
    myRightMotor.Set(0.0);
  }
};

To stop the robot when switching to Disabled Mode from Autonomous Mode, zero speed is set for both motors. This causes the motors to stop immediately; no coasting should occur. Just like the AutonomousInit method, the DisabledInit method is inherited from frc::IterativeRobot and runs once whenever the robot is disabled (as well as when the robot program first starts up). The curly brace and semicolon ("};") following the DisabledInit method conclude the Robot class.

START_ROBOT_CLASS(Robot);

Finally, this macro call specifies that the Robot class defined above should be used as the main program for the robot. Again, this line is required for all robot programs.

Turning


Try changing the motor speed values in the above program to make the robot turn rather than drive forward. Which values are needed to make it turn left, and which make it turn right? Which values make the robot turn about its center, and which make it turn about one side?


Using Timers


Instead of driving the robot forever or until it falls off the end of the table or until the Disable button is pressed, it may be helpful to use a timer to figure out when to stop. For this purpose, the Timer class comes in handy. An example of how to use it is shown below.

#include <WPILib.h>

class Robot : public frc::IterativeRobot
{
private:

  RedBotSpeedController myLeftMotor;
  RedBotSpeedController myRightMotor;
  enum DriveState { FORWARD, STOP_FORWARD, BACKWARD, STOP_BACKWARD };
  DriveState myState;
  frc::Timer myTimer;

public:

  Robot() :
    myLeftMotor(0),
    myRightMotor(1)
  {
  }

  void AutonomousInit()
  {
    myTimer.Stop();
    myTimer.Reset();
    myTimer.Start();

    myLeftMotor.Set(0.6);
    myRightMotor.Set(0.6);
  }

  void AutonomousPeriodic()
  {
    if (myTimer.HasPeriodPassed(2.0) == false)
      {
return;
      }

    double speed = 0.0;

    switch (myState)
      {
      case FORWARD:
speed = 0.0;
myState = STOP_FORWARD;
break;

      case STOP_FORWARD:
speed = -0.6;
myState = BACKWARD;
break;

      case BACKWARD:
speed = 0.0;
myState = STOP_BACKWARD;
break;

      case STOP_BACKWARD:
speed = 0.6;
myState = FORWARD;
break;
      };

    myTimer.Stop();
    myTimer.Reset();
    myTimer.Start();

    myLeftMotor.Set(speed);
    myRightMotor.Set(speed);
  }

  void DisabledInit()
  {
    myLeftMotor.Set(0.0);
    myRightMotor.Set(0.0);
  }
};

START_ROBOT_CLASS(Robot);

Just as in the first example, build and deploy this program and enable Autonomous Mode to move the robot. The robot should drive forward for 3 seconds, stop for 1 seconds, drive backward for 3 seconds, and repeat.


Breaking Down the Code


This program is a little more complicated not only because it uses a Timer object, but because it also has a state machine to govern the robot's movement. A state machine is a useful coding pattern whenever the robot has to go through a sequence of steps. It can usually be written using a state variable and a switch statement.

class Robot : public frc::IterativeRobot
{
private:

  RedBotSpeedController myLeftMotor;
  RedBotSpeedController myRightMotor;
  enum DriveState { FORWARD, STOP_FORWARD, BACKWARD, STOP_BACKWARD };
  DriveState myState;
  frc::Timer myTimer;

Just as in the first example, the two speed controllers are declared using RedBotSpeedController objects. Following those, an enum (short for "enumeration") is declared to list all of the possible states that the robot can be in: moving forward, stopping in the forward position, moving backward, and stopping in the backward position. In this program, the robot is meant to cycle through all of these states in the order shown above, using the timer to remain in each state for a certain amount of time. The current state variable myState is declared as a type of the same name as the enum (DriveState). Finally, the timer itself is declared as an object of frc::Timer.

public:

  Robot() :
    myLeftMotor(0),
    myRightMotor(1)
  {
  }

The constructor here initializes both speed controllers. Since the state variable and timer object do not need to be constructed with an argument, they are not listed here.

  void AutonomousInit()
  {
    myTimer.Stop();
    myTimer.Reset();
    myTimer.Start();

    myState = FORWARD;
    myLeftMotor.Set(0.6);
    myRightMotor.Set(0.6);
  }

The AutonomousInit method now has more code in it to set up the timer and state to begin the Autonomous mode. Since the Timer object automatically starts counting from the time that the robot program begins, it must be stopped, reset to zero, and started again every time Autonomous mode is enabled. Following that, the robot state is initialized to FORWARD, meaning that the robot should start driving forward when switching to Autonomous mode. To make that actually happen, a positive speed is set for both motors in the final two lines of this method.

  void AutonomousPeriodic()
  {
    if (myTimer.HasPeriodPassed(2.0) == false)
      {
return;
      }

The AutonomousPeriodic method is run repeatedly for as long as the robot is in Autonomous, as opposed to the AutonomousInit method, which runs just once right when the mode is enabled. The first thing to do in this method is to check the timer. If it has not yet counted past 2 seconds, then it returns immediately; nothing else in this method is executed. When the timer does count 2 seconds, then the program will continue on to the following lines.

    double speed = 0.0;

    switch (myState)
      {
      case FORWARD:
speed = 0.0;
myState = STOP_FORWARD;
break;

      case STOP_FORWARD:
speed = -0.6;
myState = BACKWARD;
break;

      case BACKWARD:
speed = 0.0;
myState = STOP_BACKWARD;
break;

      case STOP_BACKWARD:
speed = 0.6;
myState = FORWARD;
break;

      };

Here is the main code for the state machine mentioned previously. Every two seconds while the robot is in Autonomous mode, this switch statement will check the current state and decide the next state to switch to and change the motor speed at the same time. For example, since the robot begins in the FORWARD state, two seconds after starting Autonomous mode, it will change to the state STOP_FORWARD and set the speed to zero. Two seconds later, it will change to BACKWARD and change the speed to -0.6. Eventually it will reach the FORWARD state again and cycle between driving forward, stopping, driving backward, and stopping until the robot is disabled.

    myTimer.Stop();
    myTimer.Reset();
    myTimer.Start();

    myLeftMotor.Set(speed);
    myRightMotor.Set(speed);

These lines following the switch statement reset the timer every two seconds and apply the new speed to the speed controllers.

  void DisabledInit()
  {
    myLeftMotor.Set(0.0);
    myRightMotor.Set(0.0);
  }

Just as before, the robot should stop whenever it's disabled.

Detecting a Line


In addition to driving, programs can also read data from sensors connected to the robot. For example, infrared sensors can be used to detect if a nearby object is light or dark in color. When a voltage is applied to the supply input of the sensor, the voltage that it returns varies depending upon the amount of light that is reflected into its receiver: the voltage is high when it receives less light, and low when it receives more light.



Attach three infrared sensors to the bottom of the front of the robot like in the picture below. Be sure that they are facing down and are within a couple centimeters of the table surface (also ensure they don't actually touch the surface).


Wire the sensors to the analog inputs 3, 6, and 7 on the control board as shown below.


The following code can be used to continuously read values from the sensors and display them on the SmartDashboard.

#include <WPILib.h>

class Robot : public frc::IterativeRobot
{
private:

  frc::AnalogInput myLeftSensor;
  frc::AnalogInput myMiddleSensor;
  frc::AnalogInput myRightSensor;

public:

  Robot() :
    myLeftSensor(3),
    myMiddleSensor(6),
    myRightSensor(7)
  {
    frc::SmartDashboard::init();
  }

  void DisabledInit()
  {
  }

  void AutonomousInit()
  {
  }

  void AutonomousPeriodic()
  {
    frc::SmartDashboard::PutNumber("Left Sensor", myLeftSensor.Get());
    frc::SmartDashboard::PutNumber("Middle Sensor", myMiddleSensor.Get());
    frc::SmartDashboard::PutNumber("Right Sensor", myRightSensor.Get());
  }
};

START_ROBOT_CLASS(Robot);

Build and deploy this program to the robot and enable Autonomous mode. Then, start up SmartDashboard (make sure that it's using the server at localhost or 127.0.0.1). There should be three number fields visible. Change the fields to dials, and the SmartDashboard should look something like the screenshot below.


Breaking Down the Code


Sensors can be used in code much like how speed controllers were used in the previous examples. The first step is to declare them as variables in the Robot class:

class Robot : public frc::IterativeRobot
{
private:

  frc::AnalogInput myLeftSensor;
  frc::AnalogInput myMiddleSensor;
  frc::AnalogInput myRightSensor;

The three infrared sensors are declared as analog sensors because they return numeric, non-binary values; the possible values range from 0 to 1023. If a sensor could only return either a 0 or a 1, then it would be declared as a digital sensor.

  Robot() :
    myLeftSensor(3),
    myMiddleSensor(6),
    myRightSensor(7)
  {
    frc::SmartDashboard::init();
  }

Just like speed controllers, sensors have to be constructed with the numbers of the control board port they're connected to. Also in this constructor is an initialization call for the SmartDashboard. This is needed to be able to send and receive data from the SmartDashboard later in the robot program.

  void DisabledInit()
  {
  }

  void AutonomousInit()
  {
  }

Notice how both the DisabledInit() and AutonomousInit() methods are both empty in this new program. That's because there is no nothing to do just once whenever the robot changes modes. Instead, the sensors must be read continuously in the AutomousPeriodic method below.

  void AutonomousPeriodic()
  {
    frc::SmartDashboard::PutNumber("Left Sensor", myLeftSensor.Get());
    frc::SmartDashboard::PutNumber("Middle Sensor", myMiddleSensor.Get());
    frc::SmartDashboard::PutNumber("Right Sensor", myRightSensor.Get());
  }

Every time this periodic method runs, all three infrared sensors are read, and their current values are put on the SmartDashboard using the PutNumber function. This function takes a label that describes what the data is and the current value that should be shown next to that label. For different types of data (other than numbers) that must be sent to the SmartDashboard, the PutBoolean() and PutString() functions are also available.

Detecting a Line


With the above sensor program running on the robot and SmartDashboard running on the driver station, manually move the robot so that one of the sensors is above a dark surface and the others above a light surface. How do the sensor readings change? Repeat this test for each of the three sensors. Do they all change to the same values? Are the readings affected by the ambient light in the room?


For the later activities, it will be important to determine if a sensor is above a dark line drawn on a white surface. That means that the analog sensor value needs to be converted to a digital value: 0 (false) for being off a line and 1 (true) for being on a line. Write a new method to perform this conversion, and use it to publish the digital values to the SmartDashboard. The SmartDashboard should eventually look like the screenshot below.


Following a Straight Line


Most two-motor robots are often unable to keep a straight path just by applying equal power to both sides for very long. As shown in the first experiment, the robot soon veers off to one side or zig-zags from side to side. This is caused by several factors, including imperfections in the drivetrain, deformities in the driving surface, and unequal distribution of electrical power to the motors.

Feedback from sensors can be used to overcome these obstacles. In this activity, a thick, straight black line on the surface will serve to guide the robot on the correct course. Using the skills learned in the previous examples, write a robot program that automatically adjusts the power to the motors depending on which of the infrared sensors see or don't see the line. For example, if the left sensor does not see the line, but the middle and right ones do, which way should the robot turn? How quickly should it turn? What should each of the motors' speeds be to accomplish that turn?


As a suggestion, begin with low cruising speed for the motors. This will make it easier to judge if the robot is seeing and following the line correctly and to catch it if it becomes lost. Also, it may help to either log the sensor readings and other program variables to a file on the driver station or continuously publish them to the SmartDashboard, or both. Keep in mind that values can also be read from the SmartDashboard; this makes it very easy to quickly try out different sets of constants for tuning a program without having to recompile and restart the robot.

Following a Line With a Turn


Once the robot can follow a straight line, the final step is to handle a sharp turn in the line of at least 90 degrees. Any misstep in the program at the wrong moment can now throw the robot completely off the line and cause it to become lost.


One approach to this problem is to augment the sensor-feedback-drive loop with some special logic for when the robot arrives at the turn. This code could cause the robot to follow a specific sequence of steps to get it to force itself through the turn and continue onto the next straight segment. Remember that a state machine, like the one described in the timed driving example above, can be used to encode these steps in the program. 

Sunday, March 20, 2016

Unit Testing FRC C++ with CppUTest in Eclipse

Introduction

Participating as a programming mentor in this year's FIRST Robotics Competition has been a lot of fun, but I found myself wishing, once again, for better ways to test our robot's code. The existing methods are the traditional direct tests on the actual robot hardware, and simulation using Gazebo. Directly testing the robot is often difficult to even get started with, since the robot is not constructed for much of the 6-week build season. Once it is constructed, though, deploying builds and manually working the controls to verify functionality is slow and error-prone. Working with the simulator also has its own shortcomings. A realistic SolidWorks model is required to drive in a virtual arena, and the simulator itself consumes a lot of processor power and memory.
  Fortunately, there is another way, and that way is unit-testing. Unit tests are small, simple tests written in code (often in the same language as your production code) that set up inputs, exercise some part of the production code, and verify the outputs that are produced. These tests can run directly on the programming computer, no robot hardware required, and execute very quickly. For Java and C++, there are several great frameworks available for free to make the process of writing unit tests easier. In this post, I will describe how the CppUTest framework can be used to make unit tests for a C++ robot program based on WPILib. CppUMock, which is a part of CppUTest, is also used to create a mock version of WPILib that can be precisely controlled in the unit tests. Example code based on the 'Arcade Drive' sample project is available at GitHub.
  Please note that this strategy does not require any modifications to your existing robot code. The only change to your project will be an additional build configuration that allows it to be tested this way. Switching between the default configuration and unit-testing configuration (described below) is easy and fast.

Requirements

The following utilities are required to develop FRC programs with CppUTest.
  1. Eclipse with C/C++ development plugins (eclipse.org)
  2. CppUTest (github.com/cpputest/cpputest) (release 3.7.2 was used for this example)
  3. MockWPILib from the example code (unless you want to write your own mocks)
  4. Unix development tools (if developing on Windows, use Cygwin (cygwin.com)
    1. autoconf
    2. autogen
    3. automake
    4. make
    5. gcc-core
    6. gcc-g++
    7. libtool

Building CppUTest

The first step is to acquire the CppUTest sources either from a release package or the git repository. If you're using Cygwin, the sources should be placed somewhere in your Cygwin installation path (ex: C:\cygwin64\home\user). Then, using a bash shell (or Cygwin Terminal), navigate to the CppUTest root directory and run the following commands, in order:
  1. ./autogen.sh
  2. ./configure
  3. make
If you have all of the packages listed in the requirements section, this should generate the files libCppUTest.a and libCppUTestExt.a in the lib/ subdirectory. If the process is interrupted with errors, then one or more packages are probably missing and should be installed before continuing.

Building WPILib Mocks

The next step is to use CppUMock (included in CppUTest) to begin writing the mock classes you need for your tests. These will be located in a separate project in the same workspace as your main robot project. To create your own mocks project, select 'File > New > C++ Project' and set the project type to 'Static Library > EmptyProject'. For Windows users, set the toolchain to 'Cygwin GCC'.


Click 'Next' to get to the 'Select Configurations' window. Then, click on 'Advanced Settings' to go to the Tool Chain Editor (the Tool Chain Editor for an existing project can be accessed in it's Properties window).


Make sure you're in the 'C/C++ Build > Settings' section (in the menu on the left). Under 'Compiler > Includes', add an include path that points to the 'include' subdirectory of your CppUTest installation (ex: C:\cygwin64\home\user\cpputest\cpputest-3.7.2\include). Click 'Apply' at the bottom of the window.

For Windows users, go to the 'Environment' section (select 'C/C++ Build > Environment' in the menu on the left). There should be an environment variable with the name 'CYGWIN_HOME' with an empty value. Set the variable to the path of your Cygwin installation (ex: C:\cygwin64). Leave the other environment variables unchanged.


Click 'OK' at the bottom to leave the properties window and click 'Finish' to create your mock library project. You may now begin writing the code for your mocks. To learn how to create mock classes, see the CppUMock documentation at the CppUTest site (cpputest.github.io/mocking_manual.html). For examples, see the MockWPILib project. In addition to mock classes, the START_ROBOT_CLASS macro should be defined as empty (#define START_ROBOT_CLASS ()).
  If users want to use and extend the MockWPILib project instead of creating their own mocks project, it can be acquired from GitHub and imported into the Eclipse workspace. To import a project, select 'File > Import > General > Existing Projects into Workspace'.


The build properties explained above should be checked after importing the project to make sure that the correct include path for CppUTest is set. If Cygwin is being used, the Cygwin installation environment variable should be set appropriately as well.

Robot Project Configuration

The next step is to add a build configuration to the main robot project that uses the mock library instead of the real WPILib library. First, go to the project's properties (right-clock on the project and select 'Properties'). In the 'C/C++ Build' section, click on 'Manage Configurations' on the right. In the 'Manage Configurations' window, click 'New' and give a name and description for the new configuration. Copy the settings from the 'Debug' configuration.


Click 'OK' to create the configuration, and then select it and click 'Set Active' in the 'Manage Configurations' window. Click 'OK' to go back to the properties window.


In the properties window, go to 'C/C++ Build > Tool Chain Editor' and set 'Current toolchain' to 'Linux GCC' for Linux users and 'Cygwin GCC' for Windows users. For Windows users, the Cygwin installation directory needs to be set as explained above in 'Building WPILib Mocks'.


After setting the toolchain, go to the section 'C/C++ Build > Settings'. Under 'C++ Compiler > Includes' add an include path for the mock library.


In the 'Project References' section, check the mock library project to indicate that the main robot project now references it.


Click 'OK' to exit the properties window. The main robot project can now be built with the new testing configuration. Be sure that all necessary mock classes and functions are defined in the mock library project to avoid errors. To switch the build configuration to link in the actual WPILib and deploy to the roboRIO, right click on the projects and select 'Build Configurations > Set Active > Debug'.

Writing Tests

Now that the mock library is written and the robot project is configured for unit testing. the unit tests themselves can be written. These tests will reside in a separate project. Create a new project by clicking 'File > New > C++ Project'. Set the project type to 'Executable > Empty Project'. Windows users should set the toolchain to 'Cygwin GCC'.


Click 'Next' and select 'Advanced Settings' to go the properties window. For Windows users, the Cygwin installation path should be set as explained in the section 'Building WPILib Mocks'.
  In the section 'C/C++ Build > Settings', include paths for CppUTest, the mock library, and the main robot project should be added under 'C++ Compiler > Includes'.


In the same section under 'C++ Linker > Libraries', library names and search paths should be added for CppUTest, the mock library, and the main robot project. The library for the main robot project will be called 'FRCUserProgram' and is located in the project's subdirectory for the testing configuration. For CppUTest, both the CppUTest and CppUTestExt libraries should be linked.


After the compiler and linker are configured, go to the 'Project References' section and check both the main robot project and mock library project. Then, click 'OK' to exit the properties window, and click 'Finish' to create the project.


The unit tests can now be written in the new tester project. To learn how to write unit tests with CppUTest, see the documentation on the CppUTest site (cpputest.github.io/manual.html). For examples, see the 'Arcade Drive Test' project on GitHub. Remember to define the 'main' function with a call to 'CommandLineTestRunner::RunAllTests'.
  Once the unit tests are written and built, the tester project can be executed to run the tests. Right-click on the tester project and select 'Run As > Local C/C++ Application'. The test results should show up in the console in Eclipse. If a test fails, the exact location of the failing assertion will be given.


  If an error concerning a missing library appears when running the tests on Windows, then the Cygwin libraries may be missing from the dynamic linker search path. To fix this, go to the 'Run/Debug Settings' section in the project properties. Select the executable in the launch configurations list and click 'Edit' on the right. In the 'Edit Configuration' window, select the 'Environment' tab and click 'New' to add an environment variable. Set the variable name to 'PATH' and the value to the 'bin' subdirectory of the Cygwin installation (ex: C:\cygwin64\bin). Click 'OK' and make sure that 'Append environment to native environment' is selected at the bottom.


Click 'OK' to exit the 'Edit Configuration' window. Click 'OK' to exit the properties window. The tester project should now be able to run.

Monday, June 15, 2015

Introducing a Learning and Prototyping Framework for FRC Software Development

For the past year, I have been volunteering as a mentor for a robotics team at a nearby high school. This team has focused on building robots for the FIRST Robotics Competition for several years. The competition runs every year from January to April. For the first six weeks, each participating team builds a robot, roughly the size of a dishwasher, to compete in a game against robots from other teams. The game changes every year and can range from fast-paced basketball-like matches to precision-intensive construction challenges.
   The latter game type was the one that I had the pleasure of working on with the team for the first time. For the six weeks of build time plus extra hours spent between our competitions, I helped the students and other mentors develop the electronics and software that made up the control system. Since this was a project targeted for high-school students, a lot of that involved taking pre-built modules provided by approved vendors and fitting them together into a system that allowed a pair of human operators to drive the robot.
   Though the process of constructing this control system was relatively easy to manage, my small control systems group and I struggled with a problem that I have encountered before in previous projects: a lack of prototyping and testing techniques. The control system is firmly centered around a large, clunky, expensive controller board called the roboRIO of which our team had only two: one for the robot and one for backup. Destruction or loss of either one of these boards would be a huge blow. In addition, the software utilities and development tool suite were limited to Windows, which in my opinion is a terrible platform for learning how to program. These are only a couple of the factors that I believe resulted in our group having to wait weeks until the robot's hardware was finished before the software could be properly tested. All through the build season I yearned to break free of this suffocating environment.
   After the robot was completed and the team returned from the competitions, I eventually found the time to ponder an alternative development system that would be suitable for prototyping robot code as well as teaching new students the basics of programming. I started with one basic requirement: that code written for the normal system should be able to run unchanged on the new system. That meant re-implementing the main control system C++ API, WPILib. An additional constraint that I adopted was that the robot's hardware should be relatively cheap and easy to modify and expand. After considering a number of educational robotic kits, I settled on the RedBot by SparkFun. The reasons for this choice include the platform's huge popularity, a plethora of plug-and-play sensors and actuators, Arduino compatibility, and affordability. The fact that it's design files have been open-sourced is another significant benefit.
   After nearly three months of sporadic work, I'm finally ready to present an initial status report. Most of the time has been spent on the new implementation of WPILib. It is currently developed only for Linux, though a Windows port is at the top of the to-do list. At this point, only a small fraction of WPILib's interfaces are available for use, including digital output and input and driving capabilities. A lot of work went into the underlying architecture that runs the user's program on a PC base-station while communicating with the robot via a minimal serial protocol. The robot itself runs a simple control loop written in the Arduino language that gets packets from the base-station, pokes the necessary hardware, and spits packets back. More technical details on this architecture as well as plans for future development will soon follow in another post.