blob: 3cf86bdb9e008232b53b5b1ce9106af21b9cc201 [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
14#include "y2014/actors/drivetrain_actor.h"
15#include "y2014/constants.h"
16#include "y2014/control_loops/drivetrain/drivetrain.q.h"
17
18namespace frc971 {
19namespace actors {
20
21DrivetrainActor::DrivetrainActor(actors::DrivetrainActionQueueGroup* s)
22 : aos::common::actions::ActorBase<actors::DrivetrainActionQueueGroup>(s) {}
23
24bool DrivetrainActor::RunAction(const actors::DrivetrainActionParams &params) {
25 static const auto K = constants::GetValues().make_drivetrain_loop().K();
26
27 const double yoffset = params.y_offset;
28 const double turn_offset =
29 params.theta_offset * constants::GetValues().turn_width / 2.0;
30 LOG(INFO, "Going to move %f and turn %f\n", yoffset, turn_offset);
31
32 // Measured conversion to get the distance right.
33 ::aos::util::TrapezoidProfile profile(::aos::time::Time::InMS(5));
34 ::aos::util::TrapezoidProfile turn_profile(::aos::time::Time::InMS(5));
35 const double goal_velocity = 0.0;
36 const double epsilon = 0.01;
37 ::Eigen::Matrix<double, 2, 1> left_goal_state, right_goal_state;
38
39 profile.set_maximum_acceleration(params.maximum_acceleration);
40 profile.set_maximum_velocity(params.maximum_velocity);
41 turn_profile.set_maximum_acceleration(params.maximum_turn_acceleration *
42 constants::GetValues().turn_width /
43 2.0);
44 turn_profile.set_maximum_velocity(params.maximum_turn_velocity *
45 constants::GetValues().turn_width / 2.0);
46
47 while (true) {
48 ::aos::time::PhasedLoopXMS(10, 5000);
49
50 control_loops::drivetrain_queue.status.FetchLatest();
51 if (control_loops::drivetrain_queue.status.get()) {
52 const auto& status = *control_loops::drivetrain_queue.status;
53 if (::std::abs(status.uncapped_left_voltage -
54 status.uncapped_right_voltage) > 24) {
55 LOG(DEBUG, "spinning in place\n");
56 // They're more than 24V apart, so stop moving forwards and let it deal
57 // with spinning first.
58 profile.SetGoal(
59 (status.filtered_left_position + status.filtered_right_position -
60 params.left_initial_position - params.right_initial_position) /
61 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 LOG(DEBUG, "Saturating opposite ways, not adjusting\n");
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(ERROR, "no drivetrain status!\n");
100 return false;
101 }
102
103 const auto drive_profile_goal_state =
104 profile.Update(yoffset, goal_velocity);
105 const auto turn_profile_goal_state = turn_profile.Update(turn_offset, 0.0);
106 left_goal_state = drive_profile_goal_state - turn_profile_goal_state;
107 right_goal_state = drive_profile_goal_state + turn_profile_goal_state;
108
109 if (::std::abs(drive_profile_goal_state(0, 0) - yoffset) < epsilon &&
110 ::std::abs(turn_profile_goal_state(0, 0) - turn_offset) < epsilon) {
111 break;
112 }
113
114 if (ShouldCancel()) return true;
115
116 LOG(DEBUG, "Driving left to %f, right to %f\n",
117 left_goal_state(0, 0) + params.left_initial_position,
118 right_goal_state(0, 0) + params.right_initial_position);
119 control_loops::drivetrain_queue.goal.MakeWithBuilder()
120 .control_loop_driving(true)
121 //.highgear(false)
122 .left_goal(left_goal_state(0, 0) + params.left_initial_position)
123 .right_goal(right_goal_state(0, 0) + params.right_initial_position)
124 .left_velocity_goal(left_goal_state(1, 0))
125 .right_velocity_goal(right_goal_state(1, 0))
126 .Send();
127 }
128 if (ShouldCancel()) return true;
129 control_loops::drivetrain_queue.status.FetchLatest();
130 while (!control_loops::drivetrain_queue.status.get()) {
131 LOG(WARNING,
132 "No previous drivetrain status packet, trying to fetch again\n");
133 control_loops::drivetrain_queue.status.FetchNextBlocking();
134 if (ShouldCancel()) return true;
135 }
136 while (true) {
137 if (ShouldCancel()) return true;
138 const double kPositionThreshold = 0.05;
139
140 const double left_error = ::std::abs(
141 control_loops::drivetrain_queue.status->filtered_left_position -
142 (left_goal_state(0, 0) + params.left_initial_position));
143 const double right_error = ::std::abs(
144 control_loops::drivetrain_queue.status->filtered_right_position -
145 (right_goal_state(0, 0) + params.right_initial_position));
146 const double velocity_error =
147 ::std::abs(control_loops::drivetrain_queue.status->robot_speed);
148 if (left_error < kPositionThreshold && right_error < kPositionThreshold &&
149 velocity_error < 0.2) {
150 break;
151 } else {
152 LOG(DEBUG, "Drivetrain error is %f, %f, %f\n", left_error, right_error,
153 velocity_error);
154 }
155 control_loops::drivetrain_queue.status.FetchNextBlocking();
156 }
157 LOG(INFO, "Done moving\n");
158 return true;
159}
160
161::std::unique_ptr<DrivetrainAction> MakeDrivetrainAction(
162 const ::frc971::actors::DrivetrainActionParams& params) {
163 return ::std::unique_ptr<DrivetrainAction>(
164 new DrivetrainAction(&::frc971::actors::drivetrain_action, params));
165}
166
167} // namespace actors
168} // namespace frc971