La librairie d’unités 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.
Utilisation de la librairie d’unités
La librairie d’unités est une bibliothèque d’en-tête uniquement. Vous devez inclure l’en-tête approprié dans vos fichiers source pour les unités que vous souhaitez utiliser. Voici une liste des unités disponibles.
#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>
L’en-tête units/math.h
fournit des fonctions adaptées aux unités telles que units::math::abs()
.
Types d’unités et types de conteneurs
La librairie d’unités C++ est basée sur deux sortes de définitions de types: les types d’unités et les types de conteneurs.
Types d’unités
Les types d’unités correspondent au concept abstrait d’une unité, sans aucune valeur stockée réelle. Les types d’unités sont le « bloc de construction » fondamental de la librairie d’unités - tous les types d’unités sont définis de manière constructive (en utilisant le modèle compound_unit
) à partir d’un petit nombre de types d’unités « de base » (tels que mètres
, secondes
, 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.
Types de conteneurs
Les types de conteneurs correspondent à une quantité réelle dimensionnée en fonction d’une unité, c’est-à-dire qu’ils détiennent réellement la valeur numérique. Les types de conteneurs sont construits à partir de types d’unités avec le modèle unit_t
. La plupart des types d’unités ont un type de conteneur correspondant qui porte le même nom suffixé par _t
- par exemple, le type d’unité units :: meter
correspond au type de conteneur units :: meter_t
.
Chaque fois qu’une quantité spécifique d’une unité est utilisée (en tant que variable ou paramètre de méthode), ce sera une instance du type de conteneur. Par défaut, les types de conteneurs stockent la valeur réelle sous forme de double
- les utilisateurs plus avancés peuvent changer cela en appelant le modèle unit_t
manuellement.
A full list of unit and container types can be found in the documentation.
Création d’instances d’unités
Pour créer une instance d’une unité spécifique, nous créons une instance de son type de conteneur:
// The variable speed has a value of 5 meters per second.
units::meter_per_second_t speed{5.0};
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:
// The variable speed has a value of 5 meters per second.
auto speed = 5_mps;
Les unités peuvent également être initialisées à l’aide d’une valeur d’un autre type de conteneur, en autant que les types peuvent être convertis entre eux. Par exemple, une valeur mètre_t
peut être créée à partir d’une valeur pied_t
.
auto feet = 6_ft;
units::meter_t meters{feet};
En fait, tous les types de conteneurs représentant des types d’unités convertibles sont implicitement convertibles. Ainsi, ce qui suit est parfaitement légal:
units::meter_t distance = 6_ft;
En bref, nous pouvons utiliser n’importe quelle unité de longueur à la place de toute autre unité de longueur, n’importe où dans notre code; la librairie d’unités effectuera automatiquement la conversion correcte pour nous.
Exécution de l’arithmétique avec des unités
Les types de conteneurs prennent en charge toutes les opérations arithmétiques ordinaires de leur type de données sous-jacent, avec la condition supplémentaire que l’opération doit être dimensionnellement valide. Ainsi, l’addition doit toujours être effectuée sur deux types de conteneurs compatibles:
// 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;
La multiplication peut être effectuée sur n’importe quelle paire de types de conteneurs et donne le type de conteneur d’une unité composée:
Note
Lorsqu’un calcul donne un type d’unité composé, ce type ne sera vérifié pour la validité au point d’opération que si le type de résultat est spécifié explicitement. Si auto
est utilisé, cette vérification n’aura pas lieu. Par exemple, lorsque nous divisons la distance par le temps, nous pouvons vouloir nous assurer que le résultat est bien une vitesse (c’est-à-dire units :: meter_per_second_t
). Si le type de retour est déclaré auto
, cette vérification ne sera pas effectuée.
// 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
Les fonctions <cmath>
Certaines fonctions std
(telles que clamp
) sont conçues pour accepter tout type sur lequel les opérations arithmétiques peuvent être effectuées. Les quantités stockées en tant que types de conteneurs fonctionneront sans problème avec ces fonctions.
Cependant, d’autres fonctions std
ne fonctionnent que sur les types numériques ordinaires (par exemple double
). L’espace de noms units :: math
de la librairie d’unités contient des « wrappers » pour plusieurs de ces fonctions qui acceptent les unités. Des exemples de telles fonctions incluent sqrt
, pow
, etc.
auto area = 36_sq_m;
units::meter_t sideLength = units::math::sqrt(area);
Retrait du « Unit Wrapper »
Pour convertir un type de conteneur en sa valeur sous-jacente, utilisez la méthode value()
. Cela sert de trappe d’évacuation du système de type d’unités, qui ne doit être utilisé que lorsque c’est nécessaire.
units::meter_t distance = 6.5_m;
double distanceMeters = distance.value();
Exemple de la librairie d’unités dans le code WPILib
Plusieurs arguments pour des méthodes dans les nouvelles fonctionnalités de WPILib (ex. kinematics) utilisent la librairie d’unités. Voici un exemple d' échantillonnage d’une trajectoire.
// 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);
Certaines classes WPILib représentent des objets qui pourraient naturellement fonctionner avec plusieurs choix de types d’unités - par exemple, un profil de mouvement peut fonctionner sur une distance linéaire (par exemple mètres) ou angulaire (par exemple radians). Pour ces classes, le type d’unité est requis comme paramètre de modèle:
// 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};
For more detailed documentation, please visit the official GitHub page for the units library.