Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Writing Testable Robot Code for FRC

Writing Testable Robot Code for FRC

Discusses how to use Java, WPILib, and industry software testing techniques to create FRC robot code that can be thoroughly tested off the robot. Our abstractions of hardware components, command framework, and data recorder make it easier to test on development machines without robot hardware and on the RoboRIO.

FRC Team 4931

April 23, 2015
Tweet

More Decks by FRC Team 4931

Other Decks in Technology

Transcript

  1. DESIGNING 
 TESTABLE 
 ROBOT CODE FRC Team 4931 Edwardsville

    Technologies 2015 FIRST® Championship Conferences April 22, 2015
  2. PRESENTERS • Randall Hauch Coach and Mentor, FRC 4931 Senior

    Principal Engineer, Red Hat • Zach Anderson Programming Lead, FRC 4931 Edwardsville High School, Class of 2015
  3. FRC 4931 • Edwardsville, IL USA • 20 Student members

    from 4 area high schools • First competed in 2014 Rookie Inspiration Award - 2014 STL Regional FRC Highest Rookie Seed - 2014 STL Regional FRC Gracious Professionalism Award - 2015 STL Regional FRC
  4. Interactive Testing • RobotBuilder generates code - commands and command

    groups - adds buttons on dashboard to invoke commands • Driver Station test mode - subsystems show up in the dashboard - UI controls to control speed controllers • Great way to debug • But testing all functionality manually is time consuming - Ex: change subsystem logic; retest all commands?
  5. Unit Tests • Verify functionality of small “units” - Individual

    classes - Small groups of classes • Automated tests are as important as functional code - Verify that your code actually works - Helps ensure your changes didn’t break anything • Run frequently - Multiple times as you change code - All tests must pass before merging
  6. Unit Test Recommendations • When adding or changing functionality -

    Write tests firsts - Then change the code - All tests should pass • When fixing a bug - Add a test that replicates the bug’s effect - Then try to correct the code - All tests should pass
  7. WPILib library is not testable • Much of it depends

    on hardware • Few abstractions or interfaces • Difficult to specialize via subclassing (lots of private fields/methods) • Lots of dependencies - One class can bring in many of WPILib’s classes, including those that ultimately require hardware Very difficult to test without real hardware Command RobotState HLUsageReporting Timer Scheduler ButtonScheduler easily unit V
  8. Actuators & Sensors Ramp subsystem Guardrail
 subsystem Compressor subsystem Vision

    subsystem Drive subsystem Wrist subsystem Kicker subsystem Arm subsystem
  9. Code for subsystems • Create class for subsystem • Add

    references to hardware objects - Motor controllers, analog inputs, analog outputs, digital inputs, digital outputs • Add logic - Expose methods for subsystem behavior Drive subsystem
  10. Code for subsystems • Tests would create an instance of

    this subsystem class • That results in creating instances of the hardware classes - Attempts to communicate with the actual hardware - Creates lots of other hardware classes • Fails even before we can test anything Drive subsystem NOT TESTABLE!
  11. Hardware abstractions Accelerometer getXacceleration():double getYacceleration():double getZacceleration():double Motor setSpeed( speed: double

    ):void getDirection():Direction stop():void AngleSensor getAngle():double reset():void CurrentSensor getCurrent():double DriveTrain drive( leftSpeed:double, rightSpeed:double):void DistanceSensor getDistance():double Switch isTriggered():boolean SpeedSensor getSpeed():double Relay isOn():boolean isOff():boolean getState():State Solenoid extend():void retract():void getDirection():Direction isExtending():boolean isRetracting():boolean Gyroscope getRate():double getHeading():double reset():void and more!
  12. Traditionally: use WPILib classes directly but this is not testable

    DigitalInput edu.wpi.first.wpilibj SubsystemX
  13. Then use a hardware implementation 
 on the robot HardwareSwitch

    DigitalInput edu.wpi.first.wpilibj Switch isTriggered():boolean SubsystemX
  14. Java 8 lambdas make this even easier • Interfaces with

    one abstract method can be labeled as @FunctionalInterface • Lets Java 8 treat a lambda (or closure) as an implementation of the interface • Saves lots of boilerplate code
  15. But Switch is a @FunctionalInterface so it can be implemented

    with a lambda expression: Switch isTriggered():boolean
  16. So is DriveTrain so it can also be implemented with

    a lambda expression: DriveTrain drive( leftSpeed:double, rightSpeed:double):void
  17. A sample subsystem This class contains our non-trivial logic 


    and drive algorithms.
 
 We want to test this! driveTrain shifter 1 1 DriveTrain Relay DriveSystem arcade(driveSpeed:double, turnSpeed:double) tank(leftSpeed:double, rightSpeed:double) cheesy(throttle:double, wheel:double, isQuickTurn:boolean) highGear() lowGear() stop()
  18. MockDriveTrain MockRelay Easily unit tested These mocks record whether the

    DriveSystem used driveTrain and shifter correctly. The tests create mock implementations that can be programmatically set and checked. DriveSystem arcade(driveSpeed:double, turnSpeed:double) tank(leftSpeed:double, rightSpeed:double) cheesy(throttle:double, wheel:double, isQuickTurn:boolean) highGear() lowGear() stop() driveTrain shifter 1 1 DriveTrain Relay DriveSystemTest
  19. composed DriveTrain HardwareRelay Motor Relay edu.wpi.first.wpilibj SpeedController edu.wpi.first.wpilibj 4 1

    HardwareMotor 1 Also easily used on the robot (This may seem complicated, 
 but each of these classes 
 is remarkably 
 simple and easy to use) driveTrain shifter 1 1 DriveTrain Relay DriveSystem arcade(driveSpeed:double, turnSpeed:double) tank(leftSpeed:double, rightSpeed:double) cheesy(throttle:double, wheel:double, isQuickTurn:boolean) highGear() lowGear() stop() We use implementations that delegate to the WPILib hardware classes.
  20. Benefits of hardware abstractions • Each interface represent one thing

    - very simple - no implementation details • Easy to use • Easy to read • Easy to test
  21. Unit tests only get us so far • Can’t easily

    unit test the whole robot - we do need real hardware for a lot of it • Can’t test control under realistic situations - real sensors are noisy - sensors reflect changes in output - feedback loops are difficult to model We need to still test on the real robot, but …
  22. Our data recorder • Captures - continuous sensors (voltage, current,

    distance, etc.) - discrete sensors (buttons, switches, etc.) - control output (speed, solenoid actuation, etc.) - discrete activities (command states, etc.) • Sends data - to a file for later post-processing off-robot, or - over NetworkTables for real-time processing off-robot
  23. WPILib command framework • How to record change in state?

    • Tried specializing standard Scheduler - too many private methods • Could add data logging in all of our commands - we have lots of commands - would pollute each command with boilerplate - prone to error • Design new command framework - not ideal, but we could make commands more testable
  24. New command framework • All the complex logic is hidden

    in the scheduler - runs on a fixed interval (e.g., every 5ms) - uses a single thread - records all changes in command state as commands are run • Commands and command groups are very simple - lightweight and easy to implement - easier to use - easier to unit test with the real or mock subsystems
  25. Tableau • Desktop data analytics application - drag & drop

    analysis and graphing - every FRC team given 5 licenses • With it we can - graph all data channels vs time - compare, filter, and correlate different channels • Easy to visualize what happened on the robot
  26. Robot Ramp Test Determine when robot is on the ramp

    G-Force Y-Axis G-Force Filter Set to -0.9 to 0.9 Gs Grey Band Indicates Filter A trigger was depressed when the robot was on the ramp. This was done to validate the blue bars above When G-Force exceeds +-0.9, value equals one.
  27. Summary • You can unit test lots of robot code

    • Made possible with new hardware abstraction layer - uses real WPILib hardware classes on robot - easy to unit test without hardware • New command framework - easier to use and test • Data recorder captures all inputs and outputs - easy to see and figure out what happened - helps testing with robot
  28. Future plans • Create standalone open source library - easy

    to use on robot - easy to use in unit tests - sits on top of WPILib • We are considering a new open source project - hope to collaborate with other teams - stay tuned! • Hopefully also influence future WPILib versions - abstractions, commands, data logging - improved Ant build files to support unit testing and 
 3rd party libraries
  29. Resources • Website: http://evilletech.com • FRC 4931 code for 2015

    season - https://github.com/frc-4931/2015-Robot • Follow us on Twitter @frc4931