diff --git a/crates/lyapunov-demo/src/main.rs b/crates/lyapunov-demo/src/main.rs index 5d9adcd..e5f863d 100644 --- a/crates/lyapunov-demo/src/main.rs +++ b/crates/lyapunov-demo/src/main.rs @@ -4,54 +4,59 @@ use lyapunov::units::*; use lyapunov::{Controller, DCMotor, Integrator, LinearFeedback, Pendulum, Rk4}; fn main() { - let motor = DCMotor::new( - ElectricalResistance::new::(1.0), - Inductance::new::(0.5), + let qube_servo_2 = DCMotor::new( + ElectricalResistance::new::(8.4), + Inductance::new::(0.00116), lyapunov::TorqueConstant::from( - Torque::new::(0.5) / ElectricCurrent::new::(1.0), + Torque::new::(0.042) / ElectricCurrent::new::(1.0), ), ElectricCurrent::new::(2.0), - ElectricPotential::new::(12.0), + Voltage::new::(10.0), ); let system = Pendulum::new( - Mass::new::(1.0), - Length::new::(1.0), - MomentOfInertia::new::(1.0), + Mass::new::(0.024), + Length::new::(0.129), + MomentOfInertia::new::(3.33 * 0.00001), Acceleration::new::(9.81), - motor, + qube_servo_2, ); // Gains are in A/rad and A/(rad/s). - let feedback = LinearFeedback::<2, 1>::from_gains([8.0, 2.0]); + let feedback = LinearFeedback::<2, 1>::from_gains([0.02, 0.008]); let rk4 = Rk4; - // Start displaced from the downward equilibrium. + // Start at the downward (stable) equilibrium to demonstrate swing-up. let mut x = ThetaOmegaState::new( - Angle::new::(0.5), + Angle::new::(0.0), AngularVelocity::new::(0.0), ); let r = ThetaOmegaState::new( - Angle::new::(0.0), + Angle::new::(3.14159), AngularVelocity::new::(0.0), ); let dt = Time::new::(10.0); - for step in 0..300 { + for step in 0..1_000 { let t = dt * (step as f64); let u_fb = feedback.calculate(&system, t, &x, &r); - let u = u_fb.saturate(&system); + let u_ff = system.gravity_cancelling_input(&x); + let u_total = u_fb + u_ff; + let u = u_total.saturate(&system); + x = rk4.step(&system, t, &x, &u, dt); println!( - "t={:.2}s theta={:.3?} omega={:.3?} current={:.3?}", - t.value, + "t={:.2?} theta={:.3?} omega={:.3?} current={:.3?} u_fb={:.3?} u_ff={:.3?}", + t, x.angle(), x.angular_velocity(), u.current(), + u_fb.current(), + u_ff.current() ); } } diff --git a/crates/lyapunov/src/systems/pendulum.rs b/crates/lyapunov/src/systems/pendulum.rs index c81515b..47aa800 100644 --- a/crates/lyapunov/src/systems/pendulum.rs +++ b/crates/lyapunov/src/systems/pendulum.rs @@ -30,6 +30,13 @@ impl Pendulum { motor, } } + + pub fn gravity_cancelling_input(&self, x: &ThetaOmegaState) -> CurrentInput { + let theta = x.angle().value; + let current = self.mass.value * self.gravity.value * self.length.value * theta.sin() + / self.motor.torque_constant.value; + CurrentInput::new(ElectricCurrent::new::(current)) + } } impl System<2, 1> for Pendulum {