blob: 71a1be8e8a586f74c62c96ddda5e894ba821ba4c [file] [log] [blame]
Ben Fredricksond69f38b2015-01-28 20:06:15 -08001#include "frc971/actions/drivetrain_actor.h"
2
Austin Schuh80ff2e12014-03-08 12:06:19 -08003#include <functional>
4#include <numeric>
5
6#include <Eigen/Dense>
7
Brian3afd6fc2014-04-02 20:41:49 -07008#include "aos/common/util/phased_loop.h"
Austin Schuh80ff2e12014-03-08 12:06:19 -08009#include "aos/common/logging/logging.h"
10#include "aos/common/util/trapezoid_profile.h"
Brian Silvermanb94069c2014-04-17 14:34:24 -070011#include "aos/common/commonmath.h"
Ben Fredricksond69f38b2015-01-28 20:06:15 -080012#include "aos/common/time.h"
Austin Schuh80ff2e12014-03-08 12:06:19 -080013
Ben Fredricksond69f38b2015-01-28 20:06:15 -080014#include "frc971/actions/drivetrain_actor.h"
Austin Schuh80ff2e12014-03-08 12:06:19 -080015#include "frc971/constants.h"
16#include "frc971/control_loops/drivetrain/drivetrain.q.h"
17
18namespace frc971 {
19namespace actions {
20
Ben Fredricksond69f38b2015-01-28 20:06:15 -080021DrivetrainActor::DrivetrainActor(actions::DrivetrainActionQueueGroup* s)
22 : aos::common::actions::ActorBase<actions::DrivetrainActionQueueGroup>(s) {}
Austin Schuh80ff2e12014-03-08 12:06:19 -080023
Ben Fredricksond69f38b2015-01-28 20:06:15 -080024void DrivetrainActor::RunAction() {
Brian Silvermanb94069c2014-04-17 14:34:24 -070025 static const auto K = constants::GetValues().make_drivetrain_loop().K();
26
Austin Schuh80ff2e12014-03-08 12:06:19 -080027 const double yoffset = action_q_->goal->y_offset;
Brian Silvermanad9e0002014-04-13 14:55:57 -070028 const double turn_offset =
29 action_q_->goal->theta_offset * constants::GetValues().turn_width / 2.0;
30 LOG(INFO, "Going to move %f and turn %f\n", yoffset, turn_offset);
Austin Schuh80ff2e12014-03-08 12:06:19 -080031
32 // Measured conversion to get the distance right.
Ben Fredricksond69f38b2015-01-28 20:06:15 -080033 // TODO(sensors): update this time thing for some reason.
Austin Schuh80ff2e12014-03-08 12:06:19 -080034 ::aos::util::TrapezoidProfile profile(::aos::time::Time::InMS(10));
Brian Silvermanad9e0002014-04-13 14:55:57 -070035 ::aos::util::TrapezoidProfile turn_profile(::aos::time::Time::InMS(10));
Austin Schuh80ff2e12014-03-08 12:06:19 -080036 const double goal_velocity = 0.0;
37 const double epsilon = 0.01;
Brian Silvermanad9e0002014-04-13 14:55:57 -070038 ::Eigen::Matrix<double, 2, 1> left_goal_state, right_goal_state;
Austin Schuh80ff2e12014-03-08 12:06:19 -080039
Natalia Frumkind1fa52f2014-06-21 15:24:25 -070040 profile.set_maximum_acceleration(action_q_->goal->maximum_acceleration);
Austin Schuh80ff2e12014-03-08 12:06:19 -080041 profile.set_maximum_velocity(action_q_->goal->maximum_velocity);
Brian Silvermanad9e0002014-04-13 14:55:57 -070042 turn_profile.set_maximum_acceleration(
43 10.0 * constants::GetValues().turn_width / 2.0);
44 turn_profile.set_maximum_velocity(3.0 * constants::GetValues().turn_width /
45 2.0);
Austin Schuh80ff2e12014-03-08 12:06:19 -080046
47 while (true) {
48 // wait until next 10ms tick
Ben Fredricksond69f38b2015-01-28 20:06:15 -080049 // TODO(sensors): update this time thing for some reason.
Austin Schuh80ff2e12014-03-08 12:06:19 -080050 ::aos::time::PhasedLoop10MS(5000);
Austin Schuh80ff2e12014-03-08 12:06:19 -080051
Brian Silvermanada5f2c2015-02-01 02:41:14 -050052 control_loops::drivetrain_queue.status.FetchLatest();
53 if (control_loops::drivetrain_queue.status.get()) {
54 const auto& status = *control_loops::drivetrain_queue.status;
Brian Silvermanb94069c2014-04-17 14:34:24 -070055 if (::std::abs(status.uncapped_left_voltage -
Ben Fredricksond69f38b2015-01-28 20:06:15 -080056 status.uncapped_right_voltage) > 24) {
Brian Silverman38ea9bf2014-04-19 22:57:54 -070057 LOG(DEBUG, "spinning in place\n");
Brian Silvermanb94069c2014-04-17 14:34:24 -070058 // 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 {
Brian Silverman38ea9bf2014-04-19 22:57:54 -070064 static const double divisor = K(0, 0) + K(0, 2);
Brian Silvermanb94069c2014-04-17 14:34:24 -070065 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 Silverman38ea9bf2014-04-19 22:57:54 -0700102 const auto drive_profile_goal_state =
103 profile.Update(yoffset, goal_velocity);
104 const auto turn_profile_goal_state = turn_profile.Update(turn_offset, 0.0);
105 left_goal_state = drive_profile_goal_state - turn_profile_goal_state;
106 right_goal_state = drive_profile_goal_state + turn_profile_goal_state;
107
Brian Silvermanad9e0002014-04-13 14:55:57 -0700108 if (::std::abs(drive_profile_goal_state(0, 0) - yoffset) < epsilon &&
109 ::std::abs(turn_profile_goal_state(0, 0) - turn_offset) < epsilon) {
110 break;
111 }
Austin Schuh80ff2e12014-03-08 12:06:19 -0800112 if (ShouldCancel()) return;
113
114 LOG(DEBUG, "Driving left to %f, right to %f\n",
Brian Silvermanad9e0002014-04-13 14:55:57 -0700115 left_goal_state(0, 0) + action_q_->goal->left_initial_position,
116 right_goal_state(0, 0) + action_q_->goal->right_initial_position);
Brian Silvermanada5f2c2015-02-01 02:41:14 -0500117 control_loops::drivetrain_queue.goal.MakeWithBuilder()
Austin Schuh80ff2e12014-03-08 12:06:19 -0800118 .control_loop_driving(true)
Brian Silverman93335ae2015-01-26 20:43:39 -0500119 //.highgear(false)
Brian Silvermanad9e0002014-04-13 14:55:57 -0700120 .left_goal(left_goal_state(0, 0) + action_q_->goal->left_initial_position)
121 .right_goal(right_goal_state(0, 0) + action_q_->goal->right_initial_position)
122 .left_velocity_goal(left_goal_state(1, 0))
123 .right_velocity_goal(right_goal_state(1, 0))
Austin Schuh80ff2e12014-03-08 12:06:19 -0800124 .Send();
125 }
Brian Silvermanad9e0002014-04-13 14:55:57 -0700126 if (ShouldCancel()) return;
Brian Silvermanada5f2c2015-02-01 02:41:14 -0500127 control_loops::drivetrain_queue.status.FetchLatest();
128 while (!control_loops::drivetrain_queue.status.get()) {
Austin Schuh577edf62014-04-13 10:33:05 -0700129 LOG(WARNING,
130 "No previous drivetrain status packet, trying to fetch again\n");
Brian Silvermanada5f2c2015-02-01 02:41:14 -0500131 control_loops::drivetrain_queue.status.FetchNextBlocking();
Austin Schuh577edf62014-04-13 10:33:05 -0700132 if (ShouldCancel()) return;
133 }
134 while (true) {
135 if (ShouldCancel()) return;
136 const double kPositionThreshold = 0.05;
137
138 const double left_error = ::std::abs(
Brian Silvermanada5f2c2015-02-01 02:41:14 -0500139 control_loops::drivetrain_queue.status->filtered_left_position -
Brian Silvermanad9e0002014-04-13 14:55:57 -0700140 (left_goal_state(0, 0) + action_q_->goal->left_initial_position));
Austin Schuh577edf62014-04-13 10:33:05 -0700141 const double right_error = ::std::abs(
Brian Silvermanada5f2c2015-02-01 02:41:14 -0500142 control_loops::drivetrain_queue.status->filtered_right_position -
Brian Silvermanad9e0002014-04-13 14:55:57 -0700143 (right_goal_state(0, 0) + action_q_->goal->right_initial_position));
Austin Schuh577edf62014-04-13 10:33:05 -0700144 const double velocity_error =
Brian Silvermanada5f2c2015-02-01 02:41:14 -0500145 ::std::abs(control_loops::drivetrain_queue.status->robot_speed);
Austin Schuh577edf62014-04-13 10:33:05 -0700146 if (left_error < kPositionThreshold && right_error < kPositionThreshold &&
147 velocity_error < 0.2) {
148 break;
149 } else {
150 LOG(DEBUG, "Drivetrain error is %f, %f, %f\n", left_error, right_error,
151 velocity_error);
152 }
Brian Silvermanada5f2c2015-02-01 02:41:14 -0500153 control_loops::drivetrain_queue.status.FetchNextBlocking();
Austin Schuh577edf62014-04-13 10:33:05 -0700154 }
Austin Schuh80ff2e12014-03-08 12:06:19 -0800155 LOG(INFO, "Done moving\n");
156}
157
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800158::std::unique_ptr<aos::common::actions::TypedAction<
159 ::frc971::actions::DrivetrainActionQueueGroup>>
Austin Schuh80ff2e12014-03-08 12:06:19 -0800160MakeDrivetrainAction() {
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800161 return ::std::unique_ptr<aos::common::actions::TypedAction<
162 ::frc971::actions::DrivetrainActionQueueGroup>>(
163 new aos::common::actions::TypedAction<
164 ::frc971::actions::DrivetrainActionQueueGroup>(
Austin Schuh80ff2e12014-03-08 12:06:19 -0800165 &::frc971::actions::drivetrain_action));
166}
167
168} // namespace actions
169} // namespace frc971