blob: 2276108098342a182e672a853718e81fae7d5b1b [file] [log] [blame]
Comran Morshed6c6a0a92016-01-17 12:45:16 +00001#include "y2016/actors/drivetrain_actor.h"
Comran Morshed9a9948c2016-01-16 15:58:04 +00002
3#include <functional>
4#include <numeric>
5
6#include <Eigen/Dense>
7
8#include "aos/common/util/phased_loop.h"
9#include "aos/common/logging/logging.h"
10#include "aos/common/util/trapezoid_profile.h"
11#include "aos/common/commonmath.h"
12#include "aos/common/time.h"
13
Comran Morshed6c6a0a92016-01-17 12:45:16 +000014#include "y2016/actors/drivetrain_actor.h"
15#include "y2016/constants.h"
Comran Morshed9a9948c2016-01-16 15:58:04 +000016#include "frc971/control_loops/drivetrain/drivetrain.q.h"
17
Comran Morshed6c6a0a92016-01-17 12:45:16 +000018namespace y2016 {
Comran Morshed9a9948c2016-01-16 15:58:04 +000019namespace actors {
20
Comran Morshed6c6a0a92016-01-17 12:45:16 +000021DrivetrainActor::DrivetrainActor(actors::DrivetrainActionQueueGroup *s)
Comran Morshed9a9948c2016-01-16 15:58:04 +000022 : aos::common::actions::ActorBase<actors::DrivetrainActionQueueGroup>(s),
23 loop_(constants::GetValues().make_drivetrain_loop()) {
24 loop_.set_controller_index(3);
25}
26
27bool DrivetrainActor::RunAction(const actors::DrivetrainActionParams &params) {
28 static const auto K = loop_.K();
29
30 const double yoffset = params.y_offset;
31 const double turn_offset =
32 params.theta_offset * constants::GetValues().turn_width / 2.0;
33 LOG(INFO, "Going to move %f and turn %f\n", yoffset, turn_offset);
34
35 // Measured conversion to get the distance right.
36 ::aos::util::TrapezoidProfile profile(::aos::time::Time::InMS(5));
37 ::aos::util::TrapezoidProfile turn_profile(::aos::time::Time::InMS(5));
38 const double goal_velocity = 0.0;
39 const double epsilon = 0.01;
40 ::Eigen::Matrix<double, 2, 1> left_goal_state, right_goal_state;
41
42 profile.set_maximum_acceleration(params.maximum_acceleration);
43 profile.set_maximum_velocity(params.maximum_velocity);
44 turn_profile.set_maximum_acceleration(params.maximum_turn_acceleration *
45 constants::GetValues().turn_width /
46 2.0);
47 turn_profile.set_maximum_velocity(params.maximum_turn_velocity *
48 constants::GetValues().turn_width / 2.0);
49
50 while (true) {
51 ::aos::time::PhasedLoopXMS(5, 2500);
52
53 ::frc971::control_loops::drivetrain_queue.status.FetchLatest();
54 if (::frc971::control_loops::drivetrain_queue.status.get()) {
Comran Morshed6c6a0a92016-01-17 12:45:16 +000055 const auto &status = *::frc971::control_loops::drivetrain_queue.status;
Comran Morshed9a9948c2016-01-16 15:58:04 +000056 if (::std::abs(status.uncapped_left_voltage -
57 status.uncapped_right_voltage) > 24) {
58 LOG(DEBUG, "spinning in place\n");
59 // They're more than 24V apart, so stop moving forwards and let it deal
60 // with spinning first.
61 profile.SetGoal(
62 (status.filtered_left_position + status.filtered_right_position -
63 params.left_initial_position - params.right_initial_position) /
64 2.0);
65 } else {
66 static const double divisor = K(0, 0) + K(0, 2);
67 double dx_left, dx_right;
Comran Morshed6c6a0a92016-01-17 12:45:16 +000068
Comran Morshed9a9948c2016-01-16 15:58:04 +000069 if (status.uncapped_left_voltage > 12.0) {
70 dx_left = (status.uncapped_left_voltage - 12.0) / divisor;
71 } else if (status.uncapped_left_voltage < -12.0) {
72 dx_left = (status.uncapped_left_voltage + 12.0) / divisor;
73 } else {
74 dx_left = 0;
75 }
Comran Morshed6c6a0a92016-01-17 12:45:16 +000076
Comran Morshed9a9948c2016-01-16 15:58:04 +000077 if (status.uncapped_right_voltage > 12.0) {
78 dx_right = (status.uncapped_right_voltage - 12.0) / divisor;
79 } else if (status.uncapped_right_voltage < -12.0) {
80 dx_right = (status.uncapped_right_voltage + 12.0) / divisor;
81 } else {
82 dx_right = 0;
83 }
Comran Morshed6c6a0a92016-01-17 12:45:16 +000084
Comran Morshed9a9948c2016-01-16 15:58:04 +000085 double dx;
Comran Morshed6c6a0a92016-01-17 12:45:16 +000086
Comran Morshed9a9948c2016-01-16 15:58:04 +000087 if (dx_left == 0 && dx_right == 0) {
88 dx = 0;
89 } else if (dx_left != 0 && dx_right != 0 &&
90 ::aos::sign(dx_left) != ::aos::sign(dx_right)) {
91 // Both saturating in opposite directions. Don't do anything.
92 LOG(DEBUG, "Saturating opposite ways, not adjusting\n");
93 dx = 0;
94 } else if (::std::abs(dx_left) > ::std::abs(dx_right)) {
95 dx = dx_left;
96 } else {
97 dx = dx_right;
98 }
Comran Morshed6c6a0a92016-01-17 12:45:16 +000099
Comran Morshed9a9948c2016-01-16 15:58:04 +0000100 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);
127 ::frc971::control_loops::drivetrain_queue.goal.MakeWithBuilder()
128 .control_loop_driving(true)
129 .highgear(true)
130 .left_goal(left_goal_state(0, 0) + params.left_initial_position)
131 .right_goal(right_goal_state(0, 0) + params.right_initial_position)
132 .left_velocity_goal(left_goal_state(1, 0))
133 .right_velocity_goal(right_goal_state(1, 0))
134 .Send();
135 }
136 if (ShouldCancel()) return true;
137 ::frc971::control_loops::drivetrain_queue.status.FetchLatest();
Comran Morshed6c6a0a92016-01-17 12:45:16 +0000138
Comran Morshed9a9948c2016-01-16 15:58:04 +0000139 while (!::frc971::control_loops::drivetrain_queue.status.get()) {
140 LOG(WARNING,
141 "No previous drivetrain status packet, trying to fetch again\n");
142 ::frc971::control_loops::drivetrain_queue.status.FetchNextBlocking();
143 if (ShouldCancel()) return true;
144 }
Comran Morshed6c6a0a92016-01-17 12:45:16 +0000145
Comran Morshed9a9948c2016-01-16 15:58:04 +0000146 while (true) {
147 if (ShouldCancel()) return true;
148 const double kPositionThreshold = 0.05;
149
Comran Morshed6c6a0a92016-01-17 12:45:16 +0000150 const double left_error =
151 ::std::abs(::frc971::control_loops::drivetrain_queue.status
152 ->filtered_left_position -
153 (left_goal_state(0, 0) + params.left_initial_position));
154 const double right_error =
155 ::std::abs(::frc971::control_loops::drivetrain_queue.status
156 ->filtered_right_position -
157 (right_goal_state(0, 0) + params.right_initial_position));
158 const double velocity_error = ::std::abs(
159 ::frc971::control_loops::drivetrain_queue.status->robot_speed);
Comran Morshed9a9948c2016-01-16 15:58:04 +0000160 if (left_error < kPositionThreshold && right_error < kPositionThreshold &&
161 velocity_error < 0.2) {
162 break;
163 } else {
164 LOG(DEBUG, "Drivetrain error is %f, %f, %f\n", left_error, right_error,
165 velocity_error);
166 }
167 ::frc971::control_loops::drivetrain_queue.status.FetchNextBlocking();
168 }
Comran Morshed6c6a0a92016-01-17 12:45:16 +0000169
Comran Morshed9a9948c2016-01-16 15:58:04 +0000170 LOG(INFO, "Done moving\n");
171 return true;
172}
173
174::std::unique_ptr<DrivetrainAction> MakeDrivetrainAction(
Comran Morshed6c6a0a92016-01-17 12:45:16 +0000175 const ::y2016::actors::DrivetrainActionParams &params) {
Comran Morshed9a9948c2016-01-16 15:58:04 +0000176 return ::std::unique_ptr<DrivetrainAction>(
Comran Morshed6c6a0a92016-01-17 12:45:16 +0000177 new DrivetrainAction(&::y2016::actors::drivetrain_action, params));
Comran Morshed9a9948c2016-01-16 15:58:04 +0000178}
179
180} // namespace actors
Comran Morshed6c6a0a92016-01-17 12:45:16 +0000181} // namespace y2016