Drivetrain is now tuned. Quite stiff.
diff --git a/frc971/control_loops/drivetrain/drivetrain.cc b/frc971/control_loops/drivetrain/drivetrain.cc
index 63e6718..79e2864 100644
--- a/frc971/control_loops/drivetrain/drivetrain.cc
+++ b/frc971/control_loops/drivetrain/drivetrain.cc
@@ -3,6 +3,7 @@
#include <stdio.h>
#include <sched.h>
#include <cmath>
+#include <memory>
#include "aos/aos_core.h"
#include "aos/common/logging/logging.h"
@@ -21,72 +22,61 @@
// Width of the robot.
const double width = 22.0 / 100.0 * 2.54;
-class DrivetrainMotorsSS : public StateFeedbackLoop<4, 2, 2> {
+class DrivetrainMotorsSS {
public:
- DrivetrainMotorsSS (void)
- : StateFeedbackLoop(MakeDrivetrainLoop()) {
+ DrivetrainMotorsSS ()
+ : loop_(new StateFeedbackLoop<4, 2, 2>(MakeDrivetrainLoop())) {
_offset = 0;
_integral_offset = 0;
_left_goal = 0.0;
_right_goal = 0.0;
_raw_left = 0.0;
_raw_right = 0.0;
+ _control_loop_driving = false;
}
void SetGoal(double left, double left_velocity, double right, double right_velocity) {
_left_goal = left;
_right_goal = right;
- R << left + _integral_offset * width / 2.0, left_velocity, right - _integral_offset * width / 2.0, right_velocity;
+ loop_->R << left, left_velocity, right, right_velocity;
}
void SetRawPosition(double left, double right) {
_raw_right = right;
_raw_left = left;
- Y << left + _offset + _integral_offset, right - _offset + _integral_offset;
+ loop_->Y << left, right;
}
- void SetPosition(double left, double right, double gyro, bool control_loop_driving) {
+ void SetPosition(
+ double left, double right, double gyro, bool control_loop_driving) {
// Decay the offset quickly because this gyro is great.
_offset = (0.25) * (right - left - gyro * width) / 2.0 + 0.75 * _offset;
const double angle_error = (_right_goal - _left_goal) / width - (_raw_right - _offset - _raw_left - _offset) / width;
- if (!control_loop_driving) {
- _integral_offset = 0.0;
- } else if (::std::abs(angle_error) < M_PI / 10.0) {
- _integral_offset -= angle_error * 0.010;
- } else {
- _integral_offset *= 0.97;
- }
+ // TODO(aschuh): Add in the gyro.
+ _integral_offset = 0.0;
+ _offset = 0.0;
_gyro = gyro;
+ _control_loop_driving = control_loop_driving;
SetRawPosition(left, right);
LOG(DEBUG, "Left %f->%f Right %f->%f Gyro %f aerror %f ioff %f\n", left + _offset, _left_goal, right - _offset, _right_goal, gyro, angle_error, _integral_offset);
}
- double UnDeadband(double value) {
- const double positive_deadband_power = 0.15 * 12;
- const double negative_deadband_power = 0.09 * 12;
- if (value > 0) {
- value += positive_deadband_power;
- }
- if (value < 0) {
- value -= negative_deadband_power;
- }
- if (value > 12.0) {
- value = 12.0;
- }
- if (value < -12.0) {
- value = -12.0;
- }
- return value;
+
+ void Update(bool update_observer, bool stop_motors) {
+ loop_->Update(update_observer, stop_motors);
}
- void SendMotors(Drivetrain::Output *status) {
- if (status) {
- status->left_voltage = UnDeadband(U[0]);
- status->right_voltage = UnDeadband(U[1]);
+ void SendMotors(Drivetrain::Output *output) {
+ if (output) {
+ output->left_voltage = loop_->U(0, 0);
+ output->right_voltage = loop_->U(1, 0);
}
}
void PrintMotors() const {
// LOG(DEBUG, "Left Power %f Right Power %f lg %f rg %f le %f re %f gyro %f\n", U[0], U[1], R[0], R[2], Y[0], Y[1], _gyro);
- LOG(DEBUG, "lg %f rg %f le %f re %f gyro %f off %f\n", R[0], R[2], Y[0], Y[1], _gyro * 180.0 / M_PI, _offset);
+ ::Eigen::Matrix<double, 4, 1> E = loop_->R - loop_->X_hat;
+ LOG(DEBUG, "E[0, 0]: %f E[1, 0] %f E[2, 0] %f E[3, 0] %f\n", E(0, 0), E(1, 0), E(2, 0), E(3, 0));
}
private:
+ ::std::unique_ptr<StateFeedbackLoop<4, 2, 2>> loop_;
+
double _integral_offset;
double _offset;
double _gyro;
@@ -94,6 +84,7 @@
double _right_goal;
double _raw_left;
double _raw_right;
+ bool _control_loop_driving;
};
class DrivetrainMotorsOL {
@@ -273,7 +264,8 @@
double left_goal = goal->left_goal;
double right_goal = goal->right_goal;
- dt_closedloop.SetGoal(left_goal, 0.0, right_goal, 0.0);
+ dt_closedloop.SetGoal(left_goal, goal->left_velocity_goal,
+ right_goal, goal->right_velocity_goal);
if (!bad_pos) {
const double left_encoder = position->left_encoder;
const double right_encoder = position->right_encoder;
@@ -284,7 +276,8 @@
dt_closedloop.SetRawPosition(left_encoder, right_encoder);
}
}
- dt_closedloop.Update(!bad_pos, bad_pos || bad_output);
+ dt_closedloop.Update(position, output == NULL);
+ //dt_closedloop.PrintMotors();
dt_openloop.SetGoal(wheel, throttle, quickturn, highgear);
dt_openloop.Update();
if (control_loop_driving) {
diff --git a/frc971/control_loops/drivetrain/drivetrain.q b/frc971/control_loops/drivetrain/drivetrain.q
index f56c115..2085eb8 100644
--- a/frc971/control_loops/drivetrain/drivetrain.q
+++ b/frc971/control_loops/drivetrain/drivetrain.q
@@ -12,7 +12,9 @@
bool quickturn;
bool control_loop_driving;
float left_goal;
+ float left_velocity_goal;
float right_goal;
+ float right_velocity_goal;
};
message Position {
diff --git a/frc971/control_loops/drivetrain/drivetrain_lib_test.cc b/frc971/control_loops/drivetrain/drivetrain_lib_test.cc
index 75a8b8f..d15de44 100644
--- a/frc971/control_loops/drivetrain/drivetrain_lib_test.cc
+++ b/frc971/control_loops/drivetrain/drivetrain_lib_test.cc
@@ -39,7 +39,7 @@
void Reinitialize() {
drivetrain_plant_->X(0, 0) = 0.0;
drivetrain_plant_->X(1, 0) = 0.0;
- drivetrain_plant_->Y = drivetrain_plant_->C * drivetrain_plant_->X;
+ drivetrain_plant_->Y = drivetrain_plant_->C() * drivetrain_plant_->X;
last_left_position_ = drivetrain_plant_->Y(0, 0);
last_right_position_ = drivetrain_plant_->Y(1, 0);
}
diff --git a/frc971/control_loops/drivetrain/drivetrain_motor_plant.cc b/frc971/control_loops/drivetrain/drivetrain_motor_plant.cc
index d4edba8..e543c9f 100644
--- a/frc971/control_loops/drivetrain/drivetrain_motor_plant.cc
+++ b/frc971/control_loops/drivetrain/drivetrain_motor_plant.cc
@@ -1,16 +1,17 @@
#include "frc971/control_loops/drivetrain/drivetrain_motor_plant.h"
+#include <vector>
+
#include "frc971/control_loops/state_feedback_loop.h"
namespace frc971 {
namespace control_loops {
-
-StateFeedbackPlant<4, 2, 2> MakeDrivetrainPlant() {
+StateFeedbackPlantCoefficients<4, 2, 2> MakeDrivetrainPlantCoefficients() {
Eigen::Matrix<double, 4, 4> A;
- A << 1.0, 0.0081841122497, 0.0, -5.9473473594e-05, 0.0, 0.660289401132, 0.0, -0.0103071702002, 0.0, -5.9473473594e-05, 1.0, 0.0081841122497, 0.0, -0.0103071702002, 0.0, 0.660289401132;
+ A << 1.0, 0.00931379160739, 0.0, 4.70184876909e-06, 0.0, 0.865971883056, 0.0, 0.000895808426591, 0.0, 4.70184876909e-06, 1.0, 0.00931379160739, 0.0, 0.000895808426591, 0.0, 0.865971883056;
Eigen::Matrix<double, 4, 2> B;
- B << 0.000333031510271, 1.09073596255e-05, 0.0623024929693, 0.00189032194188, 1.09073596255e-05, 0.000333031510271, 0.00189032194188, 0.0623024929693;
+ B << 0.000126707931029, -8.6819330098e-07, 0.0247482041615, -0.000165410440259, -8.6819330098e-07, 0.000126707931029, -0.000165410440259, 0.0247482041615;
Eigen::Matrix<double, 2, 4> C;
C << 1, 0, 0, 0, 0, 0, 1, 0;
Eigen::Matrix<double, 2, 2> D;
@@ -19,16 +20,28 @@
U_max << 12.0, 12.0;
Eigen::Matrix<double, 2, 1> U_min;
U_min << -12.0, -12.0;
- return StateFeedbackPlant<4, 2, 2>(A, B, C, D, U_max, U_min);
+ return StateFeedbackPlantCoefficients<4, 2, 2>(A, B, C, D, U_max, U_min);
+}
+
+StateFeedbackController<4, 2, 2> MakeDrivetrainController() {
+ Eigen::Matrix<double, 4, 2> L;
+ L << 1.70597188306, 0.000895808426591, 66.3158545945, 0.117712892743, 0.000895808426591, 1.70597188306, 0.117712892743, 66.3158545945;
+ Eigen::Matrix<double, 2, 4> K;
+ K << 240.432225842, 14.3659115621, 1.60698530163, 0.13242189318, 1.60698530163, 0.13242189318, 240.432225842, 14.3659115621;
+ return StateFeedbackController<4, 2, 2>(L, K, MakeDrivetrainPlantCoefficients());
+}
+
+StateFeedbackPlant<4, 2, 2> MakeDrivetrainPlant() {
+ ::std::vector<StateFeedbackPlantCoefficients<4, 2, 2> *> plants(1);
+ plants[0] = new StateFeedbackPlantCoefficients<4, 2, 2>(MakeDrivetrainPlantCoefficients());
+ return StateFeedbackPlant<4, 2, 2>(plants);
}
StateFeedbackLoop<4, 2, 2> MakeDrivetrainLoop() {
- Eigen::Matrix<double, 4, 2> L;
- L << 1.50028940113, -0.0103071702002, 41.1373728147, -1.1627040905, -0.0103071702002, 1.50028940113, -1.1627040905, 41.1373728147;
- Eigen::Matrix<double, 2, 4> K;
- K << 48.196534943, -0.087263189034, -1.46233261597, -0.163410937407, -1.46233261597, -0.163410937407, 48.196534943, -0.087263189034;
- return StateFeedbackLoop<4, 2, 2>(L, K, MakeDrivetrainPlant());
+ ::std::vector<StateFeedbackController<4, 2, 2> *> controllers(1);
+ controllers[0] = new StateFeedbackController<4, 2, 2>(MakeDrivetrainController());
+ return StateFeedbackLoop<4, 2, 2>(controllers);
}
-} // namespace frc971
} // namespace control_loops
+} // namespace frc971
diff --git a/frc971/control_loops/drivetrain/drivetrain_motor_plant.h b/frc971/control_loops/drivetrain/drivetrain_motor_plant.h
index af43b46..2060b6f 100644
--- a/frc971/control_loops/drivetrain/drivetrain_motor_plant.h
+++ b/frc971/control_loops/drivetrain/drivetrain_motor_plant.h
@@ -6,11 +6,15 @@
namespace frc971 {
namespace control_loops {
+StateFeedbackPlantCoefficients<4, 2, 2> MakeDrivetrainPlantCoefficients();
+
+StateFeedbackController<4, 2, 2> MakeDrivetrainController();
+
StateFeedbackPlant<4, 2, 2> MakeDrivetrainPlant();
StateFeedbackLoop<4, 2, 2> MakeDrivetrainLoop();
-} // namespace frc971
} // namespace control_loops
+} // namespace frc971
#endif // FRC971_CONTROL_LOOPS_DRIVETRAIN_DRIVETRAIN_MOTOR_PLANT_H_
diff --git a/frc971/control_loops/python/drivetrain.py b/frc971/control_loops/python/drivetrain.py
index e5a8217..0e791cb 100755
--- a/frc971/control_loops/python/drivetrain.py
+++ b/frc971/control_loops/python/drivetrain.py
@@ -18,7 +18,7 @@
self.free_current = 2.7
# Moment of inertia of the drivetrain in kg m^2
# Just borrowed from last year.
- self.J = 7.0
+ self.J = 6.4
# Mass of the robot, in kg.
self.m = 68
# Radius of the robot, in meters (from last year).
@@ -26,7 +26,7 @@
# Radius of the wheels, in meters.
self.r = .04445
# Resistance of the motor, divided by the number of motors.
- self.R = 12.0 / self.stall_current / 6
+ self.R = 12.0 / self.stall_current / 6 + 0.03
# Motor velocity constant
self.Kv = ((self.free_speed / 60.0 * 2.0 * numpy.pi) /
(12.0 - self.R * self.free_current))
@@ -65,12 +65,12 @@
self.D = numpy.matrix([[0, 0],
[0, 0]])
- self.ContinuousToDiscrete(self.A_continuous, self.B_continuous,
- self.dt, self.C)
+ self.A, self.B = self.ContinuousToDiscrete(
+ self.A_continuous, self.B_continuous, self.dt)
# Poles from last year.
- self.hp = 0.8
- self.lp = 0.85
+ self.hp = 0.65
+ self.lp = 0.83
self.PlaceControllerPoles([self.hp, self.hp, self.lp, self.lp])
print self.K
@@ -81,6 +81,7 @@
self.U_max = numpy.matrix([[12.0], [12.0]])
self.U_min = numpy.matrix([[-12.0], [-12.0]])
+ self.InitializeState()
def main(argv):
# Simulate the response of the system to a step input.
@@ -92,9 +93,9 @@
simulated_left.append(drivetrain.X[0, 0])
simulated_right.append(drivetrain.X[2, 0])
- pylab.plot(range(100), simulated_left)
- pylab.plot(range(100), simulated_right)
- pylab.show()
+ #pylab.plot(range(100), simulated_left)
+ #pylab.plot(range(100), simulated_right)
+ #pylab.show()
# Simulate forwards motion.
drivetrain = Drivetrain()
@@ -109,9 +110,9 @@
close_loop_left.append(drivetrain.X[0, 0])
close_loop_right.append(drivetrain.X[2, 0])
- pylab.plot(range(100), close_loop_left)
- pylab.plot(range(100), close_loop_right)
- pylab.show()
+ #pylab.plot(range(100), close_loop_left)
+ #pylab.plot(range(100), close_loop_right)
+ #pylab.show()
# Try turning in place
drivetrain = Drivetrain()
@@ -126,9 +127,9 @@
close_loop_left.append(drivetrain.X[0, 0])
close_loop_right.append(drivetrain.X[2, 0])
- pylab.plot(range(100), close_loop_left)
- pylab.plot(range(100), close_loop_right)
- pylab.show()
+ #pylab.plot(range(100), close_loop_left)
+ #pylab.plot(range(100), close_loop_right)
+ #pylab.show()
# Try turning just one side.
drivetrain = Drivetrain()
@@ -143,19 +144,19 @@
close_loop_left.append(drivetrain.X[0, 0])
close_loop_right.append(drivetrain.X[2, 0])
- pylab.plot(range(100), close_loop_left)
- pylab.plot(range(100), close_loop_right)
- pylab.show()
+ #pylab.plot(range(100), close_loop_left)
+ #pylab.plot(range(100), close_loop_right)
+ #pylab.show()
# Write the generated constants out to a file.
if len(argv) != 3:
print "Expected .h file name and .cc file name"
else:
+ loop_writer = control_loop.ControlLoopWriter("Drivetrain", [drivetrain])
if argv[1][-3:] == '.cc':
- print '.cc file is second'
+ loop_writer.Write(argv[2], argv[1])
else:
- drivetrain.DumpHeaderFile(argv[1])
- drivetrain.DumpCppFile(argv[2], argv[1])
+ loop_writer.Write(argv[1], argv[2])
if __name__ == '__main__':
sys.exit(main(sys.argv))
diff --git a/frc971/control_loops/update_drivetrain.sh b/frc971/control_loops/update_drivetrain.sh
new file mode 100755
index 0000000..9d17e99
--- /dev/null
+++ b/frc971/control_loops/update_drivetrain.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+#
+# Updates the drivetrain controller.
+
+./python/drivetrain.py drivetrain/drivetrain_motor_plant.h \
+ drivetrain/drivetrain_motor_plant.cc