Brick
Loading...
Searching...
No Matches
pose2d.h
1#pragma once
2
3#include <vector>
4
5#include "cevalm.hpp"
6#include "core/math/geometry/rotation2d.h"
7#include "core/math/geometry/transform2d.h"
8#include "core/math/geometry/translation2d.h"
9#include "core/math/geometry/twist2d.h"
10#include "core/math/units.h"
11
12/**
13 * Class representing a pose in 2d space with x, y, and rotational components
14 *
15 * Assumes conventional cartesian coordinate system:
16 * Looking down at the coordinate plane,
17 * +X is right
18 * +Y is up
19 * +Theta is counterclockwise
20 */
21class Pose2d {
22 private:
23 Translation2d translation_;
24 Rotation2d rotation_;
25
26 public:
27 /// Default Constructor for Pose2d
28 constexpr Pose2d() : translation_{Translation2d()}, rotation_{Rotation2d()} {}
29
30 /**
31 * Constructs a pose with given translation and rotation components.
32 *
33 * @param translation translational component.
34 * @param rotation rotational component.
35 */
36 constexpr Pose2d(Translation2d translation, Rotation2d rotation)
37 : translation_{translation}, rotation_{rotation} {}
38
39 /**
40 * Constructs a pose with given translation and rotation components.
41 *
42 * @param x x component.
43 * @param y y component.
44 * @param rotation rotational component.
45 */
46 constexpr Pose2d(units::Length x, units::Length y, Rotation2d rotation)
47 : translation_{x, y}, rotation_{rotation} {}
48
49 /**
50 * Constructs a pose with given translation and rotation components.
51 *
52 * @param x x component.
53 * @param y y component.
54 * @param radians rotational component in radians.
55 */
56 constexpr Pose2d(units::Length x, units::Length y, double radians)
57 : translation_{x, y}, rotation_{radians} {}
58
59 /**
60 * Constructs a pose with given translation and rotation components in a vector,
61 * using the supplied units.
62 *
63 * @param pose_vector vector of the form [x, y, theta].
64 * @param length_unit unit of length to use.
65 * @param angle_unit unit of angle to use, defaults to radians.
66 */
67 constexpr Pose2d(
68 const Eigen::Vector3d& pose_vector, units::Length length_unit,
69 units::Angle angle_unit = units::radians
70 )
71 : translation_{
72 units::Length(pose_vector[0], length_unit), units::Length(pose_vector[1], length_unit)
73 },
74 rotation_{units::Angle(pose_vector[2], angle_unit)} {}
75
76 /// Gets the x value of the translation.
77 constexpr units::Length x() const { return translation_.x(); }
78
79 /// Gets x in the supplied length unit.
80 constexpr double x(units::Length unit) const { return translation_.x(unit); }
81
82 /// Sets the x value of the translation.
83 constexpr void set_x(units::Length val) { translation_.set_x(val); }
84
85 /// Gets the y value of the translation.
86 constexpr units::Length y() const { return translation_.y(); }
87
88 /// Gets y in the supplied length unit.
89 constexpr double y(units::Length unit) const { return translation_.y(unit); }
90
91 /// Sets the y value of the translation.
92 constexpr void set_y(units::Length val) { translation_.set_y(val); }
93
94 /// Gets the translation.
95 constexpr Translation2d translation() const { return translation_; }
96
97 /// Sets the translation.
98 constexpr void set_translation(Translation2d val) { translation_ = val; }
99
100 /// Gets the rotation.
101 constexpr Rotation2d rotation() const { return rotation_; }
102
103 /// Sets the rotation.
104 constexpr void set_rotation(Rotation2d val) { rotation_ = val; }
105
106 /// Gets the heading as an angle.
107 constexpr units::Angle angle() const { return rotation_.angle(); }
108
109 /// Gets the angle in the supplied unit.
110 constexpr double angle(units::Angle unit) const { return rotation_.angle(unit); }
111
112 /// Sets the rotation as an angle.
113 constexpr void set_angle(units::Angle val) { rotation_ = Rotation2d(val); }
114
115 /// Gets [x, y, theta] in the supplied units. Angles default to radians.
116 EVec<3> as_vector(units::Length length_unit, units::Angle angle_unit = units::radians) const {
117 return {
118 translation_.x().to(length_unit), translation_.y().to(length_unit),
119 rotation_.angle().to(angle_unit)
120 };
121 }
122
123 /// Calculates the distance from the pose to another point.
124 constexpr units::Length distance(Translation2d point) const {
125 return translation_.distance(point);
126 }
127
128 /// Calculates the distance from this to another pose, ignoring rotation.
129 constexpr units::Length distance(const Pose2d& other) const {
130 return distance(other.translation_);
131 }
132
133 /// Calculates the bearing from this to another point in the world frame.
134 constexpr Rotation2d bearing_to(Translation2d point) const {
135 const auto delta = point - translation_;
136 if (delta.x().internal() == 0 && delta.y().internal() == 0) {
137 return rotation_;
138 }
139 return delta.theta();
140 }
141
142 /// Calculates the smallest angle to another point in the local frame.
143 constexpr units::Angle angle_to(Translation2d point) const {
144 return (bearing_to(point) - rotation_).angle();
145 }
146
147 /// Converts a point from this pose's local frame to the world frame.
148 constexpr Translation2d local_to_world(Translation2d point) const {
149 return translation_ + point.rotate_by(rotation_);
150 }
151
152 /// Converts a point from the world frame to this pose's local frame.
153 constexpr Translation2d world_to_local(Translation2d point) const {
154 return (point - translation_).rotate_by(-rotation_);
155 }
156
157 /**
158 * Finds this pose in the frame of another pose rather than the origin.
159 *
160 * @param other new origin.
161 * @return this pose relative to other.
162 */
163 constexpr Pose2d relative_to(const Pose2d& other) const {
164 Transform2d transform = *this - other;
165 return Pose2d{transform.translation(), transform.rotation()};
166 }
167
168 /**
169 * Adds a transform to this pose.
170 * Rotates the transform's translation into the pose's frame,
171 * then adds the translation and rotation.
172 *
173 * @param transform the change in pose.
174 * @return the pose after being transformed.
175 */
176 constexpr Pose2d transform_by(const Transform2d& transform) const {
177 return Pose2d{
178 translation_ + (transform.translation().rotate_by(rotation_)),
179 rotation_ + transform.rotation()
180 };
181 }
182
183 /**
184 * Interpolates position along a straight line and heading along the shortest turn.
185 * Fractions outside [0, 1] return the nearest endpoint.
186 *
187 * Does NOT move along an arc like a Twist, it's a straight line.
188 */
189 constexpr Pose2d interpolate(const Pose2d& end, double fraction) const {
190 if (fraction <= 0) {
191 return *this;
192 }
193 if (fraction >= 1) {
194 return end;
195 }
196 return {
197 translation_ + (end.translation_ - translation_) * fraction,
198 rotation_ + (end.rotation_ - rotation_) * fraction
199 };
200 }
201
202 /**
203 * Applies a twist (pose delta) to a pose by integrating constant velocity and angular velocity
204 * in the robot's frame of motion.
205 *
206 * When applying a twist, imagine a constant angular velocity, the
207 * translational components must be rotated into the global frame at every
208 * point along the twist, simply adding the deltas does not do this, and using
209 * euler integration results in some error. This is the analytic solution for integrating
210 * along an arc.
211 *
212 * Can also be thought of more simply as following an arc rather than a straight line.
213 *
214 * See this document for more information on the pose exponential and its
215 * derivation.
216 * https://file.tavsys.net/control/controls-engineering-in-frc.pdf#section.10.2
217 *
218 * @param twist The twist, represents a pose delta.
219 * @return new pose that has been moved forward according to the twist.
220 */
221 constexpr Pose2d exp(const Twist2d& twist) const {
222 const units::Length dx = twist.dx();
223 const units::Length dy = twist.dy();
224 const double dtheta = twist.dtheta().to(units::radians);
225
226 const double sin_theta = cevalm::sin(dtheta);
227 const double cos_theta = cevalm::cos(dtheta);
228
229 double s, c;
230 if (cevalm::abs(dtheta) < 1e-9) {
231 s = 1.0 - 1.0 / 6.0 * dtheta * dtheta;
232 c = 0.5 * dtheta;
233 } else {
234 s = sin_theta / dtheta;
235 c = (1 - cos_theta) / dtheta;
236 }
237
238 const Transform2d transform{
239 Translation2d{dx * s - dy * c, dx * c + dy * s}, Rotation2d{cos_theta, sin_theta}
240 };
241
242 return *this + transform;
243 }
244
245 /**
246 * The inverse of the pose exponential.
247 *
248 * Determines the twist required to go from this pose to the given end pose.
249 *
250 * @param end_pose the end pose to find the mapping to.
251 * @return the twist required to go from this pose to the given end
252 */
253 constexpr Twist2d log(const Transform2d& transform) const {
254 const double dtheta = transform.rotation().radians();
255 const double half_dtheta = dtheta / 2.0;
256
257 const double cos_minus_one = transform.rotation().f_cos() - 1;
258
259 double half_theta_by_tan_of_half_dtheta;
260
261 if (cevalm::abs(cos_minus_one) < 1e-9) {
262 half_theta_by_tan_of_half_dtheta = 1.0 - 1.0 / 12.0 * dtheta * dtheta;
263 } else {
264 half_theta_by_tan_of_half_dtheta =
265 -(half_dtheta * transform.rotation().f_sin()) / cos_minus_one;
266 }
267
268 const Translation2d translation_part =
269 transform.translation().rotate_by({half_theta_by_tan_of_half_dtheta, -half_dtheta}) *
270 cevalm::hypot(half_theta_by_tan_of_half_dtheta, half_dtheta);
271
272 return Twist2d{
273 translation_part.x(), translation_part.y(), units::Angle(dtheta, units::radians)
274 };
275 }
276
277 /**
278 * Calculates the mean of a list of poses.
279 *
280 * @param list std::vector containing a list of poses.
281 * @return the single pose mean of the list of poses.
282 */
283 static Pose2d wrapped_mean(const std::vector<Pose2d>& list) {
284 if (list.size() == 0) {
285 return Pose2d{};
286 }
287
288 units::Length sumx;
289 units::Length sumy;
290
291 double sum_sin = 0;
292 double sum_cos = 0;
293
294 for (Pose2d pose : list) {
295 sumx += pose.x();
296 sumy += pose.y();
297
298 sum_sin += pose.rotation_.f_sin();
299 sum_cos += pose.rotation_.f_cos();
300 }
301
302 return Pose2d{
303 Translation2d{sumx / list.size(), sumy / list.size()},
304 Rotation2d{sum_cos / list.size(), sum_sin / list.size()}
305 };
306 }
307
308 /// Adds a transform to this pose by rotating it into the pose frame then adding.
309 constexpr Pose2d operator+(const Transform2d& transform) const {
310 return Pose2d{
311 translation_ + (transform.translation().rotate_by(rotation_)),
312 transform.rotation() + rotation_
313 };
314 }
315
316 /// Adds a transform to this pose by rotating it into the pose frame then adding.
317 constexpr Pose2d& operator+=(const Transform2d& transform) { return *this = *this + transform; }
318
319 /// Subtracts another pose from this to find the transform between them.
320 constexpr Transform2d operator-(const Pose2d& other) const {
321 return Transform2d{
322 (translation_ - other.translation_).rotate_by(-other.rotation_), rotation_ - other.rotation_
323 };
324 }
325
326 /// Checks exact equality between this and another pose.
327 constexpr bool operator==(const Pose2d& other) const {
328 return (translation_ == other.translation_) && (rotation_ == other.rotation_);
329 }
330
331 /**
332 * Checks translation distance and the smallest angle against tolerances.
333 * Defaults to 1um and 1e-6 radians.
334 */
335 constexpr bool is_near(
336 const Pose2d& other, units::Length distance_tolerance = units::Length(1e-6),
337 units::Angle angle_tolerance = units::Angle(1e-6)
338 ) const {
339 return translation_.is_near(other.translation_, distance_tolerance) &&
340 rotation_.is_near(other.rotation_, angle_tolerance);
341 }
342};
constexpr Rotation2d theta() const
Gets the angle of the vector from the x axis.
Definition translation2d.h:82
constexpr Q x() const
Gets the x component.
Definition translation2d.h:64
constexpr LinearVector2d rotate_by(Rotation2d rotation) const
Definition translation2d.h:139
constexpr Q y() const
Gets the y component.
Definition translation2d.h:73
constexpr Pose2d & operator+=(const Transform2d &transform)
Adds a transform to this pose by rotating it into the pose frame then adding.
Definition pose2d.h:317
constexpr void set_angle(units::Angle val)
Sets the rotation as an angle.
Definition pose2d.h:113
constexpr Rotation2d rotation() const
Gets the rotation.
Definition pose2d.h:101
constexpr Pose2d exp(const Twist2d &twist) const
Definition pose2d.h:221
constexpr void set_rotation(Rotation2d val)
Sets the rotation.
Definition pose2d.h:104
constexpr units::Length distance(Translation2d point) const
Calculates the distance from the pose to another point.
Definition pose2d.h:124
constexpr Pose2d(units::Length x, units::Length y, Rotation2d rotation)
Definition pose2d.h:46
constexpr Pose2d transform_by(const Transform2d &transform) const
Definition pose2d.h:176
constexpr void set_y(units::Length val)
Sets the y value of the translation.
Definition pose2d.h:92
constexpr units::Angle angle() const
Gets the heading as an angle.
Definition pose2d.h:107
constexpr void set_x(units::Length val)
Sets the x value of the translation.
Definition pose2d.h:83
constexpr Rotation2d bearing_to(Translation2d point) const
Calculates the bearing from this to another point in the world frame.
Definition pose2d.h:134
EVec< 3 > as_vector(units::Length length_unit, units::Angle angle_unit=units::radians) const
Gets [x, y, theta] in the supplied units. Angles default to radians.
Definition pose2d.h:116
constexpr units::Length y() const
Gets the y value of the translation.
Definition pose2d.h:86
constexpr void set_translation(Translation2d val)
Sets the translation.
Definition pose2d.h:98
constexpr Pose2d(Translation2d translation, Rotation2d rotation)
Definition pose2d.h:36
constexpr Twist2d log(const Transform2d &transform) const
Definition pose2d.h:253
static Pose2d wrapped_mean(const std::vector< Pose2d > &list)
Definition pose2d.h:283
constexpr Pose2d(const Eigen::Vector3d &pose_vector, units::Length length_unit, units::Angle angle_unit=units::radians)
Definition pose2d.h:67
constexpr Pose2d interpolate(const Pose2d &end, double fraction) const
Definition pose2d.h:189
constexpr Translation2d world_to_local(Translation2d point) const
Converts a point from the world frame to this pose's local frame.
Definition pose2d.h:153
constexpr units::Length distance(const Pose2d &other) const
Calculates the distance from this to another pose, ignoring rotation.
Definition pose2d.h:129
constexpr Translation2d translation() const
Gets the translation.
Definition pose2d.h:95
constexpr Translation2d local_to_world(Translation2d point) const
Converts a point from this pose's local frame to the world frame.
Definition pose2d.h:148
constexpr double angle(units::Angle unit) const
Gets the angle in the supplied unit.
Definition pose2d.h:110
constexpr double y(units::Length unit) const
Gets y in the supplied length unit.
Definition pose2d.h:89
constexpr units::Angle angle_to(Translation2d point) const
Calculates the smallest angle to another point in the local frame.
Definition pose2d.h:143
constexpr double x(units::Length unit) const
Gets x in the supplied length unit.
Definition pose2d.h:80
constexpr Pose2d operator+(const Transform2d &transform) const
Adds a transform to this pose by rotating it into the pose frame then adding.
Definition pose2d.h:309
constexpr bool operator==(const Pose2d &other) const
Checks exact equality between this and another pose.
Definition pose2d.h:327
constexpr units::Length x() const
Gets the x value of the translation.
Definition pose2d.h:77
constexpr Transform2d operator-(const Pose2d &other) const
Subtracts another pose from this to find the transform between them.
Definition pose2d.h:320
constexpr Pose2d relative_to(const Pose2d &other) const
Definition pose2d.h:163
constexpr bool is_near(const Pose2d &other, units::Length distance_tolerance=units::Length(1e-6), units::Angle angle_tolerance=units::Angle(1e-6)) const
Definition pose2d.h:335
constexpr Pose2d()
Default Constructor for Pose2d.
Definition pose2d.h:28
constexpr Pose2d(units::Length x, units::Length y, double radians)
Definition pose2d.h:56
Definition rotation2d.h:16
constexpr double radians() const
Gets the rotation in radians.
Definition rotation2d.h:72
constexpr Rotation2d()=default
Default Constructor for Rotation2d.
constexpr double f_cos() const
Gets the cosine of the rotation.
Definition rotation2d.h:84
Definition transform2d.h:17
constexpr Translation2d translation() const
Gets the translation.
Definition transform2d.h:98
constexpr Rotation2d rotation() const
Gets the rotation.
Definition transform2d.h:104
Definition twist2d.h:20
constexpr units::Length dx() const
Gets the x displacement.
Definition twist2d.h:56
constexpr units::Length dy() const
Gets the y displacement.
Definition twist2d.h:65
constexpr units::Angle dtheta() const
Gets the Angle displacement.
Definition twist2d.h:74
Definition units.h:12