blob: 7ad669691cf20d2633af30bac4de0665b49da5d0 [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;
55 static const ::Eigen::Matrix<double, 2, 2> K4;
56
57 // Generates K1-2 for the arm ODE.
58 // K1 * d^2 theta / dt^2 + K2 * d theta / dt = K3 * V - K4 * d theta/dt
59 // These matricies are missing the velocity factor for K2[1, 0], and K2[0, 1].
60 // You probbaly want MatriciesForState.
61 static void NormilizedMatriciesForState(
62 const ::Eigen::Matrix<double, 4, 1> &X,
63 ::Eigen::Matrix<double, 2, 2> *K1_result,
64 ::Eigen::Matrix<double, 2, 2> *K2_result) {
65 const double angle = X(0, 0) - X(2, 0);
66 const double s = ::std::sin(angle);
67 const double c = ::std::cos(angle);
68 *K1_result << kAlpha, c * kBeta, c * kBeta, kGamma;
69 *K2_result << 0.0, s * kBeta, -s * kBeta, 0.0;
70 }
71
72 // Generates K1-2 for the arm ODE.
73 // K1 * d^2 theta / dt^2 + K2 * d theta / dt = K3 * V - K4 * d theta/dt
74 static void MatriciesForState(const ::Eigen::Matrix<double, 4, 1> &X,
75 ::Eigen::Matrix<double, 2, 2> *K1_result,
76 ::Eigen::Matrix<double, 2, 2> *K2_result) {
77 NormilizedMatriciesForState(X, K1_result, K2_result);
78 (*K2_result)(1, 0) *= X(1, 0);
79 (*K2_result)(0, 1) *= X(3, 0);
80 }
81
82 // TODO(austin): We may want a way to provide K1 and K2 to save CPU cycles.
83
84 // Calculates the acceleration given the current state and control input.
85 static const ::Eigen::Matrix<double, 4, 1> Acceleration(
86 const ::Eigen::Matrix<double, 4, 1> &X,
87 const ::Eigen::Matrix<double, 2, 1> &U) {
88 ::Eigen::Matrix<double, 2, 2> K1;
89 ::Eigen::Matrix<double, 2, 2> K2;
90
91 MatriciesForState(X, &K1, &K2);
92
93 const ::Eigen::Matrix<double, 2, 1> velocity =
94 (::Eigen::Matrix<double, 2, 1>() << X(1, 0), X(3, 0)).finished();
95
96 const ::Eigen::Matrix<double, 2, 1> torque = K3 * U - K4 * velocity;
97
98 const ::Eigen::Matrix<double, 2, 1> accel =
99 K1.inverse() * (torque - K2 * velocity);
100
101 return (::Eigen::Matrix<double, 4, 1>() << X(1, 0), accel(0, 0), X(3, 0),
102 accel(1, 0))
103 .finished();
104 }
105
106 // Calculates the voltage required to follow the trajectory. This requires
107 // knowing the current state, desired angular velocity and acceleration.
108 static const ::Eigen::Matrix<double, 2, 1> FF_U(
109 const ::Eigen::Matrix<double, 4, 1> &X,
110 const ::Eigen::Matrix<double, 2, 1> &omega_t,
111 const ::Eigen::Matrix<double, 2, 1> &alpha_t) {
112 ::Eigen::Matrix<double, 2, 2> K1;
113 ::Eigen::Matrix<double, 2, 2> K2;
114
115 MatriciesForState(X, &K1, &K2);
116
117 return K3.inverse() * (K1 * alpha_t + K2 * omega_t + K4 * omega_t);
118 }
119
120 static const ::Eigen::Matrix<double, 4, 1> UnboundedDiscreteDynamics(
121 const ::Eigen::Matrix<double, 4, 1> &X,
122 const ::Eigen::Matrix<double, 2, 1> &U, double dt) {
123 return ::frc971::control_loops::RungeKutta(Dynamics::Acceleration, X, U,
124 dt);
125 }
126};
127
128} // namespace arm
129} // namespace superstructure
130} // namespace control_loops
131} // namespace y2018
132
133#endif // Y2018_CONTROL_LOOPS_SUPERSTRUCTURE_ARM_DYNAMICS_H_