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