This page details motion modules within the NUbots main codebase, such as the walk engine and the script engine. Information about modules for running and tuning scripts can be found on the Behaviour page.
Walk Engine
NUbots use an open loop walk based on quintic splines. This walk engine takes care of the mathematics and control involved in taking steps without falling over. The walk engine does not plan where to walk, only how to walk.
The walk engine will trigger when a walkcommand is emitted. The walk command gives a vector [x, y, z]
which represents:
Variable | Description |
---|---|
x | velocity in metres per second in the direction of the x axis |
y | velocity in metres per second in the direction of the y axis |
z | yaw in radians per second, positive is counter-clockwise. The 0 point is straight forward. |
The robot's behaviour determines the walk command.
Quintic Spline Walk
The Quintic Walk is an open loop controller based on quintic splines (piecewise fifth degree polynomials). It sets points in each direction for rotation and translation and uses those points to create smooth quintic splines.
The engine has support for kicking using quintic splines. Integration of the kick is a work in progress.
The code used for this walk comes from the RoboCup team Hamburg Bit-Bots, which in turn is from Quentin "Leph" Rouxel and Team Rhoban's walk.
Implementation
The walk uses the Footstep
class to generate the targets for the foot, using the calculated splines.
The SplineContainer
class holds multiple Spline
objects. As the SplineContainer
gets points, they are used to create Spline
s. These Spline objects are each mapped to names based on what they do. These mappings for the walk and kick are in the table below.
The splines that the SplineContainer
holds are instances of a generic Spline
class that holds all the information for a mathematical spline. Each piecewise polynomial in the spline is a Polynom
object that contains the coefficients for a polynomial.
The specific Spline
type we use is a SmoothSpline
, extended from the Spline
class. Find out more about splines and this specific type of spline on the mathematics page.
The TrajectoryUtils
file uses the SplineContainer
for walking and kicking. It creates a SplineContainer
with the following splines:
Name | Description |
---|---|
IS_DOUBLE_SUPPORT | Splines for when the robot is in double support phase, i.e. both feet are on the ground. |
IS_LEFT_SUPPORT_FOOT | Splines for the support foot. |
TRUNK_POS_X | The Cartesian position of the robot's torso in the x-axis. |
TRUNK_POS_Y | The Cartesian position of the robot's torso in the y-axis. |
TRUNK_POS_Z | The Cartesian position of the robot's torso in the z-axis. |
TRUNK_AXIS_X | The orientation of the robot's torso in the x-axis. |
TRUNK_AXIS_Y | The orientation of the robot's torso in the y-axis. |
TRUNK_AXIS_Z | The orientation of the robot's torso in the z-axis. |
FOOT_POS_X | The Cartesian position of the robot's flying foot in the x-axis. |
FOOT_POS_Y | The Cartesian position of the robot's flying foot in the y-axis. |
FOOT_POS_Z | The Cartesian position of the robot's flying foot in the z-axis. |
FOOT_AXIS_X | The orientation of the robot's flying foot in the x-axis. |
FOOT_AXIS_Y | The orientation of the robot's flying foot in the y-axis. |
FOOT_AXIS_Z | The orientation of the robot's flying foot in the z-axis. |
The points that make up all these splines are in the WalkEngine.cpp file. The configuration parameters affect some of these points. Values are all in SI units.
Script Engine
Scripts are static motions for the robot. They specify what joint angles to move to and how long the robot should take to get to those joint angles. For example, standing up is a script telling the robot to move its joints to the stand position over one second. There can be many of these position specifications in sequence to make the robot do more complex movements like getting up or kicking.
To learn how to tune scripts, see the ScriptTuner guide.
Messages
To execute a script, we emit an "execute script" message describing the script to execute. This message is received in the ScriptEngine, which executes the appropriate script. These are specified in Script.h as ExecuteScriptByName and ExecuteScript.
ExecuteScriptByName
takes
- a subsumption ID (this is used to determine servo access priority)
- the name of the script/s as a string or a vector of strings
- the duration of the scripts
- the time that these scripts should start executing
An example of receiving this message is in ScriptEngine.cpp.
on<Trigger<ExecuteScriptByName>>().then([this](const ExecuteScriptByName& command) {...}
An example of emitting this message is in KickScript.cpp
emit(std::make_unique<ExecuteScriptByName>( id, std::vector<std::string>({"Stand.yaml", "KickRight.yaml", "Stand.yaml"})));
Note these are only the names of the scripts, not the full paths. The names correspond to the names of YAML files in the scripts folder.
In addition to using the name of a script, we can also use an instance of Script directly. Script
can be instantiated with all the information for the script to execute, and can be emitted using the ExecuteScript
message. ExecuteScript
takes:
- a subsumption ID (this is used to determine servo access priority)
- a Script or vector of Scripts
- the duration of the scripts
- the time that these scripts should start executing
An example of receiving this messages is in ScriptEngine.cpp
on<Trigger<ExecuteScript>>().then([this](const ExecuteScript& command) {...}
An example of emitting this message is in ScriptTuner.cpp
emit(std::make_unique<ExecuteScript>(id, script, NUClear::clock::now()));
The ScriptEngine module receives either of these messages and processes the information for the script. It collects the servo positions and time for each frame and modifies them if needed based on the given duration and start time in the message. The information is then emitted as a ServoCommand message.
Script files
The script files are YAML files specifying a duration and list of servo targets, in a format like the following:
- duration: 1000 targets: - id: HEAD_YAW position: 0 gain: 30 torque: 100 - id: HEAD_PITCH position: 0.5 gain: 30 torque: 100 - id: R_HIP_YAW position: -0.03 gain: 20 torque: 100
The fields are described in the table below.
Field | Description |
---|---|
duration | An integer in milliseconds. |
position | A float representing the angle of the servo in radians. |
gain | A float representing how much effort the servo will use to get to the target position. Gain is often between 10 and 30. |
torque | A float, where 0 represents no torque and 100 represents torque being on. Torque is 100 unless you want that servo relaxed, in which case it will be 0. |
id | One of the servo IDs listed in ServoID.h. |
Script files can be found in the ScriptEngine module. Scripts can be specific to a robot. More on scripts can be found on the Configuration and Script System page.