blob: 832796a6a3420cda9811fb91aaf449a5801425b9 [file] [log] [blame]
Austin Schuh74455862018-02-17 17:14:59 -08001#ifndef Y2018_CONTROL_LOOPS_SUPERSTRUCTURE_ARM_DYNAMICS_H_
2#define Y2018_CONTROL_LOOPS_SUPERSTRUCTURE_ARM_DYNAMICS_H_
3
4#include "Eigen/Dense"
5
6#include "frc971/control_loops/runge_kutta.h"
7
8namespace y2018 {
9namespace control_loops {
10namespace superstructure {
11namespace arm {
12
13// This class captures the dynamics of our system. It doesn't actually need to
14// store state yet, so everything can be constexpr and/or static.
15class Dynamics {
16 public:
17 // Below, 1 refers to the proximal joint, and 2 refers to the distal joint.
18 // Length of the joints in meters.
19 static constexpr double kL1 = 46.25 * 0.0254;
20 static constexpr double kL2 = 41.80 * 0.0254;
21
22 // Mass of the joints in kilograms.
23 static constexpr double kM1 = 9.34 / 2.2;
24 static constexpr double kM2 = 9.77 / 2.2;
25
26 // Moment of inertia of the joints in kg m^2
27 static constexpr double kJ1 = 2957.05 * 0.0002932545454545454;
28 static constexpr double kJ2 = 2824.70 * 0.0002932545454545454;
29
30 // Radius of the center of mass of the joints in meters.
31 static constexpr double r1 = 21.64 * 0.0254;
32 static constexpr double r2 = 26.70 * 0.0254;
33
34 // Gear ratios for the two joints.
35 static constexpr double kG1 = 140.0;
36 static constexpr double kG2 = 90.0;
37
38 // MiniCIM motor constants.
39 static constexpr double kStallTorque = 1.41;
40 static constexpr double kFreeSpeed = (5840.0 / 60.0) * 2.0 * M_PI;
41 static constexpr double kStallCurrent = 89.0;
42 static constexpr double kResistance = 12.0 / kStallCurrent;
43 static constexpr double Kv = kFreeSpeed / 12.0;
44 static constexpr double Kt = kStallTorque / kStallCurrent;
45
46 // Number of motors on the distal joint.
47 static constexpr double kNumDistalMotors = 2.0;
48
49 static constexpr double kAlpha = kJ1 + r1 * r1 * kM1 + kL1 * kL1 * kM2;
50 static constexpr double kBeta = kL1 * r2 * kM2;
51 static constexpr double kGamma = kJ2 + r2 * r2 * kM2;
52
53 // K3, K4 matricies described below.
54 static const ::Eigen::Matrix<double, 2, 2> K3;
Austin Schuh8e99b822018-02-18 00:15:36 -080055 static const ::Eigen::Matrix<double, 2, 2> K3_inverse;
Austin Schuh74455862018-02-17 17:14:59 -080056 static const ::Eigen::Matrix<double, 2, 2> K4;
57
58 // Generates K1-2 for the arm ODE.
59 // K1 * d^2 theta / dt^2 + K2 * d theta / dt = K3 * V - K4 * d theta/dt
60 // These matricies are missing the velocity factor for K2[1, 0], and K2[0, 1].
61 // You probbaly want MatriciesForState.
62 static void NormilizedMatriciesForState(
63 const ::Eigen::Matrix<double, 4, 1> &X,
64 ::Eigen::Matrix<double, 2, 2> *K1_result,
65 ::Eigen::Matrix<double, 2, 2> *K2_result) {
66 const double angle = X(0, 0) - X(2, 0);
67 const double s = ::std::sin(angle);
68 const double c = ::std::cos(angle);
69 *K1_result << kAlpha, c * kBeta, c * kBeta, kGamma;
70 *K2_result << 0.0, s * kBeta, -s * kBeta, 0.0;
71 }
72
73 // Generates K1-2 for the arm ODE.
74 // K1 * d^2 theta / dt^2 + K2 * d theta / dt = K3 * V - K4 * d theta/dt
75 static void MatriciesForState(const ::Eigen::Matrix<double, 4, 1> &X,
76 ::Eigen::Matrix<double, 2, 2> *K1_result,
77 ::Eigen::Matrix<double, 2, 2> *K2_result) {
78 NormilizedMatriciesForState(X, K1_result, K2_result);
79 (*K2_result)(1, 0) *= X(1, 0);
80 (*K2_result)(0, 1) *= X(3, 0);
81 }
82
83 // TODO(austin): We may want a way to provide K1 and K2 to save CPU cycles.
84
85 // Calculates the acceleration given the current state and control input.
86 static const ::Eigen::Matrix<double, 4, 1> Acceleration(
87 const ::Eigen::Matrix<double, 4, 1> &X,
88 const ::Eigen::Matrix<double, 2, 1> &U) {
89 ::Eigen::Matrix<double, 2, 2> K1;
90 ::Eigen::Matrix<double, 2, 2> K2;
91
92 MatriciesForState(X, &K1, &K2);
93
94 const ::Eigen::Matrix<double, 2, 1> velocity =
95 (::Eigen::Matrix<double, 2, 1>() << X(1, 0), X(3, 0)).finished();
96
97 const ::Eigen::Matrix<double, 2, 1> torque = K3 * U - K4 * velocity;
98
99 const ::Eigen::Matrix<double, 2, 1> accel =
100 K1.inverse() * (torque - K2 * velocity);
101
102 return (::Eigen::Matrix<double, 4, 1>() << X(1, 0), accel(0, 0), X(3, 0),
103 accel(1, 0))
104 .finished();
105 }
106
107 // Calculates the voltage required to follow the trajectory. This requires
108 // knowing the current state, desired angular velocity and acceleration.
109 static const ::Eigen::Matrix<double, 2, 1> FF_U(
110 const ::Eigen::Matrix<double, 4, 1> &X,
111 const ::Eigen::Matrix<double, 2, 1> &omega_t,
112 const ::Eigen::Matrix<double, 2, 1> &alpha_t) {
113 ::Eigen::Matrix<double, 2, 2> K1;
114 ::Eigen::Matrix<double, 2, 2> K2;
115
116 MatriciesForState(X, &K1, &K2);
117
Austin Schuh8e99b822018-02-18 00:15:36 -0800118 return K3_inverse * (K1 * alpha_t + K2 * omega_t + K4 * omega_t);
Austin Schuh74455862018-02-17 17:14:59 -0800119 }
120
121 static const ::Eigen::Matrix<double, 4, 1> UnboundedDiscreteDynamics(
122 const ::Eigen::Matrix<double, 4, 1> &X,
123 const ::Eigen::Matrix<double, 2, 1> &U, double dt) {
124 return ::frc971::control_loops::RungeKutta(Dynamics::Acceleration, X, U,
125 dt);
126 }
127};
128
129} // namespace arm
130} // namespace superstructure
131} // namespace control_loops
132} // namespace y2018
133
134#endif // Y2018_CONTROL_LOOPS_SUPERSTRUCTURE_ARM_DYNAMICS_H_