|
8 | 8 | #include "software/geom/angular_velocity.h" |
9 | 9 | #include "software/geom/vector.h" |
10 | 10 |
|
| 11 | +#ifdef DEBUG_WHEEL |
11 | 12 | EuclideanToWheel::EuclideanToWheel(const robot_constants::RobotConstants& robot_constants) |
12 | 13 | : robot_constants_(robot_constants) |
13 | 14 | { |
14 | 15 | // Angles [rads] |
15 | | - const double p = robot_constants_.front_wheel_angle_deg * M_PI / 180.; |
16 | | - const double t = robot_constants_.back_wheel_angle_deg * M_PI / 180.; |
17 | | - |
18 | | - // Beta is angle of wheel rolling direction relative to X-axis |
19 | | - // LOOK AT (software)/src/shared/robot_constants.h to see X-axis |
20 | | - const double b_fr = -(M_PI - p); |
21 | | - const double b_fl = -p; |
22 | | - const double b_bl = t; |
23 | | - const double b_br = (M_PI - t); |
24 | | - |
25 | | - // Mapped to the robot frame: +X = Forward, +Y = Left |
26 | | - const double fr_x = robot_constants_.fr_x_pos_meters; |
27 | | - const double fr_y = robot_constants_.fr_y_pos_meters; |
28 | | - const double fl_x = robot_constants_.fl_x_pos_meters; |
29 | | - const double fl_y = robot_constants_.fl_y_pos_meters; |
30 | | - const double bl_x = robot_constants_.bl_x_pos_meters; |
31 | | - const double bl_y = robot_constants_.bl_y_pos_meters; |
32 | | - const double br_x = robot_constants_.br_x_pos_meters; |
33 | | - const double br_y = robot_constants_.br_y_pos_meters; |
34 | | - |
35 | | - |
36 | | - // Assuming that CCW when looking end of shaft into motor is the positive direction. |
37 | | - // Formula is u_1 = v_x * cos(B_1) + v_y * sin(B_1) + W * (x_1 * sin(B_1) - y_1 * |
38 | | - // cos(B_1)) |
| 16 | + auto p = robot_constants_.front_wheel_angle_deg * M_PI / 180.; |
| 17 | + auto t = robot_constants_.back_wheel_angle_deg * M_PI / 180.; |
| 18 | + |
| 19 | + auto cos_p = std::cos(p); |
| 20 | + auto sin_p = std::sin(p); |
| 21 | + auto cos_t = std::cos(t); |
| 22 | + auto sin_t = std::sin(t); |
| 23 | + |
| 24 | + // 1. Physical wheel coordinates in meters |
| 25 | + // Mapped to the robot frame: +X = Right, +Y = Forward |
| 26 | + double fr_x = 0.06632, fr_y = 0.03485; |
| 27 | + double br_x = 0.05592, br_y = -0.04985; |
| 28 | + |
| 29 | + // 2. Unit drive vectors (extracted directly from the matrix's linear columns) |
| 30 | + double fr_dx = -sin_p, fr_dy = cos_p; |
| 31 | + double br_dx = sin_t, br_dy = cos_t; |
| 32 | + |
| 33 | + // 3. Dynamically calculate the rotational lever arms using the 2D cross product |
| 34 | + // Lever Arm = | X * Dy - Y * Dx | |
| 35 | + double rot_f = std::abs((fr_x * fr_dy) - (fr_y * fr_dx)); |
| 36 | + double rot_b = std::abs((br_x * br_dy) - (br_y * br_dx)); |
| 37 | + |
| 38 | + // clang-format off |
| 39 | + euclidean_to_wheel_velocity_D_ << |
| 40 | + -sin_p, cos_p, rot_f, |
| 41 | + -sin_p, -cos_p, rot_f, |
| 42 | + sin_t, -cos_t, rot_b, |
| 43 | + sin_t, cos_t, rot_b; |
| 44 | + // clang-format on |
| 45 | + |
| 46 | + // Calculate Pseudo-inverse dynamically |
| 47 | + wheel_to_euclidean_velocity_D_inverse_ = |
| 48 | + (euclidean_to_wheel_velocity_D_.transpose() * euclidean_to_wheel_velocity_D_) |
| 49 | + .inverse() * |
| 50 | + euclidean_to_wheel_velocity_D_.transpose(); |
| 51 | +} |
| 52 | + |
| 53 | +#else |
| 54 | + |
| 55 | +EuclideanToWheel::EuclideanToWheel(const robot_constants::RobotConstants& robot_constants) |
| 56 | + : robot_constants_(robot_constants) |
| 57 | +{ |
| 58 | + // Phi, the angle between the hemisphere line of the robot and the front wheel axles |
| 59 | + // [rads] |
| 60 | + auto p = robot_constants_.front_wheel_angle_deg * M_PI / 180.; |
| 61 | + |
| 62 | + // Theta, the angle between the hemisphere line of the robot and the rear wheel axles |
| 63 | + // [rads] |
| 64 | + auto t = robot_constants_.back_wheel_angle_deg * M_PI / 180.; |
| 65 | + |
| 66 | + // Caching repeated calculations |
| 67 | + auto cos_p = std::cos(p); |
| 68 | + auto cos_t = std::cos(t); |
| 69 | + auto sin_p = std::sin(p); |
| 70 | + auto sin_t = std::sin(t); |
39 | 71 |
|
40 | 72 | // clang-format off |
41 | 73 | euclidean_to_wheel_velocity_D_ << |
42 | | - std::cos(b_fr), std::sin(b_fr), (fr_x * std::sin(b_fr) - fr_y * std::cos(b_fr)), |
43 | | - std::cos(b_fl), std::sin(b_fl), (fl_x * std::sin(b_fl) - fl_y * std::cos(b_fl)), |
44 | | - std::cos(b_bl), std::sin(b_bl), (bl_x * std::sin(b_bl) - bl_y * std::cos(b_bl)), |
45 | | - std::cos(b_br), std::sin(b_br), (br_x * std::sin(b_br) - br_y * std::cos(b_br)); |
| 74 | + -sin_p, cos_p, 1, |
| 75 | + -sin_p, -cos_p, 1, |
| 76 | + sin_t, -cos_t, 1, |
| 77 | + sin_t, cos_t, 1; |
46 | 78 | // clang-format on |
47 | 79 |
|
48 | 80 | // Inverse of euclidean to wheel matrix (D) for converting wheel velocity to euclidean |
49 | 81 | // velocity. |
50 | 82 | // NOTE: The pseudoinverse given in the paper |
51 | 83 | // (http://robocup.mi.fu-berlin.de/buch/omnidrive.pdf pg 17) is incorrect. The inverse |
52 | 84 | // was calculated using Wolfram Alpha: https://bit.ly/3A08BJX |
| 85 | + auto i = 1 / (2 * sin_p + 2 * sin_t); |
53 | 86 |
|
54 | | - // Calculate Pseudo-inverse dynamically |
| 87 | + auto j_denom = 2 * cos_p * cos_p + 2 * cos_t * cos_t; |
| 88 | + auto j1 = cos_p / j_denom; |
| 89 | + auto j2 = cos_t / j_denom; |
55 | 90 |
|
56 | | - wheel_to_euclidean_velocity_D_inverse_ = |
57 | | - euclidean_to_wheel_velocity_D_.completeOrthogonalDecomposition().pseudoInverse(); |
| 91 | + auto k_denom = 2 * sin_p + 2 * sin_t; |
| 92 | + auto k1 = sin_t / k_denom; |
| 93 | + auto k2 = sin_p / k_denom; |
| 94 | + |
| 95 | + // clang-format off |
| 96 | + wheel_to_euclidean_velocity_D_inverse_ << |
| 97 | + -i, -i, i, i, |
| 98 | + j1, -j1, -j2, j2, |
| 99 | + k1, k1, k2, k2; |
| 100 | + // clang-format on |
58 | 101 | } |
59 | 102 |
|
| 103 | +#endif |
| 104 | + |
| 105 | +#ifdef DEBUG_WHEEL |
60 | 106 | WheelSpace_t EuclideanToWheel::getWheelVelocity(EuclideanSpace_t euclidean_velocity) const |
61 | 107 | { |
62 | 108 | // The generalized D matrix natively handles the w -> tangential velocity |
63 | 109 | // conversion because its third column already represents the lever arm in meters. |
64 | 110 | return euclidean_to_wheel_velocity_D_ * euclidean_velocity; |
65 | 111 | } |
66 | 112 |
|
| 113 | + |
67 | 114 | EuclideanSpace_t EuclideanToWheel::getEuclideanVelocity( |
68 | 115 | const WheelSpace_t& wheel_velocity) const |
69 | 116 | { |
70 | 117 | // The D inverse matrix natively outputs w in rad/s. |
71 | 118 | return wheel_to_euclidean_velocity_D_inverse_ * wheel_velocity; |
72 | 119 | } |
73 | 120 |
|
| 121 | +#else |
| 122 | + |
| 123 | +WheelSpace_t EuclideanToWheel::getWheelVelocity(EuclideanSpace_t euclidean_velocity) const |
| 124 | +{ |
| 125 | + // need to multiply the angular velocity by the robot radius to |
| 126 | + // calculate the wheel velocity (robot tangential velocity) |
| 127 | + // ref: http://robocup.mi.fu-berlin.de/buch/omnidrive.pdf pg 8 |
| 128 | + euclidean_velocity[2] = euclidean_velocity[2] * robot_constants_.robot_radius_m; |
| 129 | + |
| 130 | + return euclidean_to_wheel_velocity_D_ * euclidean_velocity; |
| 131 | +} |
| 132 | + |
| 133 | +EuclideanSpace_t EuclideanToWheel::getEuclideanVelocity( |
| 134 | + const WheelSpace_t& wheel_velocity) const |
| 135 | +{ |
| 136 | + EuclideanSpace_t euclidean_velocity = |
| 137 | + wheel_to_euclidean_velocity_D_inverse_ * wheel_velocity; |
| 138 | + |
| 139 | + // The above multiplication will calculate the tangential robot |
| 140 | + // velocity. This can be divided by the robot radius to calculate |
| 141 | + // the angular velocity |
| 142 | + // ref: http://robocup.mi.fu-berlin.de/buch/omnidrive.pdf pg 8 |
| 143 | + euclidean_velocity[2] = euclidean_velocity[2] / robot_constants_.robot_radius_m; |
| 144 | + |
| 145 | + return euclidean_velocity; |
| 146 | +} |
| 147 | +#endif |
| 148 | + |
74 | 149 | WheelSpace_t EuclideanToWheel::rampWheelVelocity( |
75 | 150 | const WheelSpace_t& current_wheel_velocity, const WheelSpace_t& target_wheel_velocity, |
76 | 151 | const double& time_to_ramp) |
|
0 commit comments