WPILibC++ 2027.0.0-alpha-4
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 Reference to array of module states. The array will
361 * be mutated with the normalized velocities!
362 * @param attainableMaxVelocity The absolute max velocity that a module can
363 * reach.
364 */
367 wpi::units::meters_per_second_t attainableMaxVelocity) {
368 auto& states = *moduleVelocities;
369 auto realMaxVelocity = wpi::units::math::abs(
370 std::max_element(states.begin(), states.end(),
371 [](const auto& a, const auto& b) {
372 return wpi::units::math::abs(a.velocity) <
373 wpi::units::math::abs(b.velocity);
374 })
375 ->velocity);
376
377 if (realMaxVelocity > attainableMaxVelocity) {
378 for (auto& module : states) {
379 module.velocity =
380 module.velocity / realMaxVelocity * attainableMaxVelocity;
381 }
382 }
383 }
384
385 /**
386 * Renormalizes the wheel velocities if any individual velocity is above the
387 * specified maximum, as well as getting rid of joystick saturation at edges
388 * of joystick.
389 *
390 * Sometimes, after inverse kinematics, the requested velocity
391 * from one or more modules may be above the max attainable velocity for the
392 * driving motor on that module. To fix this issue, one can reduce all the
393 * wheel velocities to make sure that all requested module velocities are
394 * at-or-below the absolute threshold, while maintaining the ratio of
395 * velocities between modules.
396 *
397 * Scaling down the module velocities rotates the direction of net motion in
398 * the opposite direction of rotational velocity, which makes discretizing the
399 * chassis velocities inaccurate because the discretization did not account
400 * for this translational skew.
401 *
402 * @param moduleVelocities Reference to array of module states. The array will
403 * be mutated with the normalized velocities!
404 * @param desiredChassisVelocity The desired velocity of the robot
405 * @param attainableMaxModuleVelocity The absolute max velocity a module can
406 * reach
407 * @param attainableMaxRobotTranslationVelocity The absolute max velocity the
408 * robot can reach while translating
409 * @param attainableMaxRobotRotationVelocity The absolute max velocity the
410 * robot can reach while rotating
411 */
414 ChassisVelocities desiredChassisVelocity,
415 wpi::units::meters_per_second_t attainableMaxModuleVelocity,
416 wpi::units::meters_per_second_t attainableMaxRobotTranslationVelocity,
417 wpi::units::radians_per_second_t attainableMaxRobotRotationVelocity) {
418 auto& states = *moduleVelocities;
419
420 auto realMaxVelocity = wpi::units::math::abs(
421 std::max_element(states.begin(), states.end(),
422 [](const auto& a, const auto& b) {
423 return wpi::units::math::abs(a.velocity) <
424 wpi::units::math::abs(b.velocity);
425 })
426 ->velocity);
427
428 if (attainableMaxRobotTranslationVelocity == 0_mps ||
429 attainableMaxRobotRotationVelocity == 0_rad_per_s ||
430 realMaxVelocity == 0_mps) {
431 return;
432 }
433
434 auto translationalK = wpi::units::math::hypot(desiredChassisVelocity.vx,
435 desiredChassisVelocity.vy) /
436 attainableMaxRobotTranslationVelocity;
437
438 auto rotationalK = wpi::units::math::abs(desiredChassisVelocity.omega) /
439 attainableMaxRobotRotationVelocity;
440
441 auto k = wpi::units::math::max(translationalK, rotationalK);
442
443 auto scale =
444 wpi::units::math::min(k * attainableMaxModuleVelocity / realMaxVelocity,
445 wpi::units::scalar_t{1});
446 for (auto& module : states) {
447 module.velocity = module.velocity * scale;
448 }
449 }
450
454 double t) const override {
457 for (size_t i = 0; i < NumModules; ++i) {
458 result[i] = start[i].Interpolate(end[i], t);
459 }
460 return {result};
461 }
462
464 return m_modules;
465 }
466
467 /**
468 * Performs inverse kinematics to return the module accelerations from a
469 * desired chassis acceleration. This method is often used for dynamics
470 * calculations -- converting desired robot accelerations into individual
471 * module accelerations.
472 *
473 * This function also supports variable centers of rotation. During normal
474 * operations, the center of rotation is usually the same as the physical
475 * center of the robot; therefore, the argument is defaulted to that use case.
476 * However, if you wish to change the center of rotation for evasive
477 * maneuvers, vision alignment, or for any other use case, you can do so.
478 *
479 * @param chassisAccelerations The desired chassis accelerations.
480 * @param angularVelocity The desired robot angular velocity.
481 * @param centerOfRotation The center of rotation. For example, if you set the
482 * center of rotation at one corner of the robot and provide a chassis
483 * acceleration that only has a dtheta component, the robot will rotate
484 * around that corner.
485 * @return An array containing the module accelerations.
486 */
489 const ChassisAccelerations& chassisAccelerations,
490 const units::radians_per_second_t angularVelocity = 0.0_rad_per_s,
491 const Translation2d& centerOfRotation = Translation2d{}) const {
492 // Derivation for second-order kinematics from "Swerve Drive Second Order
493 // Kinematics" by FRC Team 449 - The Blair Robot Project, Rafi Pedersen
494 // https://www.chiefdelphi.com/uploads/short-url/qzj4k2LyBs7rLxAem0YajNIlStH.pdf
495
498
499 if (chassisAccelerations.ax == 0.0_mps_sq &&
500 chassisAccelerations.ay == 0.0_mps_sq &&
501 chassisAccelerations.alpha == 0.0_rad_per_s_sq) {
502 for (size_t i = 0; i < NumModules; i++) {
503 moduleAccelerations[i] = {0.0_mps_sq, Rotation2d{0.0_rad}};
504 }
505 return moduleAccelerations;
506 }
507
508 if (centerOfRotation != m_previousCoR) {
509 SetInverseKinematics(centerOfRotation);
510 }
511
512 Eigen::Vector4d chassisAccelerationsVector{
513 chassisAccelerations.ax.value(), chassisAccelerations.ay.value(),
514 angularVelocity.value() * angularVelocity.value(),
515 chassisAccelerations.alpha.value()};
516
517 Matrixd<NumModules * 2, 1> moduleAccelerationsMatrix =
518 m_secondOrderInverseKinematics * chassisAccelerationsVector;
519
520 for (size_t i = 0; i < NumModules; i++) {
521 units::meters_per_second_squared_t x{moduleAccelerationsMatrix(i * 2, 0)};
522 units::meters_per_second_squared_t y{
523 moduleAccelerationsMatrix(i * 2 + 1, 0)};
524
525 // For swerve modules, we need to compute both linear acceleration and
526 // angular acceleration The linear acceleration is the magnitude of the
527 // acceleration vector
528 units::meters_per_second_squared_t linearAcceleration =
529 units::math::hypot(x, y);
530
531 if (linearAcceleration.value() < 1e-6) {
532 moduleAccelerations[i] = {linearAcceleration, {}};
533 } else {
534 moduleAccelerations[i] = {linearAcceleration,
535 Rotation2d{x.value(), y.value()}};
536 }
537 }
538
539 return moduleAccelerations;
540 }
541
542 /**
543 * Performs inverse kinematics to return the module accelerations from a
544 * desired chassis acceleration. This method is often used for dynamics
545 * calculations -- converting desired robot accelerations into individual
546 * module accelerations.
547 *
548 * @param chassisAccelerations The desired chassis accelerations.
549 * @return An array containing the module accelerations.
550 */
552 const ChassisAccelerations& chassisAccelerations) const override {
553 return ToSwerveModuleAccelerations(chassisAccelerations);
554 }
555
556 /**
557 * Performs forward kinematics to return the resulting chassis accelerations
558 * from the given module accelerations. This method is often used for dynamics
559 * calculations -- determining the robot's acceleration on the field using
560 * data from the real-world acceleration of each module on the robot.
561 *
562 * @param moduleAccelerations The accelerations of the modules as measured
563 * from respective encoders and gyros. The order of the swerve module
564 * accelerations should be same as passed into the constructor of this
565 * class.
566 * @return The resulting chassis accelerations.
567 */
568 template <
569 std::convertible_to<SwerveModuleAcceleration>... ModuleAccelerations>
570 requires(sizeof...(ModuleAccelerations) == NumModules)
572 ModuleAccelerations&&... moduleAccelerations) const {
573 return this->ToChassisAccelerations(
575 moduleAccelerations...});
576 }
577
578 /**
579 * Performs forward kinematics to return the resulting chassis accelerations
580 * from the given module accelerations. This method is often used for dynamics
581 * calculations -- determining the robot's acceleration on the field using
582 * data from the real-world acceleration of each module on the robot.
583 *
584 * @param moduleAccelerations The accelerations of the modules as measured
585 * from respective encoders and gyros. The order of the swerve module
586 * accelerations should be same as passed into the constructor of this
587 * class.
588 * @return The resulting chassis accelerations.
589 */
592 moduleAccelerations) const override {
593 // Derivation for second-order kinematics from "Swerve Drive Second Order
594 // Kinematics" by FRC Team 449 - The Blair Robot Project, Rafi Pedersen
595 // https://www.chiefdelphi.com/uploads/short-url/qzj4k2LyBs7rLxAem0YajNIlStH.pdf
596
597 Matrixd<NumModules * 2, 1> moduleAccelerationsMatrix;
598
599 for (size_t i = 0; i < NumModules; i++) {
600 SwerveModuleAcceleration module = moduleAccelerations[i];
601
602 moduleAccelerationsMatrix(i * 2 + 0, 0) =
603 module.acceleration.value() * module.angle.Cos();
604 moduleAccelerationsMatrix(i * 2 + 1, 0) =
605 module.acceleration.value() * module.angle.Sin();
606 }
607
608 Eigen::Vector4d chassisAccelerationsVector =
609 m_secondOrderForwardKinematics.solve(moduleAccelerationsMatrix);
610
611 // the second order kinematics equation for swerve drive yields a state
612 // vector [aₓ, a_y, ω², α]
613 return {units::meters_per_second_squared_t{chassisAccelerationsVector(0)},
614 units::meters_per_second_squared_t{chassisAccelerationsVector(1)},
615 units::radians_per_second_squared_t{chassisAccelerationsVector(3)}};
616 }
617
618 private:
620 mutable Matrixd<NumModules * 2, 3> m_firstOrderInverseKinematics;
621 Eigen::HouseholderQR<Matrixd<NumModules * 2, 3>>
622 m_firstOrderForwardKinematics;
623 mutable Matrixd<NumModules * 2, 4> m_secondOrderInverseKinematics;
624 Eigen::HouseholderQR<Matrixd<NumModules * 2, 4>>
625 m_secondOrderForwardKinematics;
626 mutable wpi::util::array<Rotation2d, NumModules> m_moduleHeadings;
627
628 mutable Translation2d m_previousCoR;
629
630 /**
631 * Sets both inverse kinematics matrices based on the new center of rotation.
632 * This does not check if the new center of rotation is different from the
633 * previous one, so a check should be included before the call to this
634 * function.
635 *
636 * @param centerOfRotation new center of rotation
637 */
638 void SetInverseKinematics(const Translation2d& centerOfRotation) const {
639 for (size_t i = 0; i < NumModules; i++) {
640 const double rx = m_modules[i].X().value() - centerOfRotation.X().value();
641 const double ry = m_modules[i].Y().value() - centerOfRotation.Y().value();
642
643 m_firstOrderInverseKinematics.row(i * 2 + 0) << 1, 0, -ry;
644 m_firstOrderInverseKinematics.row(i * 2 + 1) << 0, 1, rx;
645
646 m_secondOrderInverseKinematics.row(i * 2 + 0) << 1, 0, -rx, -ry;
647 m_secondOrderInverseKinematics.row(i * 2 + 1) << 0, 1, -ry, +rx;
648 }
649 m_previousCoR = centerOfRotation;
650 }
651};
652
653template <typename ModuleTranslation, typename... ModuleTranslations>
654SwerveDriveKinematics(ModuleTranslation, ModuleTranslations...)
655 -> SwerveDriveKinematics<1 + sizeof...(ModuleTranslations)>;
656
657extern template class EXPORT_TEMPLATE_DECLARE(WPILIB_DLLEXPORT)
659
660} // namespace wpi::math
661
#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:26
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:551
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:488
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:463
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
Twist2d ToTwist2d(ModuleDeltas &&... moduleDeltas) const
Performs forward kinematics to return the resulting Twist2d from the given module position deltas.
Definition SwerveDriveKinematics.hpp:295
static void 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:365
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:451
ChassisVelocities ToChassisVelocities(ModuleVelocities &&... moduleVelocities) const
Performs forward kinematics to return the resulting chassis state from the given module states.
Definition SwerveDriveKinematics.hpp:241
ChassisAccelerations ToChassisAccelerations(ModuleAccelerations &&... moduleAccelerations) const
Performs forward kinematics to return the resulting chassis accelerations from the given module accel...
Definition SwerveDriveKinematics.hpp:571
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:590
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
static void 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:412
Represents a translation in 2D space.
Definition Translation2d.hpp:30
constexpr wpi::units::meter_t Y() const
Returns the Y component of the translation.
Definition Translation2d.hpp:109
constexpr wpi::units::meter_t X() const
Returns the X component of the translation.
Definition Translation2d.hpp:102
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