WPILibC++ 2027.0.0-alpha-5
Loading...
Searching...
No Matches
SwerveDriveKinematics.hpp
Go to the documentation of this file.
1// Copyright (c) FIRST and other WPILib contributors.
2// Open Source Software; you can modify and/or share it under the terms of
3// the WPILib BSD license file in the root directory of this project.
4
5#pragma once
6
7#include <algorithm>
8#include <concepts>
9#include <cstddef>
10
11#include <Eigen/QR>
12
24#include "wpi/units/math.hpp"
25#include "wpi/units/velocity.hpp"
27#include "wpi/util/array.hpp"
28
29namespace wpi::math {
30
31/**
32 * Helper class that converts a chassis velocity (dx, dy, and dtheta components)
33 * into individual module states (velocity and angle).
34 *
35 * The inverse kinematics (converting from a desired chassis velocity to
36 * individual module states) uses the relative locations of the modules with
37 * respect to the center of rotation. The center of rotation for inverse
38 * kinematics is also variable. This means that you can set your set your center
39 * of rotation in a corner of the robot to perform special evasion maneuvers.
40 *
41 * Forward kinematics (converting an array of module states into the overall
42 * chassis motion) is performs the exact opposite of what inverse kinematics
43 * does. Since this is an overdetermined system (more equations than variables),
44 * we use a least-squares approximation.
45 *
46 * The inverse kinematics: [moduleVelocities] = [moduleLocations] *
47 * [chassisVelocities] We take the Moore-Penrose pseudoinverse of
48 * [moduleLocations] and then multiply by [moduleVelocities] to get our chassis
49 * velocities.
50 *
51 * Forward kinematics is also used for odometry -- determining the position of
52 * the robot on the field using encoders and a gyro.
53 */
54template <size_t NumModules>
56 : public Kinematics<
57 wpi::util::array<SwerveModulePosition, NumModules>,
58 wpi::util::array<SwerveModuleVelocity, NumModules>,
59 wpi::util::array<SwerveModuleAcceleration, NumModules>> {
60 public:
61 /**
62 * Constructs a swerve drive kinematics object. This takes in a variable
63 * number of module locations as Translation2ds. The order in which you pass
64 * in the module locations is the same order that you will receive the module
65 * states when performing inverse kinematics. It is also expected that you
66 * pass in the module states in the same order when calling the forward
67 * kinematics methods.
68 *
69 * @param moduleTranslations The locations of the modules relative to the
70 * physical center of the robot.
71 */
72 template <std::convertible_to<Translation2d>... ModuleTranslations>
73 requires(sizeof...(ModuleTranslations) == NumModules)
74 explicit SwerveDriveKinematics(ModuleTranslations&&... moduleTranslations)
75 : m_modules{moduleTranslations...},
76 m_moduleHeadings(wpi::util::empty_array) {
77 for (size_t i = 0; i < NumModules; i++) {
78 // clang-format off
79 m_firstOrderInverseKinematics.template block<2, 3>(i * 2, 0) <<
80 1, 0, (-m_modules[i].Y()).value(),
81 0, 1, (+m_modules[i].X()).value();
82
83 m_secondOrderInverseKinematics.template block<2, 4>(i * 2, 0) <<
84 1, 0, (-m_modules[i].X()).value(), (-m_modules[i].Y()).value(),
85 0, 1, (-m_modules[i].Y()).value(), (+m_modules[i].X()).value();
86 // clang-format on
87 }
88
89 m_firstOrderForwardKinematics =
90 m_firstOrderInverseKinematics.householderQr();
91 m_secondOrderForwardKinematics =
92 m_secondOrderInverseKinematics.householderQr();
93
94 wpi::math::MathSharedStore::ReportUsage("SwerveDriveKinematics", "");
95 }
96
99 : m_modules{modules}, m_moduleHeadings(wpi::util::empty_array) {
100 for (size_t i = 0; i < NumModules; i++) {
101 // clang-format off
102 m_firstOrderInverseKinematics.template block<2, 3>(i * 2, 0) <<
103 1, 0, (-m_modules[i].Y()).value(),
104 0, 1, (+m_modules[i].X()).value();
105
106 m_secondOrderInverseKinematics.template block<2, 4>(i * 2, 0) <<
107 1, 0, (-m_modules[i].X()).value(), (-m_modules[i].Y()).value(),
108 0, 1, (-m_modules[i].Y()).value(), (+m_modules[i].X()).value();
109 // clang-format on
110 }
111
112 m_firstOrderForwardKinematics =
113 m_firstOrderInverseKinematics.householderQr();
114 m_secondOrderForwardKinematics =
115 m_secondOrderInverseKinematics.householderQr();
116
117 wpi::math::MathSharedStore::ReportUsage("Kinematics_SwerveDrive", "");
118 }
119
121
122 /**
123 * Reset the internal swerve module headings.
124 *
125 * @param moduleHeadings The swerve module headings. The order of the module
126 * headings should be same as passed into the constructor of this class.
127 */
128 template <std::convertible_to<Rotation2d>... ModuleHeadings>
129 requires(sizeof...(ModuleHeadings) == NumModules)
130 void ResetHeadings(ModuleHeadings&&... moduleHeadings) {
131 return this->ResetHeadings(
133 }
134
135 /**
136 * Reset the internal swerve module headings.
137 *
138 * @param moduleHeadings The swerve module headings. The order of the module
139 * headings should be same as passed into the constructor of this class.
140 */
142 for (size_t i = 0; i < NumModules; i++) {
143 m_moduleHeadings[i] = moduleHeadings[i];
144 }
145 }
146
147 /**
148 * Performs inverse kinematics to return the module states from a desired
149 * chassis velocity. This method is often used to convert joystick values into
150 * module velocities and angles.
151 *
152 * This function also supports variable centers of rotation. During normal
153 * operations, the center of rotation is usually the same as the physical
154 * center of the robot; therefore, the argument is defaulted to that use case.
155 * However, if you wish to change the center of rotation for evasive
156 * maneuvers, vision alignment, or for any other use case, you can do so.
157 *
158 * In the case that the desired chassis velocities are zero (i.e. the robot
159 * will be stationary), the previously calculated module angle will be
160 * maintained.
161 *
162 * @param chassisVelocities The desired chassis velocity.
163 * @param centerOfRotation The center of rotation. For example, if you set the
164 * center of rotation at one corner of the robot and provide a chassis
165 * velocity that only has a dtheta component, the robot will rotate around
166 * that corner.
167 * @return An array containing the module states. Use caution because these
168 * module states are not normalized. Sometimes, a user input may cause one
169 * of the module velocities to go above the attainable max velocity. Use
170 * the DesaturateWheelVelocities(wpi::util::array<SwerveModuleVelocity,
171 * NumModules>, wpi::units::meters_per_second_t) function to rectify this
172 * issue. In addition, you can leverage the power of C++17 to directly
173 * assign the module states to variables:
174 *
175 * @code{.cpp}
176 * auto [fl, fr, bl, br] =
177 * kinematics.ToSwerveModuleVelocities(chassisVelocities);
178 * @endcode
179 */
181 const ChassisVelocities& chassisVelocities,
182 const Translation2d& centerOfRotation = Translation2d{}) const {
185
186 if (chassisVelocities.vx == 0_mps && chassisVelocities.vy == 0_mps &&
187 chassisVelocities.omega == 0_rad_per_s) {
188 for (size_t i = 0; i < NumModules; i++) {
189 moduleVelocities[i] = {0_mps, m_moduleHeadings[i]};
190 }
191
192 return moduleVelocities;
193 }
194
195 // We have a new center of rotation. We need to compute the matrix again.
196 if (centerOfRotation != m_previousCoR) {
197 SetInverseKinematics(centerOfRotation);
198 }
199
200 Eigen::Vector3d chassisVelocitiesVector{chassisVelocities.vx.value(),
201 chassisVelocities.vy.value(),
202 chassisVelocities.omega.value()};
203
204 Matrixd<NumModules * 2, 1> moduleVelocityMatrix =
205 m_firstOrderInverseKinematics * chassisVelocitiesVector;
206
207 for (size_t i = 0; i < NumModules; i++) {
208 wpi::units::meters_per_second_t x{moduleVelocityMatrix(i * 2, 0)};
209 wpi::units::meters_per_second_t y{moduleVelocityMatrix(i * 2 + 1, 0)};
210
211 auto velocity = wpi::units::math::hypot(x, y);
212 auto rotation = velocity > 1e-6_mps ? Rotation2d{x.value(), y.value()}
213 : m_moduleHeadings[i];
214
215 moduleVelocities[i] = {velocity, rotation};
216 m_moduleHeadings[i] = rotation;
217 }
218
219 return moduleVelocities;
220 }
221
223 const ChassisVelocities& chassisVelocities) const override {
224 return ToSwerveModuleVelocities(chassisVelocities);
225 }
226
227 /**
228 * Performs forward kinematics to return the resulting chassis state from the
229 * given module states. This method is often used for odometry -- determining
230 * the robot's position on the field using data from the real-world velocity
231 * and angle of each module on the robot.
232 *
233 * @param moduleVelocities The state of the modules (as a SwerveModuleVelocity
234 * type) as measured from respective encoders and gyros. The order of the
235 * swerve module states should be same as passed into the constructor of
236 * this class.
237 * @return The resulting chassis velocity.
238 */
239 template <std::convertible_to<SwerveModuleVelocity>... ModuleVelocities>
240 requires(sizeof...(ModuleVelocities) == NumModules)
242 ModuleVelocities&&... moduleVelocities) const {
243 return this->ToChassisVelocities(
245 moduleVelocities...});
246 }
247
248 /**
249 * Performs forward kinematics to return the resulting chassis state from the
250 * given module states. This method is often used for odometry -- determining
251 * the robot's position on the field using data from the real-world velocity
252 * and angle of each module on the robot.
253 *
254 * @param moduleVelocities The state of the modules as an wpi::util::array of
255 * type SwerveModuleVelocity, NumModules long as measured from respective
256 * encoders and gyros. The order of the swerve module states should be
257 * same as passed into the constructor of this class.
258 * @return The resulting chassis velocity.
259 */
262 moduleVelocities) const override {
263 Matrixd<NumModules * 2, 1> moduleVelocityMatrix;
264
265 for (size_t i = 0; i < NumModules; ++i) {
266 SwerveModuleVelocity module = moduleVelocities[i];
267 moduleVelocityMatrix(i * 2, 0) =
268 module.velocity.value() * module.angle.Cos();
269 moduleVelocityMatrix(i * 2 + 1, 0) =
270 module.velocity.value() * module.angle.Sin();
271 }
272
273 Eigen::Vector3d chassisVelocitiesVector =
274 m_firstOrderForwardKinematics.solve(moduleVelocityMatrix);
275
276 return {wpi::units::meters_per_second_t{chassisVelocitiesVector(0)},
277 wpi::units::meters_per_second_t{chassisVelocitiesVector(1)},
278 wpi::units::radians_per_second_t{chassisVelocitiesVector(2)}};
279 }
280
281 /**
282 * Performs forward kinematics to return the resulting Twist2d from the
283 * given module position deltas. This method is often used for odometry --
284 * determining the robot's position on the field using data from the
285 * real-world position delta and angle of each module on the robot.
286 *
287 * @param moduleDeltas The latest change in position of the modules (as a
288 * SwerveModulePosition type) as measured from respective encoders and
289 * gyros. The order of the swerve module states should be same as passed
290 * into the constructor of this class.
291 * @return The resulting Twist2d.
292 */
293 template <std::convertible_to<SwerveModulePosition>... ModuleDeltas>
294 requires(sizeof...(ModuleDeltas) == NumModules)
295 Twist2d ToTwist2d(ModuleDeltas&&... moduleDeltas) const {
296 return this->ToTwist2d(
298 }
299
300 /**
301 * Performs forward kinematics to return the resulting Twist2d from the
302 * given module position deltas. This method is often used for odometry --
303 * determining the robot's position on the field using data from the
304 * real-world position delta and angle of each module on the robot.
305 *
306 * @param moduleDeltas The latest change in position of the modules (as a
307 * SwerveModulePosition type) as measured from respective encoders and
308 * gyros. The order of the swerve module states should be same as passed
309 * into the constructor of this class.
310 * @return The resulting Twist2d.
311 */
314 Matrixd<NumModules * 2, 1> moduleDeltaMatrix;
315
316 for (size_t i = 0; i < NumModules; ++i) {
317 SwerveModulePosition module = moduleDeltas[i];
318 moduleDeltaMatrix(i * 2, 0) =
319 module.distance.value() * module.angle.Cos();
320 moduleDeltaMatrix(i * 2 + 1, 0) =
321 module.distance.value() * module.angle.Sin();
322 }
323
324 Eigen::Vector3d chassisDeltaVector =
325 m_firstOrderForwardKinematics.solve(moduleDeltaMatrix);
326
327 return {wpi::units::meter_t{chassisDeltaVector(0)},
328 wpi::units::meter_t{chassisDeltaVector(1)},
329 wpi::units::radian_t{chassisDeltaVector(2)}};
330 }
331
335 const override {
338 for (size_t i = 0; i < NumModules; i++) {
339 result[i] = {end[i].distance - start[i].distance, end[i].angle};
340 }
341 return ToTwist2d(result);
342 }
343
344 /**
345 * Renormalizes the wheel velocities if any individual velocity is above the
346 * specified maximum.
347 *
348 * Sometimes, after inverse kinematics, the requested velocity
349 * from one or more modules may be above the max attainable velocity for the
350 * driving motor on that module. To fix this issue, one can reduce all the
351 * wheel velocities to make sure that all requested module velocities are
352 * at-or-below the absolute threshold, while maintaining the ratio of
353 * velocities between modules.
354 *
355 * Scaling down the module velocities rotates the direction of net motion in
356 * the opposite direction of rotational velocity, which makes discretizing the
357 * chassis velocities inaccurate because the discretization did not account
358 * for this translational skew.
359 *
360 * @param moduleVelocities The array of module velocities.
361 * @param attainableMaxVelocity The absolute max velocity that a module can
362 * reach.
363 * @return The array of desaturated module velocities.
364 */
365 [[nodiscard]]
369 wpi::units::meters_per_second_t attainableMaxVelocity) {
370 auto realMaxVelocity = wpi::units::math::abs(
371 std::max_element(moduleVelocities.begin(), moduleVelocities.end(),
372 [](const auto& a, const auto& b) {
373 return wpi::units::math::abs(a.velocity) <
374 wpi::units::math::abs(b.velocity);
375 })
376 ->velocity);
377
378 if (realMaxVelocity > attainableMaxVelocity) {
381 for (size_t i = 0; i < NumModules; ++i) {
382 velocities[i] = {moduleVelocities[i].velocity / realMaxVelocity *
383 attainableMaxVelocity,
384 moduleVelocities[i].angle};
385 }
386 return velocities;
387 }
388 return moduleVelocities;
389 }
390
391 /**
392 * Renormalizes the wheel velocities if any individual velocity is above the
393 * specified maximum, as well as getting rid of joystick saturation at edges
394 * of joystick.
395 *
396 * Sometimes, after inverse kinematics, the requested velocity
397 * from one or more modules may be above the max attainable velocity for the
398 * driving motor on that module. To fix this issue, one can reduce all the
399 * wheel velocities to make sure that all requested module velocities are
400 * at-or-below the absolute threshold, while maintaining the ratio of
401 * velocities between modules.
402 *
403 * Scaling down the module velocities rotates the direction of net motion in
404 * the opposite direction of rotational velocity, which makes discretizing the
405 * chassis velocities inaccurate because the discretization did not account
406 * for this translational skew.
407 *
408 * @param moduleVelocities The array of module velocities.
409 * @param desiredChassisVelocity The desired velocity of the robot
410 * @param attainableMaxModuleVelocity The absolute max velocity a module can
411 * reach
412 * @param attainableMaxRobotTranslationVelocity The absolute max velocity the
413 * robot can reach while translating
414 * @param attainableMaxRobotRotationVelocity The absolute max velocity the
415 * robot can reach while rotating
416 * @return The array of desaturated module velocities
417 */
418 [[nodiscard]]
422 ChassisVelocities desiredChassisVelocity,
423 wpi::units::meters_per_second_t attainableMaxModuleVelocity,
424 wpi::units::meters_per_second_t attainableMaxRobotTranslationVelocity,
425 wpi::units::radians_per_second_t attainableMaxRobotRotationVelocity) {
426 auto realMaxVelocity = wpi::units::math::abs(
427 std::max_element(moduleVelocities.begin(), moduleVelocities.end(),
428 [](const auto& a, const auto& b) {
429 return wpi::units::math::abs(a.velocity) <
430 wpi::units::math::abs(b.velocity);
431 })
432 ->velocity);
433
434 if (attainableMaxRobotTranslationVelocity == 0_mps ||
435 attainableMaxRobotRotationVelocity == 0_rad_per_s ||
436 realMaxVelocity == 0_mps) {
437 return moduleVelocities;
438 }
439
440 auto translationalK = wpi::units::math::hypot(desiredChassisVelocity.vx,
441 desiredChassisVelocity.vy) /
442 attainableMaxRobotTranslationVelocity;
443
444 auto rotationalK = wpi::units::math::abs(desiredChassisVelocity.omega) /
445 attainableMaxRobotRotationVelocity;
446
447 auto k = wpi::units::math::max(translationalK, rotationalK);
448
449 auto scale =
450 wpi::units::math::min(k * attainableMaxModuleVelocity / realMaxVelocity,
451 wpi::units::scalar_t{1});
454 for (size_t i = 0; i < NumModules; ++i) {
455 velocities[i] = {moduleVelocities[i].velocity * scale,
456 moduleVelocities[i].angle};
457 }
458 return velocities;
459 }
460
464 double t) const override {
467 for (size_t i = 0; i < NumModules; ++i) {
468 result[i] = start[i].Interpolate(end[i], t);
469 }
470 return {result};
471 }
472
474 return m_modules;
475 }
476
477 /**
478 * Performs inverse kinematics to return the module accelerations from a
479 * desired chassis acceleration. This method is often used for dynamics
480 * calculations -- converting desired robot accelerations into individual
481 * module accelerations.
482 *
483 * This function also supports variable centers of rotation. During normal
484 * operations, the center of rotation is usually the same as the physical
485 * center of the robot; therefore, the argument is defaulted to that use case.
486 * However, if you wish to change the center of rotation for evasive
487 * maneuvers, vision alignment, or for any other use case, you can do so.
488 *
489 * @param chassisAccelerations The desired chassis accelerations.
490 * @param angularVelocity The desired robot angular velocity.
491 * @param centerOfRotation The center of rotation. For example, if you set the
492 * center of rotation at one corner of the robot and provide a chassis
493 * acceleration that only has a dtheta component, the robot will rotate
494 * around that corner.
495 * @return An array containing the module accelerations.
496 */
499 const ChassisAccelerations& chassisAccelerations,
500 const units::radians_per_second_t angularVelocity = 0.0_rad_per_s,
501 const Translation2d& centerOfRotation = Translation2d{}) const {
502 // Derivation for second-order kinematics from "Swerve Drive Second Order
503 // Kinematics" by FRC Team 449 - The Blair Robot Project, Rafi Pedersen
504 // https://www.chiefdelphi.com/uploads/short-url/qzj4k2LyBs7rLxAem0YajNIlStH.pdf
505
508
509 if (chassisAccelerations.ax == 0.0_mps_sq &&
510 chassisAccelerations.ay == 0.0_mps_sq &&
511 chassisAccelerations.alpha == 0.0_rad_per_s_sq) {
512 for (size_t i = 0; i < NumModules; i++) {
513 moduleAccelerations[i] = {0.0_mps_sq, Rotation2d{0.0_rad}};
514 }
515 return moduleAccelerations;
516 }
517
518 if (centerOfRotation != m_previousCoR) {
519 SetInverseKinematics(centerOfRotation);
520 }
521
522 Eigen::Vector4d chassisAccelerationsVector{
523 chassisAccelerations.ax.value(), chassisAccelerations.ay.value(),
524 angularVelocity.value() * angularVelocity.value(),
525 chassisAccelerations.alpha.value()};
526
527 Matrixd<NumModules * 2, 1> moduleAccelerationsMatrix =
528 m_secondOrderInverseKinematics * chassisAccelerationsVector;
529
530 for (size_t i = 0; i < NumModules; i++) {
531 units::meters_per_second_squared_t x{moduleAccelerationsMatrix(i * 2, 0)};
532 units::meters_per_second_squared_t y{
533 moduleAccelerationsMatrix(i * 2 + 1, 0)};
534
535 // For swerve modules, we need to compute both linear acceleration and
536 // angular acceleration The linear acceleration is the magnitude of the
537 // acceleration vector
538 units::meters_per_second_squared_t linearAcceleration =
539 units::math::hypot(x, y);
540
541 if (linearAcceleration.value() < 1e-6) {
542 moduleAccelerations[i] = {linearAcceleration, {}};
543 } else {
544 moduleAccelerations[i] = {linearAcceleration,
545 Rotation2d{x.value(), y.value()}};
546 }
547 }
548
549 return moduleAccelerations;
550 }
551
552 /**
553 * Performs inverse kinematics to return the module accelerations from a
554 * desired chassis acceleration. This method is often used for dynamics
555 * calculations -- converting desired robot accelerations into individual
556 * module accelerations.
557 *
558 * @param chassisAccelerations The desired chassis accelerations.
559 * @return An array containing the module accelerations.
560 */
562 const ChassisAccelerations& chassisAccelerations) const override {
563 return ToSwerveModuleAccelerations(chassisAccelerations);
564 }
565
566 /**
567 * Performs forward kinematics to return the resulting chassis accelerations
568 * from the given module accelerations. This method is often used for dynamics
569 * calculations -- determining the robot's acceleration on the field using
570 * data from the real-world acceleration of each module on the robot.
571 *
572 * @param moduleAccelerations The accelerations of the modules as measured
573 * from respective encoders and gyros. The order of the swerve module
574 * accelerations should be same as passed into the constructor of this
575 * class.
576 * @return The resulting chassis accelerations.
577 */
578 template <
579 std::convertible_to<SwerveModuleAcceleration>... ModuleAccelerations>
580 requires(sizeof...(ModuleAccelerations) == NumModules)
582 ModuleAccelerations&&... moduleAccelerations) const {
583 return this->ToChassisAccelerations(
585 moduleAccelerations...});
586 }
587
588 /**
589 * Performs forward kinematics to return the resulting chassis accelerations
590 * from the given module accelerations. This method is often used for dynamics
591 * calculations -- determining the robot's acceleration on the field using
592 * data from the real-world acceleration of each module on the robot.
593 *
594 * @param moduleAccelerations The accelerations of the modules as measured
595 * from respective encoders and gyros. The order of the swerve module
596 * accelerations should be same as passed into the constructor of this
597 * class.
598 * @return The resulting chassis accelerations.
599 */
602 moduleAccelerations) const override {
603 // Derivation for second-order kinematics from "Swerve Drive Second Order
604 // Kinematics" by FRC Team 449 - The Blair Robot Project, Rafi Pedersen
605 // https://www.chiefdelphi.com/uploads/short-url/qzj4k2LyBs7rLxAem0YajNIlStH.pdf
606
607 Matrixd<NumModules * 2, 1> moduleAccelerationsMatrix;
608
609 for (size_t i = 0; i < NumModules; i++) {
610 SwerveModuleAcceleration module = moduleAccelerations[i];
611
612 moduleAccelerationsMatrix(i * 2 + 0, 0) =
613 module.acceleration.value() * module.angle.Cos();
614 moduleAccelerationsMatrix(i * 2 + 1, 0) =
615 module.acceleration.value() * module.angle.Sin();
616 }
617
618 Eigen::Vector4d chassisAccelerationsVector =
619 m_secondOrderForwardKinematics.solve(moduleAccelerationsMatrix);
620
621 // the second order kinematics equation for swerve drive yields a state
622 // vector [aₓ, a_y, ω², α]
623 return {units::meters_per_second_squared_t{chassisAccelerationsVector(0)},
624 units::meters_per_second_squared_t{chassisAccelerationsVector(1)},
625 units::radians_per_second_squared_t{chassisAccelerationsVector(3)}};
626 }
627
628 private:
630 mutable Matrixd<NumModules * 2, 3> m_firstOrderInverseKinematics;
631 Eigen::HouseholderQR<Matrixd<NumModules * 2, 3>>
632 m_firstOrderForwardKinematics;
633 mutable Matrixd<NumModules * 2, 4> m_secondOrderInverseKinematics;
634 Eigen::HouseholderQR<Matrixd<NumModules * 2, 4>>
635 m_secondOrderForwardKinematics;
636 mutable wpi::util::array<Rotation2d, NumModules> m_moduleHeadings;
637
638 mutable Translation2d m_previousCoR;
639
640 /**
641 * Sets both inverse kinematics matrices based on the new center of rotation.
642 * This does not check if the new center of rotation is different from the
643 * previous one, so a check should be included before the call to this
644 * function.
645 *
646 * @param centerOfRotation new center of rotation
647 */
648 void SetInverseKinematics(const Translation2d& centerOfRotation) const {
649 for (size_t i = 0; i < NumModules; i++) {
650 const double rx = m_modules[i].X().value() - centerOfRotation.X().value();
651 const double ry = m_modules[i].Y().value() - centerOfRotation.Y().value();
652
653 m_firstOrderInverseKinematics.row(i * 2 + 0) << 1, 0, -ry;
654 m_firstOrderInverseKinematics.row(i * 2 + 1) << 0, 1, rx;
655
656 m_secondOrderInverseKinematics.row(i * 2 + 0) << 1, 0, -rx, -ry;
657 m_secondOrderInverseKinematics.row(i * 2 + 1) << 0, 1, -ry, +rx;
658 }
659 m_previousCoR = centerOfRotation;
660 }
661};
662
663template <typename ModuleTranslation, typename... ModuleTranslations>
664SwerveDriveKinematics(ModuleTranslation, ModuleTranslations...)
665 -> SwerveDriveKinematics<1 + sizeof...(ModuleTranslations)>;
666
667extern template class EXPORT_TEMPLATE_DECLARE(WPILIB_DLLEXPORT)
669
670} // namespace wpi::math
671
#define EXPORT_TEMPLATE_DECLARE(export)
Definition SymbolExports.hpp:94
#define WPILIB_DLLEXPORT
Definition SymbolExports.hpp:36
Helper class that converts a chassis velocity (dx, dy, and dtheta components) into individual wheel v...
Definition Kinematics.hpp:26
static void ReportUsage(std::string_view resource, std::string_view data)
Definition MathShared.hpp:61
A rotation in a 2D coordinate frame represented by a point on the unit circle (cosine and sine).
Definition Rotation2d.hpp:29
Helper class that converts a chassis velocity (dx, dy, and dtheta components) into individual module ...
Definition SwerveDriveKinematics.hpp:59
void ResetHeadings(ModuleHeadings &&... moduleHeadings)
Reset the internal swerve module headings.
Definition SwerveDriveKinematics.hpp:130
wpi::util::array< SwerveModuleAcceleration, NumModules > ToWheelAccelerations(const ChassisAccelerations &chassisAccelerations) const override
Performs inverse kinematics to return the module accelerations from a desired chassis acceleration.
Definition SwerveDriveKinematics.hpp:561
wpi::util::array< SwerveModuleVelocity, NumModules > ToWheelVelocities(const ChassisVelocities &chassisVelocities) const override
Performs inverse kinematics to return the wheel velocities from a desired chassis velocity.
Definition SwerveDriveKinematics.hpp:222
wpi::util::array< SwerveModuleAcceleration, NumModules > ToSwerveModuleAccelerations(const ChassisAccelerations &chassisAccelerations, const units::radians_per_second_t angularVelocity=0.0_rad_per_s, const Translation2d &centerOfRotation=Translation2d{}) const
Performs inverse kinematics to return the module accelerations from a desired chassis acceleration.
Definition SwerveDriveKinematics.hpp:498
SwerveDriveKinematics(const wpi::util::array< Translation2d, NumModules > &modules)
Definition SwerveDriveKinematics.hpp:97
SwerveDriveKinematics(const SwerveDriveKinematics &)=default
const wpi::util::array< Translation2d, NumModules > & GetModules() const
Definition SwerveDriveKinematics.hpp:473
SwerveDriveKinematics(ModuleTranslations &&... moduleTranslations)
Constructs a swerve drive kinematics object.
Definition SwerveDriveKinematics.hpp:74
Twist2d ToTwist2d(wpi::util::array< SwerveModulePosition, NumModules > moduleDeltas) const
Performs forward kinematics to return the resulting Twist2d from the given module position deltas.
Definition SwerveDriveKinematics.hpp:312
Twist2d ToTwist2d(const wpi::util::array< SwerveModulePosition, NumModules > &start, const wpi::util::array< SwerveModulePosition, NumModules > &end) const override
Performs forward kinematics to return the resulting Twist2d from the given change in wheel positions.
Definition SwerveDriveKinematics.hpp:332
ChassisVelocities ToChassisVelocities(const wpi::util::array< SwerveModuleVelocity, NumModules > &moduleVelocities) const override
Performs forward kinematics to return the resulting chassis state from the given module states.
Definition SwerveDriveKinematics.hpp:260
static wpi::util::array< SwerveModuleVelocity, NumModules > DesaturateWheelVelocities(wpi::util::array< SwerveModuleVelocity, NumModules > moduleVelocities, ChassisVelocities desiredChassisVelocity, wpi::units::meters_per_second_t attainableMaxModuleVelocity, wpi::units::meters_per_second_t attainableMaxRobotTranslationVelocity, wpi::units::radians_per_second_t attainableMaxRobotRotationVelocity)
Renormalizes the wheel velocities if any individual velocity is above the specified maximum,...
Definition SwerveDriveKinematics.hpp:420
Twist2d ToTwist2d(ModuleDeltas &&... moduleDeltas) const
Performs forward kinematics to return the resulting Twist2d from the given module position deltas.
Definition SwerveDriveKinematics.hpp:295
wpi::util::array< SwerveModulePosition, NumModules > Interpolate(const wpi::util::array< SwerveModulePosition, NumModules > &start, const wpi::util::array< SwerveModulePosition, NumModules > &end, double t) const override
Performs interpolation between two values.
Definition SwerveDriveKinematics.hpp:461
ChassisVelocities ToChassisVelocities(ModuleVelocities &&... moduleVelocities) const
Performs forward kinematics to return the resulting chassis state from the given module states.
Definition SwerveDriveKinematics.hpp:241
static wpi::util::array< SwerveModuleVelocity, NumModules > DesaturateWheelVelocities(wpi::util::array< SwerveModuleVelocity, NumModules > moduleVelocities, wpi::units::meters_per_second_t attainableMaxVelocity)
Renormalizes the wheel velocities if any individual velocity is above the specified maximum.
Definition SwerveDriveKinematics.hpp:367
ChassisAccelerations ToChassisAccelerations(ModuleAccelerations &&... moduleAccelerations) const
Performs forward kinematics to return the resulting chassis accelerations from the given module accel...
Definition SwerveDriveKinematics.hpp:581
ChassisAccelerations ToChassisAccelerations(const wpi::util::array< SwerveModuleAcceleration, NumModules > &moduleAccelerations) const override
Performs forward kinematics to return the resulting chassis accelerations from the given module accel...
Definition SwerveDriveKinematics.hpp:600
wpi::util::array< SwerveModuleVelocity, NumModules > ToSwerveModuleVelocities(const ChassisVelocities &chassisVelocities, const Translation2d &centerOfRotation=Translation2d{}) const
Performs inverse kinematics to return the module states from a desired chassis velocity.
Definition SwerveDriveKinematics.hpp:180
void ResetHeadings(wpi::util::array< Rotation2d, NumModules > moduleHeadings)
Reset the internal swerve module headings.
Definition SwerveDriveKinematics.hpp:141
Represents a translation in 2D space.
Definition Translation2d.hpp:33
constexpr wpi::units::meter_t Y() const
Returns the Y component of the translation.
Definition Translation2d.hpp:112
constexpr wpi::units::meter_t X() const
Returns the X component of the translation.
Definition Translation2d.hpp:105
This class is a wrapper around std::array that does compile time size checking.
Definition array.hpp:26
Definition LinearSystem.hpp:20
SwerveDriveKinematics(ModuleTranslation, ModuleTranslations...) -> SwerveDriveKinematics< 1+sizeof...(ModuleTranslations)>
Eigen::Matrix< double, Rows, Cols, Options, MaxRows, MaxCols > Matrixd
Definition EigenCore.hpp:21
Definition raw_os_ostream.hpp:19
constexpr empty_array_t empty_array
Definition array.hpp:16
Definition CvSource.hpp:15
Represents robot chassis accelerations.
Definition ChassisAccelerations.hpp:21
units::meters_per_second_squared_t ax
Acceleration along the x-axis.
Definition ChassisAccelerations.hpp:25
units::radians_per_second_squared_t alpha
Angular acceleration of the robot frame.
Definition ChassisAccelerations.hpp:35
units::meters_per_second_squared_t ay
Acceleration along the y-axis.
Definition ChassisAccelerations.hpp:30
Represents robot chassis velocities.
Definition ChassisVelocities.hpp:26
wpi::units::meters_per_second_t vx
Velocity along the x-axis.
Definition ChassisVelocities.hpp:30
wpi::units::radians_per_second_t omega
Represents the angular velocity of the robot frame.
Definition ChassisVelocities.hpp:40
wpi::units::meters_per_second_t vy
Velocity along the y-axis.
Definition ChassisVelocities.hpp:35
Represents the accelerations of one swerve module.
Definition SwerveModuleAcceleration.hpp:16
Represents the position of one swerve module.
Definition SwerveModulePosition.hpp:17
Represents the velocity of one swerve module.
Definition SwerveModuleVelocity.hpp:17
A change in distance along a 2D arc since the last pose update.
Definition Twist2d.hpp:23