blob: 7275d0dc61075836945b42ede8537079c0a0ce07 [file] [log] [blame]
Brian Silverman17f503e2015-08-02 18:17:18 -07001#include "y2014/actors/drivetrain_actor.h"
2
3#include <functional>
4#include <numeric>
5
6#include <Eigen/Dense>
7
John Park33858a32018-09-28 23:05:48 -07008#include "aos/util/phased_loop.h"
9#include "aos/logging/logging.h"
10#include "aos/util/trapezoid_profile.h"
11#include "aos/commonmath.h"
12#include "aos/time/time.h"
Brian Silverman17f503e2015-08-02 18:17:18 -070013
Austin Schuh3130b372016-02-17 00:34:51 -080014#include "frc971/control_loops/drivetrain/drivetrain.q.h"
Brian Silverman17f503e2015-08-02 18:17:18 -070015#include "y2014/actors/drivetrain_actor.h"
16#include "y2014/constants.h"
Austin Schuh3130b372016-02-17 00:34:51 -080017#include "y2014/control_loops/drivetrain/drivetrain_dog_motor_plant.h"
Brian Silverman17f503e2015-08-02 18:17:18 -070018
Brian Silvermanb601d892015-12-20 18:24:38 -050019namespace y2014 {
Brian Silverman17f503e2015-08-02 18:17:18 -070020namespace actors {
21
Austin Schuh214e9c12016-11-25 17:26:20 -080022namespace chrono = ::std::chrono;
23
Brian Silverman17f503e2015-08-02 18:17:18 -070024DrivetrainActor::DrivetrainActor(actors::DrivetrainActionQueueGroup* s)
Austin Schuhadf2cde2015-11-08 20:35:16 -080025 : aos::common::actions::ActorBase<actors::DrivetrainActionQueueGroup>(s),
26 loop_(constants::GetValues().make_drivetrain_loop()) {
Austin Schuhc5fceb82017-02-25 16:24:12 -080027 loop_.set_index(3);
Austin Schuhadf2cde2015-11-08 20:35:16 -080028}
Brian Silverman17f503e2015-08-02 18:17:18 -070029
30bool DrivetrainActor::RunAction(const actors::DrivetrainActionParams &params) {
Austin Schuh32501832017-02-25 18:32:56 -080031 static const auto &K = loop_.controller().K();
Brian Silverman17f503e2015-08-02 18:17:18 -070032
33 const double yoffset = params.y_offset;
34 const double turn_offset =
Austin Schuh3130b372016-02-17 00:34:51 -080035 params.theta_offset * control_loops::drivetrain::kRobotRadius;
Brian Silverman17f503e2015-08-02 18:17:18 -070036 LOG(INFO, "Going to move %f and turn %f\n", yoffset, turn_offset);
37
38 // Measured conversion to get the distance right.
Austin Schuh214e9c12016-11-25 17:26:20 -080039 ::aos::util::TrapezoidProfile profile(chrono::milliseconds(5));
40 ::aos::util::TrapezoidProfile turn_profile(chrono::milliseconds(5));
Brian Silverman17f503e2015-08-02 18:17:18 -070041 const double goal_velocity = 0.0;
42 const double epsilon = 0.01;
43 ::Eigen::Matrix<double, 2, 1> left_goal_state, right_goal_state;
44
45 profile.set_maximum_acceleration(params.maximum_acceleration);
46 profile.set_maximum_velocity(params.maximum_velocity);
Austin Schuh3130b372016-02-17 00:34:51 -080047 turn_profile.set_maximum_acceleration(
48 params.maximum_turn_acceleration *
49 control_loops::drivetrain::kRobotRadius);
Brian Silverman17f503e2015-08-02 18:17:18 -070050 turn_profile.set_maximum_velocity(params.maximum_turn_velocity *
Austin Schuh3130b372016-02-17 00:34:51 -080051 control_loops::drivetrain::kRobotRadius);
Brian Silverman17f503e2015-08-02 18:17:18 -070052
Austin Schuhf2a50ba2016-12-24 16:16:26 -080053 ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
54 ::std::chrono::milliseconds(5) / 2);
Brian Silverman17f503e2015-08-02 18:17:18 -070055 while (true) {
Austin Schuhf2a50ba2016-12-24 16:16:26 -080056 phased_loop.SleepUntilNext();
Brian Silverman17f503e2015-08-02 18:17:18 -070057
Comran Morshed5323ecb2015-12-26 20:50:55 +000058 ::frc971::control_loops::drivetrain_queue.status.FetchLatest();
59 if (::frc971::control_loops::drivetrain_queue.status.get()) {
Austin Schuh3130b372016-02-17 00:34:51 -080060 const auto &status = *::frc971::control_loops::drivetrain_queue.status;
Brian Silverman17f503e2015-08-02 18:17:18 -070061 if (::std::abs(status.uncapped_left_voltage -
62 status.uncapped_right_voltage) > 24) {
63 LOG(DEBUG, "spinning in place\n");
64 // They're more than 24V apart, so stop moving forwards and let it deal
65 // with spinning first.
66 profile.SetGoal(
Austin Schuh093535c2016-03-05 23:21:00 -080067 (status.estimated_left_position + status.estimated_right_position -
Brian Silverman17f503e2015-08-02 18:17:18 -070068 params.left_initial_position - params.right_initial_position) /
69 2.0);
70 } else {
71 static const double divisor = K(0, 0) + K(0, 2);
72 double dx_left, dx_right;
73 if (status.uncapped_left_voltage > 12.0) {
74 dx_left = (status.uncapped_left_voltage - 12.0) / divisor;
75 } else if (status.uncapped_left_voltage < -12.0) {
76 dx_left = (status.uncapped_left_voltage + 12.0) / divisor;
77 } else {
78 dx_left = 0;
79 }
80 if (status.uncapped_right_voltage > 12.0) {
81 dx_right = (status.uncapped_right_voltage - 12.0) / divisor;
82 } else if (status.uncapped_right_voltage < -12.0) {
83 dx_right = (status.uncapped_right_voltage + 12.0) / divisor;
84 } else {
85 dx_right = 0;
86 }
87 double dx;
88 if (dx_left == 0 && dx_right == 0) {
89 dx = 0;
90 } else if (dx_left != 0 && dx_right != 0 &&
91 ::aos::sign(dx_left) != ::aos::sign(dx_right)) {
92 // Both saturating in opposite directions. Don't do anything.
93 LOG(DEBUG, "Saturating opposite ways, not adjusting\n");
94 dx = 0;
95 } else if (::std::abs(dx_left) > ::std::abs(dx_right)) {
96 dx = dx_left;
97 } else {
98 dx = dx_right;
99 }
100 if (dx != 0) {
101 LOG(DEBUG, "adjusting goal by %f\n", dx);
102 profile.MoveGoal(-dx);
103 }
104 }
105 } else {
106 // If we ever get here, that's bad and we should just give up
107 LOG(ERROR, "no drivetrain status!\n");
108 return false;
109 }
110
111 const auto drive_profile_goal_state =
112 profile.Update(yoffset, goal_velocity);
113 const auto turn_profile_goal_state = turn_profile.Update(turn_offset, 0.0);
114 left_goal_state = drive_profile_goal_state - turn_profile_goal_state;
115 right_goal_state = drive_profile_goal_state + turn_profile_goal_state;
116
117 if (::std::abs(drive_profile_goal_state(0, 0) - yoffset) < epsilon &&
118 ::std::abs(turn_profile_goal_state(0, 0) - turn_offset) < epsilon) {
119 break;
120 }
121
122 if (ShouldCancel()) return true;
123
124 LOG(DEBUG, "Driving left to %f, right to %f\n",
125 left_goal_state(0, 0) + params.left_initial_position,
126 right_goal_state(0, 0) + params.right_initial_position);
Comran Morshed5323ecb2015-12-26 20:50:55 +0000127 ::frc971::control_loops::drivetrain_queue.goal.MakeWithBuilder()
Austin Schuh78379ea2019-01-04 20:39:45 -0800128 .controller_type(1)
Austin Schuh86f895e2015-11-08 13:40:51 -0800129 .highgear(true)
Brian Silverman17f503e2015-08-02 18:17:18 -0700130 .left_goal(left_goal_state(0, 0) + params.left_initial_position)
131 .right_goal(right_goal_state(0, 0) + params.right_initial_position)
Brian Silverman17f503e2015-08-02 18:17:18 -0700132 .Send();
133 }
134 if (ShouldCancel()) return true;
Comran Morshed5323ecb2015-12-26 20:50:55 +0000135 ::frc971::control_loops::drivetrain_queue.status.FetchLatest();
136 while (!::frc971::control_loops::drivetrain_queue.status.get()) {
Brian Silverman17f503e2015-08-02 18:17:18 -0700137 LOG(WARNING,
138 "No previous drivetrain status packet, trying to fetch again\n");
Comran Morshed5323ecb2015-12-26 20:50:55 +0000139 ::frc971::control_loops::drivetrain_queue.status.FetchNextBlocking();
Brian Silverman17f503e2015-08-02 18:17:18 -0700140 if (ShouldCancel()) return true;
141 }
142 while (true) {
143 if (ShouldCancel()) return true;
144 const double kPositionThreshold = 0.05;
145
Austin Schuh3130b372016-02-17 00:34:51 -0800146 const double left_error =
147 ::std::abs(::frc971::control_loops::drivetrain_queue.status
Austin Schuh093535c2016-03-05 23:21:00 -0800148 ->estimated_left_position -
Austin Schuh3130b372016-02-17 00:34:51 -0800149 (left_goal_state(0, 0) + params.left_initial_position));
150 const double right_error =
151 ::std::abs(::frc971::control_loops::drivetrain_queue.status
Austin Schuh093535c2016-03-05 23:21:00 -0800152 ->estimated_right_position -
Austin Schuh3130b372016-02-17 00:34:51 -0800153 (right_goal_state(0, 0) + params.right_initial_position));
154 const double velocity_error = ::std::abs(
155 ::frc971::control_loops::drivetrain_queue.status->robot_speed);
Brian Silverman17f503e2015-08-02 18:17:18 -0700156 if (left_error < kPositionThreshold && right_error < kPositionThreshold &&
157 velocity_error < 0.2) {
158 break;
159 } else {
160 LOG(DEBUG, "Drivetrain error is %f, %f, %f\n", left_error, right_error,
161 velocity_error);
162 }
Comran Morshed5323ecb2015-12-26 20:50:55 +0000163 ::frc971::control_loops::drivetrain_queue.status.FetchNextBlocking();
Brian Silverman17f503e2015-08-02 18:17:18 -0700164 }
165 LOG(INFO, "Done moving\n");
166 return true;
167}
168
169::std::unique_ptr<DrivetrainAction> MakeDrivetrainAction(
Austin Schuh3130b372016-02-17 00:34:51 -0800170 const ::y2014::actors::DrivetrainActionParams &params) {
Brian Silverman17f503e2015-08-02 18:17:18 -0700171 return ::std::unique_ptr<DrivetrainAction>(
Brian Silvermanb601d892015-12-20 18:24:38 -0500172 new DrivetrainAction(&::y2014::actors::drivetrain_action, params));
Brian Silverman17f503e2015-08-02 18:17:18 -0700173}
174
175} // namespace actors
Brian Silvermanb601d892015-12-20 18:24:38 -0500176} // namespace y2014