Skip to content

Latest commit

 

History

History
188 lines (128 loc) · 9.04 KB

cpp-units.rst

File metadata and controls

188 lines (128 loc) · 9.04 KB

The C++ Units Library

WPILib is coupled with a Units library for C++ teams. This library leverages the C++ type system to enforce proper dimensionality for method parameters, automatically perform unit conversions, and even allow users to define arbitrary defined unit types. Since the C++ type system is enforced at compile-time, the library has essentially no runtime cost.

Using the Units Library

The units library is a header-only library. You must include the relevant header in your source files for the units you want to use. Here's a list of available units.

The units/math.h header provides unit-aware functions like units::math::abs().

Unit Types and Container Types

The C++ units library is based around two sorts of type definitions: unit types and container types.

Unit Types

Unit types correspond to the abstract concept of a unit, without any actual stored value. Unit types are the fundamental "building block" of the units library - all unit types are defined constructively (using the compound_unit template) from a small number of "basic" unit types (such as meters, seconds, etc).

While unit types cannot contain numerical values, their use in building other unit types means that when a type or method uses a template parameter to specify its dimensionality, that parameter will be a unit type.

Container Types

Container types correspond to an actual quantity dimensioned according to some unit - that is, they are what actually hold the numerical value. Container types are constructed from unit types with the unit_t template. Most unit types have a corresponding container type that has the same name suffixed by _t - for example, the unit type units::meter corresponds to the container type units::meter_t.

Whenever a specific quantity of a unit is used (as a variable or a method parameter), it will be an instance of the container type. By default, container types will store the actual value as a double - advanced users may change this by calling the unit_t template manually.

A full list of unit and container types can be found in the documentation.

Creating Instances of Units

To create an instance of a specific unit, we create an instance of its container type:

Alternatively, the units library has type literals defined for some of the more common container types. These can be used in conjunction with type inference via auto to define a unit more succinctly:

Units can also be initialized using a value of an another container type, as long as the types can be converted between one another. For example, a meter_t value can be created from a foot_t value.

In fact, all container types representing convertible unit types are implicitly convertible. Thus, the following is perfectly legal:

In short, we can use any unit of length in place of any other unit of length, anywhere in our code; the units library will automatically perform the correct conversion for us.

Performing Arithmetic with Units

Container types support all of the ordinary arithmetic operations of their underlying data type, with the added condition that the operation must be dimensionally sound. Thus, addition must always be performed on two compatible container types:

Multiplication may be performed on any pair of container types, and yields the container type of a compound unit:

Note

When a calculation yields a compound unit type, this type will only be checked for validity at the point of operation if the result type is specified explicitly. If auto is used, this check will not occur. For example, when we divide distance by time, we may want to ensure the result is, indeed, a velocity (i.e. units::meter_per_second_t). If the return type is declared as auto, this check will not be made.

<cmath> Functions

Some std functions (such as clamp) are templated to accept any type on which the arithmetic operations can be performed. Quantities stored as container types will work with these functions without issue.

However, other std functions work only on ordinary numerical types (e.g. double). The units library's units::math namespace contains wrappers for several of these functions that accept units. Examples of such functions include sqrt, pow, etc.

Removing the Unit Wrapper

To convert a container type to its underlying value, use the value() method. This serves as an escape hatch from the units type system, which should be used only when necessary.

Example of the Units Library in WPILib Code

Several arguments for methods in new features of WPILib (ex. kinematics <docs/software/kinematics-and-odometry/intro-and-chassis-speeds:What is kinematics?>) use the units library. Here is an example of sampling a trajectory <docs/software/advanced-controls/trajectories/manipulating-trajectories:Sampling the trajectory>.

Some WPILib classes represent objects that could naturally work with multiple choices of unit types - for example, a motion profile might operate on either linear distance (e.g. meters) or angular distance (e.g. radians). For such classes, the unit type is required as a template parameter:

For more detailed documentation, please visit the official GitHub page for the units library.