Motion

Motion and how it works in the NUbots codebase.

The motion subsystem contains modules that are responsible for walking, kicking, moving the head, and running scripts. They perform these motions by sending servo commands (called targets) to the motors.

The Script Engine is detailed on this page, while Script Runner and Script Tuner can be found on the Behaviour page.

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.

FieldDescription
durationAn integer in milliseconds.
positionA float representing the angle of the servo in radians.
gainA float representing how much effort the servo will use to get to the target position. Gain is often between 10 and 30.
torqueA 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.
idOne 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.

Subsystems
Localisation
Subsystems
Vision
Copyright © 2021 NUbots - CC-BY-4.0
Deploys by Netlify