blob: 07a2abbe5212d4e6b6cb1d2b9e6ff38e3e322bb2 [file] [log] [blame]
Austin Schuh80ff2e12014-03-08 12:06:19 -08001#include <functional>
2#include <numeric>
3
4#include <Eigen/Dense>
5
Brian3afd6fc2014-04-02 20:41:49 -07006#include "aos/common/util/phased_loop.h"
Austin Schuh80ff2e12014-03-08 12:06:19 -08007#include "aos/common/logging/logging.h"
8#include "aos/common/util/trapezoid_profile.h"
Brian Silvermanb94069c2014-04-17 14:34:24 -07009#include "aos/common/commonmath.h"
Austin Schuh80ff2e12014-03-08 12:06:19 -080010
11#include "frc971/actions/drivetrain_action.h"
12#include "frc971/constants.h"
13#include "frc971/control_loops/drivetrain/drivetrain.q.h"
14
15namespace frc971 {
16namespace actions {
17
18DrivetrainAction::DrivetrainAction(actions::DrivetrainActionQueueGroup* s)
19 : actions::ActionBase<actions::DrivetrainActionQueueGroup>(s) {}
20
21void DrivetrainAction::RunAction() {
Brian Silvermanb94069c2014-04-17 14:34:24 -070022 static const auto K = constants::GetValues().make_drivetrain_loop().K();
23
Austin Schuh80ff2e12014-03-08 12:06:19 -080024 const double yoffset = action_q_->goal->y_offset;
Brian Silvermanad9e0002014-04-13 14:55:57 -070025 const double turn_offset =
26 action_q_->goal->theta_offset * constants::GetValues().turn_width / 2.0;
27 LOG(INFO, "Going to move %f and turn %f\n", yoffset, turn_offset);
Austin Schuh80ff2e12014-03-08 12:06:19 -080028
29 // Measured conversion to get the distance right.
30 ::aos::util::TrapezoidProfile profile(::aos::time::Time::InMS(10));
Brian Silvermanad9e0002014-04-13 14:55:57 -070031 ::aos::util::TrapezoidProfile turn_profile(::aos::time::Time::InMS(10));
Austin Schuh80ff2e12014-03-08 12:06:19 -080032 const double goal_velocity = 0.0;
33 const double epsilon = 0.01;
Brian Silvermanad9e0002014-04-13 14:55:57 -070034 ::Eigen::Matrix<double, 2, 1> left_goal_state, right_goal_state;
Austin Schuh80ff2e12014-03-08 12:06:19 -080035
Brian Silvermanad9e0002014-04-13 14:55:57 -070036 profile.set_maximum_acceleration(3.0);
Austin Schuh80ff2e12014-03-08 12:06:19 -080037 profile.set_maximum_velocity(action_q_->goal->maximum_velocity);
Brian Silvermanad9e0002014-04-13 14:55:57 -070038 turn_profile.set_maximum_acceleration(
39 10.0 * constants::GetValues().turn_width / 2.0);
40 turn_profile.set_maximum_velocity(3.0 * constants::GetValues().turn_width /
41 2.0);
Austin Schuh80ff2e12014-03-08 12:06:19 -080042
43 while (true) {
44 // wait until next 10ms tick
45 ::aos::time::PhasedLoop10MS(5000);
Brian Silvermanad9e0002014-04-13 14:55:57 -070046 const auto drive_profile_goal_state =
47 profile.Update(yoffset, goal_velocity);
48 const auto turn_profile_goal_state = turn_profile.Update(turn_offset, 0.0);
49 left_goal_state = drive_profile_goal_state - turn_profile_goal_state;
50 right_goal_state = drive_profile_goal_state + turn_profile_goal_state;
Austin Schuh80ff2e12014-03-08 12:06:19 -080051
Brian Silvermanb94069c2014-04-17 14:34:24 -070052 control_loops::drivetrain.status.FetchLatest();
53 if (control_loops::drivetrain.status.get()) {
54 const auto &status = *control_loops::drivetrain.status;
55 if (::std::abs(status.uncapped_left_voltage -
56 status.uncapped_right_voltage) >
57 24) {
58 // They're more than 24V apart, so stop moving forwards and let it deal
59 // with spinning first.
60 profile.SetGoal(
61 (status.filtered_left_position + status.filtered_right_position) /
62 2.0);
63 } else {
64 static const double divisor = K(0, 1) + K(0, 3);
65 double dx_left, dx_right;
66 if (status.uncapped_left_voltage > 12.0) {
67 dx_left = (status.uncapped_left_voltage - 12.0) / divisor;
68 } else if (status.uncapped_left_voltage < -12.0) {
69 dx_left = (status.uncapped_left_voltage + 12.0) / divisor;
70 } else {
71 dx_left = 0;
72 }
73 if (status.uncapped_right_voltage > 12.0) {
74 dx_right = (status.uncapped_right_voltage - 12.0) / divisor;
75 } else if (status.uncapped_right_voltage < -12.0) {
76 dx_right = (status.uncapped_right_voltage + 12.0) / divisor;
77 } else {
78 dx_right = 0;
79 }
80 double dx;
81 if (dx_left == 0 && dx_right == 0) {
82 dx = 0;
83 } else if (dx_left != 0 && dx_right != 0 &&
84 ::aos::sign(dx_left) != ::aos::sign(dx_right)) {
85 // Both saturating in opposite directions. Don't do anything.
86 dx = 0;
87 } else if (::std::abs(dx_left) > ::std::abs(dx_right)) {
88 dx = dx_left;
89 } else {
90 dx = dx_right;
91 }
92 if (dx != 0) {
93 LOG(DEBUG, "adjusting goal by %f\n", dx);
94 profile.MoveGoal(-dx);
95 }
96 }
97 } else {
98 // If we ever get here, that's bad and we should just give up
99 LOG(FATAL, "no drivetrain status!\n");
100 }
101
Brian Silvermanad9e0002014-04-13 14:55:57 -0700102 if (::std::abs(drive_profile_goal_state(0, 0) - yoffset) < epsilon &&
103 ::std::abs(turn_profile_goal_state(0, 0) - turn_offset) < epsilon) {
104 break;
105 }
Austin Schuh80ff2e12014-03-08 12:06:19 -0800106 if (ShouldCancel()) return;
107
108 LOG(DEBUG, "Driving left to %f, right to %f\n",
Brian Silvermanad9e0002014-04-13 14:55:57 -0700109 left_goal_state(0, 0) + action_q_->goal->left_initial_position,
110 right_goal_state(0, 0) + action_q_->goal->right_initial_position);
Austin Schuh80ff2e12014-03-08 12:06:19 -0800111 control_loops::drivetrain.goal.MakeWithBuilder()
112 .control_loop_driving(true)
113 .highgear(false)
Brian Silvermanad9e0002014-04-13 14:55:57 -0700114 .left_goal(left_goal_state(0, 0) + action_q_->goal->left_initial_position)
115 .right_goal(right_goal_state(0, 0) + action_q_->goal->right_initial_position)
116 .left_velocity_goal(left_goal_state(1, 0))
117 .right_velocity_goal(right_goal_state(1, 0))
Austin Schuh80ff2e12014-03-08 12:06:19 -0800118 .Send();
119 }
Brian Silvermanad9e0002014-04-13 14:55:57 -0700120 if (ShouldCancel()) return;
Austin Schuh577edf62014-04-13 10:33:05 -0700121 control_loops::drivetrain.status.FetchLatest();
122 while (!control_loops::drivetrain.status.get()) {
123 LOG(WARNING,
124 "No previous drivetrain status packet, trying to fetch again\n");
125 control_loops::drivetrain.status.FetchNextBlocking();
126 if (ShouldCancel()) return;
127 }
128 while (true) {
129 if (ShouldCancel()) return;
130 const double kPositionThreshold = 0.05;
131
132 const double left_error = ::std::abs(
133 control_loops::drivetrain.status->filtered_left_position -
Brian Silvermanad9e0002014-04-13 14:55:57 -0700134 (left_goal_state(0, 0) + action_q_->goal->left_initial_position));
Austin Schuh577edf62014-04-13 10:33:05 -0700135 const double right_error = ::std::abs(
136 control_loops::drivetrain.status->filtered_right_position -
Brian Silvermanad9e0002014-04-13 14:55:57 -0700137 (right_goal_state(0, 0) + action_q_->goal->right_initial_position));
Austin Schuh577edf62014-04-13 10:33:05 -0700138 const double velocity_error =
139 ::std::abs(control_loops::drivetrain.status->robot_speed);
140 if (left_error < kPositionThreshold && right_error < kPositionThreshold &&
141 velocity_error < 0.2) {
142 break;
143 } else {
144 LOG(DEBUG, "Drivetrain error is %f, %f, %f\n", left_error, right_error,
145 velocity_error);
146 }
147 control_loops::drivetrain.status.FetchNextBlocking();
148 }
Austin Schuh80ff2e12014-03-08 12:06:19 -0800149 LOG(INFO, "Done moving\n");
150}
151
152::std::unique_ptr<TypedAction< ::frc971::actions::DrivetrainActionQueueGroup>>
153MakeDrivetrainAction() {
154 return ::std::unique_ptr<
155 TypedAction< ::frc971::actions::DrivetrainActionQueueGroup>>(
156 new TypedAction< ::frc971::actions::DrivetrainActionQueueGroup>(
157 &::frc971::actions::drivetrain_action));
158}
159
160} // namespace actions
161} // namespace frc971