blob: d7660b3af0ed5e9f93f2f04da3fd6686fec4a58e [file] [log] [blame]
Comran Morshede9b12922015-11-04 19:46:48 +00001#include <functional>
2#include <numeric>
3
4#include <Eigen/Dense>
5
6#include "aos/common/util/phased_loop.h"
7#include "aos/common/logging/logging.h"
8#include "aos/common/util/trapezoid_profile.h"
9#include "aos/common/commonmath.h"
10
11#include "bot3/actions/drivetrain_action.h"
12#include "bot3/control_loops/drivetrain/drivetrain.q.h"
13#include "bot3/control_loops/drivetrain/drivetrain_constants.h"
14#include "bot3/control_loops/drivetrain/drivetrain_dog_motor_plant.h"
15
16namespace bot3 {
17namespace actions {
18
Austin Schuh214e9c12016-11-25 17:26:20 -080019namespace chrono = ::std::chrono;
20
Comran Morshede9b12922015-11-04 19:46:48 +000021DrivetrainAction::DrivetrainAction(::frc971::actions::DrivetrainActionQueueGroup* s)
22 : ::frc971::actions::ActionBase
23 <::frc971::actions::DrivetrainActionQueueGroup>(s) {}
24
25void DrivetrainAction::RunAction() {
26 static const auto K = control_loops::MakeDrivetrainLoop().K();
27
28 const double yoffset = action_q_->goal->y_offset;
29 const double turn_offset =
30 action_q_->goal->theta_offset * control_loops::kBot3TurnWidth / 2.0;
31 LOG(INFO, "Going to move %f and turn %f\n", yoffset, turn_offset);
32
33 // Measured conversion to get the distance right.
Austin Schuh214e9c12016-11-25 17:26:20 -080034 ::aos::util::TrapezoidProfile profile(chrono::milliseconds(10));
35 ::aos::util::TrapezoidProfile turn_profile(chrono::milliseconds(10));
Comran Morshede9b12922015-11-04 19:46:48 +000036 const double goal_velocity = 0.0;
37 const double epsilon = 0.01;
38 ::Eigen::Matrix<double, 2, 1> left_goal_state, right_goal_state;
39
40 profile.set_maximum_acceleration(action_q_->goal->maximum_acceleration);
41 profile.set_maximum_velocity(action_q_->goal->maximum_velocity);
42 turn_profile.set_maximum_acceleration(
43 10.0 * control_loops::kBot3TurnWidth / 2.0);
44 turn_profile.set_maximum_velocity(3.0 * control_loops::kBot3TurnWidth / 2.0);
45
46 while (true) {
47 // wait until next 10ms tick
48 ::aos::time::PhasedLoop10MS(5000);
49
50 control_loops::drivetrain.status.FetchLatest();
51 if (control_loops::drivetrain.status.get()) {
52 const auto &status = *control_loops::drivetrain.status;
53 if (::std::abs(status.uncapped_left_voltage -
54 status.uncapped_right_voltage) >
55 24) {
56 LOG(DEBUG, "spinning in place\n");
57 // They're more than 24V apart, so stop moving forwards and let it deal
58 // with spinning first.
59 profile.SetGoal(
Austin Schuh093535c2016-03-05 23:21:00 -080060 (status.estimated_left_position + status.estimated_right_position) /
Comran Morshede9b12922015-11-04 19:46:48 +000061 2.0);
62 } else {
63 static const double divisor = K(0, 0) + K(0, 2);
64 double dx_left, dx_right;
65 if (status.uncapped_left_voltage > 12.0) {
66 dx_left = (status.uncapped_left_voltage - 12.0) / divisor;
67 } else if (status.uncapped_left_voltage < -12.0) {
68 dx_left = (status.uncapped_left_voltage + 12.0) / divisor;
69 } else {
70 dx_left = 0;
71 }
72 if (status.uncapped_right_voltage > 12.0) {
73 dx_right = (status.uncapped_right_voltage - 12.0) / divisor;
74 } else if (status.uncapped_right_voltage < -12.0) {
75 dx_right = (status.uncapped_right_voltage + 12.0) / divisor;
76 } else {
77 dx_right = 0;
78 }
79 double dx;
80 if (dx_left == 0 && dx_right == 0) {
81 dx = 0;
82 } else if (dx_left != 0 && dx_right != 0 &&
83 ::aos::sign(dx_left) != ::aos::sign(dx_right)) {
84 // Both saturating in opposite directions. Don't do anything.
85 dx = 0;
86 } else if (::std::abs(dx_left) > ::std::abs(dx_right)) {
87 dx = dx_left;
88 } else {
89 dx = dx_right;
90 }
91 if (dx != 0) {
92 LOG(DEBUG, "adjusting goal by %f\n", dx);
93 profile.MoveGoal(-dx);
94 }
95 }
96 } else {
97 // If we ever get here, that's bad and we should just give up
98 LOG(FATAL, "no drivetrain status!\n");
99 }
100
101 const auto drive_profile_goal_state =
102 profile.Update(yoffset, goal_velocity);
103 const auto turn_profile_goal_state = turn_profile.Update(turn_offset, 0.0);
104 left_goal_state = drive_profile_goal_state - turn_profile_goal_state;
105 right_goal_state = drive_profile_goal_state + turn_profile_goal_state;
106
107 if (::std::abs(drive_profile_goal_state(0, 0) - yoffset) < epsilon &&
108 ::std::abs(turn_profile_goal_state(0, 0) - turn_offset) < epsilon) {
109 break;
110 }
111 if (ShouldCancel()) return;
112
113 LOG(DEBUG, "Driving left to %f, right to %f\n",
114 left_goal_state(0, 0) + action_q_->goal->left_initial_position,
115 right_goal_state(0, 0) + action_q_->goal->right_initial_position);
116 control_loops::drivetrain.goal.MakeWithBuilder()
117 .control_loop_driving(true)
118 .highgear(false)
119 .left_goal(left_goal_state(0, 0) + action_q_->goal->left_initial_position)
120 .right_goal(right_goal_state(0, 0) + action_q_->goal->right_initial_position)
121 .left_velocity_goal(left_goal_state(1, 0))
122 .right_velocity_goal(right_goal_state(1, 0))
123 .Send();
124 }
125 if (ShouldCancel()) return;
126 control_loops::drivetrain.status.FetchLatest();
127 while (!control_loops::drivetrain.status.get()) {
128 LOG(WARNING,
129 "No previous drivetrain status packet, trying to fetch again\n");
130 control_loops::drivetrain.status.FetchNextBlocking();
131 if (ShouldCancel()) return;
132 }
133 while (true) {
134 if (ShouldCancel()) return;
135 const double kPositionThreshold = 0.05;
136
137 const double left_error = ::std::abs(
Austin Schuh093535c2016-03-05 23:21:00 -0800138 control_loops::drivetrain.status->estimated_left_position -
Comran Morshede9b12922015-11-04 19:46:48 +0000139 (left_goal_state(0, 0) + action_q_->goal->left_initial_position));
140 const double right_error = ::std::abs(
Austin Schuh093535c2016-03-05 23:21:00 -0800141 control_loops::drivetrain.status->estimated_right_position -
Comran Morshede9b12922015-11-04 19:46:48 +0000142 (right_goal_state(0, 0) + action_q_->goal->right_initial_position));
143 const double velocity_error =
144 ::std::abs(control_loops::drivetrain.status->robot_speed);
145 if (left_error < kPositionThreshold && right_error < kPositionThreshold &&
146 velocity_error < 0.2) {
147 break;
148 } else {
149 LOG(DEBUG, "Drivetrain error is %f, %f, %f\n", left_error, right_error,
150 velocity_error);
151 }
152 control_loops::drivetrain.status.FetchNextBlocking();
153 }
154 LOG(INFO, "Done moving\n");
155}
156
157::std::unique_ptr<::frc971::TypedAction< ::frc971::actions::DrivetrainActionQueueGroup>>
158MakeDrivetrainAction() {
159 return ::std::unique_ptr<
160 ::frc971::TypedAction< ::frc971::actions::DrivetrainActionQueueGroup>>(
161 new ::frc971::TypedAction< ::frc971::actions::DrivetrainActionQueueGroup>(
162 &::frc971::actions::drivetrain_action));
163}
164
165} // namespace actions
166} // namespace bot3