C++ 单位库

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.

使用单位库

单位库是仅有标头的库。您必须在源文件中包含要使用的单位的相关标头。下面是可用单位的列表。

#include <units/acceleration.h>
#include <units/angle.h>
#include <units/angular_acceleration.h>
#include <units/angular_velocity.h>
#include <units/area.h>
#include <units/capacitance.h>
#include <units/charge.h>
#include <units/concentration.h>
#include <units/conductance.h>
#include <units/current.h>
#include <units/curvature.h>
#include <units/data.h>
#include <units/data_transfer_rate.h>
#include <units/density.h>
#include <units/dimensionless.h>
#include <units/energy.h>
#include <units/force.h>
#include <units/frequency.h>
#include <units/illuminance.h>
#include <units/impedance.h>
#include <units/inductance.h>
#include <units/length.h>
#include <units/luminous_flux.h>
#include <units/luminous_intensity.h>
#include <units/magnetic_field_strength.h>
#include <units/magnetic_flux.h>
#include <units/mass.h>
#include <units/moment_of_inertia.h>
#include <units/power.h>
#include <units/pressure.h>
#include <units/radiation.h>
#include <units/solid_angle.h>
#include <units/substance.h>
#include <units/temperature.h>
#include <units/time.h>
#include <units/torque.h>
#include <units/velocity.h>
#include <units/voltage.h>
#include <units/volume.h>

“units/math.h” 标头提供了单位感知功能,例如 “units::math::abs()”。

单位类型和容器类型

C ++ 单位库基于两种类型定义 : 单位类型和容器类型。

单位类型

单元类型对应于单元的抽象概念,没有任何实际的存储值。单元类型是单元库的基本“构建块”-所有单元类型都通过少量“基本”单元类型 (例如“ meters”,“ `seconds’等) 在被构造时定义 (通过 “compound_unit” 模版) 。

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.

容器类型

容器类型对应于根据某个单位确定尺寸的实际数量。也就是说,它们是实际包含数值的内容。容器类型是使用具有 “unit_t” 模板的单元类型构造的。大多数单位类型都有一个对应的容器类型,其名称后缀有 “_t” -例如,单元类型 “units :: meter” 对应于容器类型 “units :: meter_t”。

每当使用特定数量的单位 (作为变量或方法参数) 时,它将是容器类型的实例。默认情况下,容器类型会将实际值存储为 “double” -高级用户可以通过手动调用 “unit_t” 模板来更改此值。

单位和容器类型的完整列表可以在文档 “<https://github.com/nholthaus/units#namespaces>” __ 中找到。

创建单位的实例

为了创建特定单元的实例,我们需要创建其容器类型的实例:

// The variable speed has a value of 5 meters per second.
units::meter_per_second_t speed{5.0};

另外,单位库还为一些较常见的容器类型定义了 “类型文字<https://en.cppreference.com/w/cpp/language/user_literal>” __ 。这些可以与通过 “auto” 进行的类型推断结合使用,以更简洁地定义一个单元:

// The variable speed has a value of 5 meters per second.
auto speed = 5_mps;

只要可以在另一个容器类型之间进行转换,单元也可以使用另一个容器类型的值来初始化。例如,可以从 “foot_t” 值创建 “meter_t” 值。

auto feet = 6_ft;
units::meter_t meters{feet};

实际上,代表可转换单位类型的所有容器类型都是 “隐式可转换的” 。因此,以下内容完全合法:

units::meter_t distance = 6_ft;

简而言之,我们可以在代码中的任何位置使用 任意 长度单位代替 任何其他 长度单位;单位库将自动为我们执行正确的转换。

执行含有单位的算术

容器类型支持其基础数据类型的所有普通算术运算,其附加条件是该运算必须是 的。因此,必须始终对两种兼容的容器类型执行添加:

// Add two meter_t values together
auto sum = 5_m + 7_m; // sum is 12_m

// Adds meters to feet; both are length, so this is fine
auto sum = 5_m + 7_ft;

// Tries to add a meter_t to a second_t, will throw a compile-time error
auto sum = 5_m + 7_s;

乘法可以对任何一对容器类型执行,并得出复合单元的容器类型:

备注

当计算产生复合单位类型时,如果明确指定结果类型,则仅在操作时检查此类型的有效性。如果使用 “auto” , 则不会进行此检查。例如, 当我们将距离除以时间时, 我们希望确保结果确实是速度即 ( “units :: meter_per_second_t” )。如果返回类型声明为 “auto” ,则不会进行此检查。

// Multiply two meter_t values, result is square_meter_t
auto product = 5_m * 7_m; // product is 35_sq_m
// Divide a meter_t value by a second_t, result is a meter_per_second_t
units::meter_per_second_t speed = 6_m / 0.5_s; // speed is 12_mps

``<cmath>’’函数

一些 “std” 函数 (例如 clamp ) 被模板化以接受可以在其上执行算术运算的任何类型。以容器类型存储的数量可以使用这些功能而不会出现问题。

但是,其他``std`` 函数仅适用于普通数字类型 (例如 double )。单元库的 units :: math 命名空间包含一些接受单元的函数的包装。此类功能的示例包括 sqrt, pow 等。

auto area = 36_sq_m;
units::meter_t sideLength = units::math::sqrt(area);

去除 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.

units::meter_t distance = 6.5_m;
double distanceMeters = distance.value();

WPILib 代码中的单位库示例

WPILib 新功能中的函数的几个参数 (例如: kinematics <docs/software/kinematics-and-odometry/intro-and-chassis-speeds:What is kinematics?>) 使用单位库。这是对轨迹 <docs/software/advanced-controls/trajectories/manipulating-trajectories:Sampling the trajectory> 进行采样的示例。

// Sample the trajectory at 1.2 seconds. This represents where the robot
// should be after 1.2 seconds of traversal.
Trajectory::State point = trajectory.Sample(1.2_s);

// Since units of time are implicitly convertible, this is exactly equivalent to the above code
Trajectory::State point = trajectory.Sample(1200_ms);

某些 WPILib 类表示可以自然地与多种单位类型一起使用的对象 -例如,运动曲线可能会在线性距离 (例如米) 或角距离 (例如弧度) 上运行。对于这种类,必须将单位类型作为模板参数:

// Creates a new set of trapezoidal motion profile constraints
// Max velocity of 10 meters per second
// Max acceleration of 20 meters per second squared
frc::TrapezoidProfile<units::meters>::Constraints{10_mps, 20_mps_sq};

// Creates a new set of trapezoidal motion profile constraints
// Max velocity of 10 radians per second
// Max acceleration of 20 radians per second squared
frc::TrapezoidProfile<units::radians>::Constraints{10_rad_per_s, 20__rad_per_s / 1_s};

有关更多详细文档,请访问官方 GitHub 页面 获取单位库。