blob: 352ec6200fc8b25eab4fb97ff28c9b1851132618 [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
Natalia Frumkind1fa52f2014-06-21 15:24:25 -070036 profile.set_maximum_acceleration(action_q_->goal->maximum_acceleration);
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);
Austin Schuh80ff2e12014-03-08 12:06:19 -080046
Brian Silvermanb94069c2014-04-17 14:34:24 -070047 control_loops::drivetrain.status.FetchLatest();
48 if (control_loops::drivetrain.status.get()) {
49 const auto &status = *control_loops::drivetrain.status;
50 if (::std::abs(status.uncapped_left_voltage -
51 status.uncapped_right_voltage) >
52 24) {
Brian Silverman38ea9bf2014-04-19 22:57:54 -070053 LOG(DEBUG, "spinning in place\n");
Brian Silvermanb94069c2014-04-17 14:34:24 -070054 // They're more than 24V apart, so stop moving forwards and let it deal
55 // with spinning first.
56 profile.SetGoal(
57 (status.filtered_left_position + status.filtered_right_position) /
58 2.0);
59 } else {
Brian Silverman38ea9bf2014-04-19 22:57:54 -070060 static const double divisor = K(0, 0) + K(0, 2);
Brian Silvermanb94069c2014-04-17 14:34:24 -070061 double dx_left, dx_right;
62 if (status.uncapped_left_voltage > 12.0) {
63 dx_left = (status.uncapped_left_voltage - 12.0) / divisor;
64 } else if (status.uncapped_left_voltage < -12.0) {
65 dx_left = (status.uncapped_left_voltage + 12.0) / divisor;
66 } else {
67 dx_left = 0;
68 }
69 if (status.uncapped_right_voltage > 12.0) {
70 dx_right = (status.uncapped_right_voltage - 12.0) / divisor;
71 } else if (status.uncapped_right_voltage < -12.0) {
72 dx_right = (status.uncapped_right_voltage + 12.0) / divisor;
73 } else {
74 dx_right = 0;
75 }
76 double dx;
77 if (dx_left == 0 && dx_right == 0) {
78 dx = 0;
79 } else if (dx_left != 0 && dx_right != 0 &&
80 ::aos::sign(dx_left) != ::aos::sign(dx_right)) {
81 // Both saturating in opposite directions. Don't do anything.
82 dx = 0;
83 } else if (::std::abs(dx_left) > ::std::abs(dx_right)) {
84 dx = dx_left;
85 } else {
86 dx = dx_right;
87 }
88 if (dx != 0) {
89 LOG(DEBUG, "adjusting goal by %f\n", dx);
90 profile.MoveGoal(-dx);
91 }
92 }
93 } else {
94 // If we ever get here, that's bad and we should just give up
95 LOG(FATAL, "no drivetrain status!\n");
96 }
97
Brian Silverman38ea9bf2014-04-19 22:57:54 -070098 const auto drive_profile_goal_state =
99 profile.Update(yoffset, goal_velocity);
100 const auto turn_profile_goal_state = turn_profile.Update(turn_offset, 0.0);
101 left_goal_state = drive_profile_goal_state - turn_profile_goal_state;
102 right_goal_state = drive_profile_goal_state + turn_profile_goal_state;
103
Brian Silvermanad9e0002014-04-13 14:55:57 -0700104 if (::std::abs(drive_profile_goal_state(0, 0) - yoffset) < epsilon &&
105 ::std::abs(turn_profile_goal_state(0, 0) - turn_offset) < epsilon) {
106 break;
107 }
Austin Schuh80ff2e12014-03-08 12:06:19 -0800108 if (ShouldCancel()) return;
109
110 LOG(DEBUG, "Driving left to %f, right to %f\n",
Brian Silvermanad9e0002014-04-13 14:55:57 -0700111 left_goal_state(0, 0) + action_q_->goal->left_initial_position,
112 right_goal_state(0, 0) + action_q_->goal->right_initial_position);
Austin Schuh80ff2e12014-03-08 12:06:19 -0800113 control_loops::drivetrain.goal.MakeWithBuilder()
114 .control_loop_driving(true)
Brian Silverman93335ae2015-01-26 20:43:39 -0500115 //.highgear(false)
Brian Silvermanad9e0002014-04-13 14:55:57 -0700116 .left_goal(left_goal_state(0, 0) + action_q_->goal->left_initial_position)
117 .right_goal(right_goal_state(0, 0) + action_q_->goal->right_initial_position)
118 .left_velocity_goal(left_goal_state(1, 0))
119 .right_velocity_goal(right_goal_state(1, 0))
Austin Schuh80ff2e12014-03-08 12:06:19 -0800120 .Send();
121 }
Brian Silvermanad9e0002014-04-13 14:55:57 -0700122 if (ShouldCancel()) return;
Austin Schuh577edf62014-04-13 10:33:05 -0700123 control_loops::drivetrain.status.FetchLatest();
124 while (!control_loops::drivetrain.status.get()) {
125 LOG(WARNING,
126 "No previous drivetrain status packet, trying to fetch again\n");
127 control_loops::drivetrain.status.FetchNextBlocking();
128 if (ShouldCancel()) return;
129 }
130 while (true) {
131 if (ShouldCancel()) return;
132 const double kPositionThreshold = 0.05;
133
134 const double left_error = ::std::abs(
135 control_loops::drivetrain.status->filtered_left_position -
Brian Silvermanad9e0002014-04-13 14:55:57 -0700136 (left_goal_state(0, 0) + action_q_->goal->left_initial_position));
Austin Schuh577edf62014-04-13 10:33:05 -0700137 const double right_error = ::std::abs(
138 control_loops::drivetrain.status->filtered_right_position -
Brian Silvermanad9e0002014-04-13 14:55:57 -0700139 (right_goal_state(0, 0) + action_q_->goal->right_initial_position));
Austin Schuh577edf62014-04-13 10:33:05 -0700140 const double velocity_error =
141 ::std::abs(control_loops::drivetrain.status->robot_speed);
142 if (left_error < kPositionThreshold && right_error < kPositionThreshold &&
143 velocity_error < 0.2) {
144 break;
145 } else {
146 LOG(DEBUG, "Drivetrain error is %f, %f, %f\n", left_error, right_error,
147 velocity_error);
148 }
149 control_loops::drivetrain.status.FetchNextBlocking();
150 }
Austin Schuh80ff2e12014-03-08 12:06:19 -0800151 LOG(INFO, "Done moving\n");
152}
153
154::std::unique_ptr<TypedAction< ::frc971::actions::DrivetrainActionQueueGroup>>
155MakeDrivetrainAction() {
156 return ::std::unique_ptr<
157 TypedAction< ::frc971::actions::DrivetrainActionQueueGroup>>(
158 new TypedAction< ::frc971::actions::DrivetrainActionQueueGroup>(
159 &::frc971::actions::drivetrain_action));
160}
161
162} // namespace actions
163} // namespace frc971