blob: 6c7427b4eaf59c1900c3cdf9410ab1d49a92b4f6 [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
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
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
22DrivetrainActor::DrivetrainActor(actors::DrivetrainActionQueueGroup* s)
Austin Schuhadf2cde2015-11-08 20:35:16 -080023 : aos::common::actions::ActorBase<actors::DrivetrainActionQueueGroup>(s),
24 loop_(constants::GetValues().make_drivetrain_loop()) {
25 loop_.set_controller_index(3);
26}
Brian Silverman17f503e2015-08-02 18:17:18 -070027
28bool DrivetrainActor::RunAction(const actors::DrivetrainActionParams &params) {
Austin Schuhadf2cde2015-11-08 20:35:16 -080029 static const auto K = loop_.K();
Brian Silverman17f503e2015-08-02 18:17:18 -070030
31 const double yoffset = params.y_offset;
32 const double turn_offset =
Austin Schuh3130b372016-02-17 00:34:51 -080033 params.theta_offset * control_loops::drivetrain::kRobotRadius;
Brian Silverman17f503e2015-08-02 18:17:18 -070034 LOG(INFO, "Going to move %f and turn %f\n", yoffset, turn_offset);
35
36 // Measured conversion to get the distance right.
Austin Schuhadf2cde2015-11-08 20:35:16 -080037 ::aos::util::TrapezoidProfile profile(::aos::time::Time::InMS(5));
38 ::aos::util::TrapezoidProfile turn_profile(::aos::time::Time::InMS(5));
Brian Silverman17f503e2015-08-02 18:17:18 -070039 const double goal_velocity = 0.0;
40 const double epsilon = 0.01;
41 ::Eigen::Matrix<double, 2, 1> left_goal_state, right_goal_state;
42
43 profile.set_maximum_acceleration(params.maximum_acceleration);
44 profile.set_maximum_velocity(params.maximum_velocity);
Austin Schuh3130b372016-02-17 00:34:51 -080045 turn_profile.set_maximum_acceleration(
46 params.maximum_turn_acceleration *
47 control_loops::drivetrain::kRobotRadius);
Brian Silverman17f503e2015-08-02 18:17:18 -070048 turn_profile.set_maximum_velocity(params.maximum_turn_velocity *
Austin Schuh3130b372016-02-17 00:34:51 -080049 control_loops::drivetrain::kRobotRadius);
Brian Silverman17f503e2015-08-02 18:17:18 -070050
51 while (true) {
Austin Schuhadf2cde2015-11-08 20:35:16 -080052 ::aos::time::PhasedLoopXMS(5, 2500);
Brian Silverman17f503e2015-08-02 18:17:18 -070053
Comran Morshed5323ecb2015-12-26 20:50:55 +000054 ::frc971::control_loops::drivetrain_queue.status.FetchLatest();
55 if (::frc971::control_loops::drivetrain_queue.status.get()) {
Austin Schuh3130b372016-02-17 00:34:51 -080056 const auto &status = *::frc971::control_loops::drivetrain_queue.status;
Brian Silverman17f503e2015-08-02 18:17:18 -070057 if (::std::abs(status.uncapped_left_voltage -
58 status.uncapped_right_voltage) > 24) {
59 LOG(DEBUG, "spinning in place\n");
60 // They're more than 24V apart, so stop moving forwards and let it deal
61 // with spinning first.
62 profile.SetGoal(
63 (status.filtered_left_position + status.filtered_right_position -
64 params.left_initial_position - params.right_initial_position) /
65 2.0);
66 } else {
67 static const double divisor = K(0, 0) + K(0, 2);
68 double dx_left, dx_right;
69 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 }
76 if (status.uncapped_right_voltage > 12.0) {
77 dx_right = (status.uncapped_right_voltage - 12.0) / divisor;
78 } else if (status.uncapped_right_voltage < -12.0) {
79 dx_right = (status.uncapped_right_voltage + 12.0) / divisor;
80 } else {
81 dx_right = 0;
82 }
83 double dx;
84 if (dx_left == 0 && dx_right == 0) {
85 dx = 0;
86 } else if (dx_left != 0 && dx_right != 0 &&
87 ::aos::sign(dx_left) != ::aos::sign(dx_right)) {
88 // Both saturating in opposite directions. Don't do anything.
89 LOG(DEBUG, "Saturating opposite ways, not adjusting\n");
90 dx = 0;
91 } else if (::std::abs(dx_left) > ::std::abs(dx_right)) {
92 dx = dx_left;
93 } else {
94 dx = dx_right;
95 }
96 if (dx != 0) {
97 LOG(DEBUG, "adjusting goal by %f\n", dx);
98 profile.MoveGoal(-dx);
99 }
100 }
101 } else {
102 // If we ever get here, that's bad and we should just give up
103 LOG(ERROR, "no drivetrain status!\n");
104 return false;
105 }
106
107 const auto drive_profile_goal_state =
108 profile.Update(yoffset, goal_velocity);
109 const auto turn_profile_goal_state = turn_profile.Update(turn_offset, 0.0);
110 left_goal_state = drive_profile_goal_state - turn_profile_goal_state;
111 right_goal_state = drive_profile_goal_state + turn_profile_goal_state;
112
113 if (::std::abs(drive_profile_goal_state(0, 0) - yoffset) < epsilon &&
114 ::std::abs(turn_profile_goal_state(0, 0) - turn_offset) < epsilon) {
115 break;
116 }
117
118 if (ShouldCancel()) return true;
119
120 LOG(DEBUG, "Driving left to %f, right to %f\n",
121 left_goal_state(0, 0) + params.left_initial_position,
122 right_goal_state(0, 0) + params.right_initial_position);
Comran Morshed5323ecb2015-12-26 20:50:55 +0000123 ::frc971::control_loops::drivetrain_queue.goal.MakeWithBuilder()
Brian Silverman17f503e2015-08-02 18:17:18 -0700124 .control_loop_driving(true)
Austin Schuh86f895e2015-11-08 13:40:51 -0800125 .highgear(true)
Brian Silverman17f503e2015-08-02 18:17:18 -0700126 .left_goal(left_goal_state(0, 0) + params.left_initial_position)
127 .right_goal(right_goal_state(0, 0) + params.right_initial_position)
128 .left_velocity_goal(left_goal_state(1, 0))
129 .right_velocity_goal(right_goal_state(1, 0))
130 .Send();
131 }
132 if (ShouldCancel()) return true;
Comran Morshed5323ecb2015-12-26 20:50:55 +0000133 ::frc971::control_loops::drivetrain_queue.status.FetchLatest();
134 while (!::frc971::control_loops::drivetrain_queue.status.get()) {
Brian Silverman17f503e2015-08-02 18:17:18 -0700135 LOG(WARNING,
136 "No previous drivetrain status packet, trying to fetch again\n");
Comran Morshed5323ecb2015-12-26 20:50:55 +0000137 ::frc971::control_loops::drivetrain_queue.status.FetchNextBlocking();
Brian Silverman17f503e2015-08-02 18:17:18 -0700138 if (ShouldCancel()) return true;
139 }
140 while (true) {
141 if (ShouldCancel()) return true;
142 const double kPositionThreshold = 0.05;
143
Austin Schuh3130b372016-02-17 00:34:51 -0800144 const double left_error =
145 ::std::abs(::frc971::control_loops::drivetrain_queue.status
146 ->filtered_left_position -
147 (left_goal_state(0, 0) + params.left_initial_position));
148 const double right_error =
149 ::std::abs(::frc971::control_loops::drivetrain_queue.status
150 ->filtered_right_position -
151 (right_goal_state(0, 0) + params.right_initial_position));
152 const double velocity_error = ::std::abs(
153 ::frc971::control_loops::drivetrain_queue.status->robot_speed);
Brian Silverman17f503e2015-08-02 18:17:18 -0700154 if (left_error < kPositionThreshold && right_error < kPositionThreshold &&
155 velocity_error < 0.2) {
156 break;
157 } else {
158 LOG(DEBUG, "Drivetrain error is %f, %f, %f\n", left_error, right_error,
159 velocity_error);
160 }
Comran Morshed5323ecb2015-12-26 20:50:55 +0000161 ::frc971::control_loops::drivetrain_queue.status.FetchNextBlocking();
Brian Silverman17f503e2015-08-02 18:17:18 -0700162 }
163 LOG(INFO, "Done moving\n");
164 return true;
165}
166
167::std::unique_ptr<DrivetrainAction> MakeDrivetrainAction(
Austin Schuh3130b372016-02-17 00:34:51 -0800168 const ::y2014::actors::DrivetrainActionParams &params) {
Brian Silverman17f503e2015-08-02 18:17:18 -0700169 return ::std::unique_ptr<DrivetrainAction>(
Brian Silvermanb601d892015-12-20 18:24:38 -0500170 new DrivetrainAction(&::y2014::actors::drivetrain_action, params));
Brian Silverman17f503e2015-08-02 18:17:18 -0700171}
172
173} // namespace actors
Brian Silvermanb601d892015-12-20 18:24:38 -0500174} // namespace y2014