@@ 91,9 91,8 @@ fn solve_thrust(
// +Z == counterclockwise/ccw
// -Z == clockwise/cw
- const MAGIC_TORQUE_SCALE_FACTOR: f32 = 100.0; // mystery units
-
let mut target_unit_vector = Vec3::ZERO;
+ let mut target_torque_vector = Vec3::ZERO;
let mut anything_pressed = false;
@@ 115,16 114,14 @@ fn solve_thrust(
}
if input.pressed(&ClientAction::TorqueCw) {
anything_pressed = true;
- target_unit_vector += Vec3::new(0.0, 0.0, -1.0 / MAGIC_TORQUE_SCALE_FACTOR);
+ target_torque_vector += Vec3::new(0.0, 0.0, -1.0);
}
if input.pressed(&ClientAction::TorqueCcw) {
anything_pressed = true;
- target_unit_vector += Vec3::new(0.0, 0.0, 1.0 / MAGIC_TORQUE_SCALE_FACTOR);
+ target_torque_vector += Vec3::new(0.0, 0.0, 1.0);
}
- target_unit_vector = target_unit_vector.normalize();
-
- if target_unit_vector == Vec3::ZERO || !anything_pressed {
+ if !anything_pressed {
trace!("no buttons are pressed; zeroing thrust solution");
trace!("solved thrust in {}ms", start.elapsed().as_millis());
solution.converged = true;
@@ 132,6 129,13 @@ fn solve_thrust(
return;
}
+ if target_unit_vector != Vec3::ZERO {
+ target_unit_vector = target_unit_vector.normalize();
+ }
+ if target_torque_vector != Vec3::ZERO {
+ target_torque_vector = target_torque_vector.normalize();
+ }
+
let mut all_parts = vec![hearty];
if let Some(parts) = our_parts {
all_parts.extend(parts.iter());
@@ 158,16 162,27 @@ fn solve_thrust(
// determine our rotational offset from hearty
let relative_rotation = thruster_transform.rotation() * -hearty_transform.rotation();
- let thruster_torque = relative_translation.extend(0.0).cross(thruster_vector.extend(0.0)).z / MAGIC_TORQUE_SCALE_FACTOR;
+ let thruster_torque = relative_translation.normalize().extend(0.0).cross(thruster_vector.normalize().extend(0.0)).z;
+ let renormalized_thruster_torque = if thruster_torque.abs() < 0.1 {
+ 0.0
+ } else if thruster_torque < 0.0 {
+ -1.0
+ } else {
+ 1.0
+ };
+
+ trace!("thruster: {:?} {}({})", thruster_vector, thruster_torque, renormalized_thruster_torque);
// magically assemble the worldspace vector! for the solver (not shipspace)
- let target_vector = thruster_vector.extend(thruster_torque);
- all_thrusters.push((thruster_id, target_vector));
+ all_thrusters.push((thruster_id,
+ thruster_vector.extend(0.0),
+ Vec3::new(0.0, 0.0, renormalized_thruster_torque)
+ ));
}
}
- // calculate thrust and torque values
+ // calculate thrust ~~and torque~~ values
trace!("found {} thrusters, computing coefficients", all_thrusters.len());
for thruster in &all_thrusters {
@@ 176,34 191,43 @@ fn solve_thrust(
let coefficients = all_thrusters.iter()
.map(|u| {
- trace!("{} dot {}", target_unit_vector, u.1.normalize());
- target_unit_vector.dot(u.1.normalize())
+ trace!("{} dot {}, {} dot {}", target_unit_vector, u.1.normalize(), target_torque_vector, u.2.normalize());
+ (
+ target_unit_vector.dot(u.1.normalize()),
+ target_torque_vector.dot(u.2.normalize())
+ )
})
.map(|u| {
- trace!("=> {u}");
+ trace!("=> {}, {}", u.0, u.1);
// improve reliability:
// if dot is <0.1, zap it entirely (this thruster is not helping)
// TODO: figure out how to make this adjustable
- if u.abs() < 0.1 {
- 0.0
+ if u.0.abs() < 0.1 {
+ (0.0, u.1)
} else {
- u
+ (u.0, u.1)
}
})
//.map(|u| u.powi(3))
.collect::<Vec<_>>();
- trace!("preparing model");
- let mut problem = Problem::new(OptimizationDirection::Maximize);
+ trace!("preparing models");
+ let mut thrust_problem = Problem::new(OptimizationDirection::Maximize);
+ let mut torque_problem = Problem::new(OptimizationDirection::Maximize);
// add variables to problem
let variables = coefficients.iter()
- .map(|u| problem.add_var(*u as f64, (0.0, 1.0)))
+ .map(|u| {
+ (
+ thrust_problem.add_var(u.0 as f64, (0.0, 1.0)),
+ torque_problem.add_var(u.1 as f64, (0.0, 1.0))
+ )
+ })
.collect::<Vec<_>>();
trace!("prepared {} variables; solving", variables.len());
- let ssolution = match problem.solve() {
+ let thrust_solution = match thrust_problem.solve() {
Ok(soln) => soln,
Err(e) => {
match e {
@@ 225,9 249,32 @@ fn solve_thrust(
}
}
};
+ let torque_solution = match torque_problem.solve() {
+ Ok(soln) => soln,
+ Err(e) => {
+ match e {
+ microlp::Error::Infeasible => {
+ error!("failed to solve for torque: constraints cannot be satisfied");
+ error!("failed to solve for torque after {}ms", start.elapsed().as_millis());
+ return;
+ },
+ microlp::Error::Unbounded => {
+ error!("failed to solve for torque: system is unbounded");
+ error!("failed to solve for torque after {}ms", start.elapsed().as_millis());
+ return;
+ },
+ microlp::Error::InternalError(e) => {
+ error!("failed to solve for torque: solver encountered internal error: {e}");
+ error!("failed to solve for torque after {}ms", start.elapsed().as_millis());
+ return;
+ }
+ }
+ }
+ };
- trace!("found thrust solution!");
- trace!("solution alignment (higher is better): {}", ssolution.objective());
+ trace!("found thrust+torque solution!");
+ trace!("thrust solution alignment (higher is better): {}", thrust_solution.objective());
+ trace!("torque solution alignment (higher is better): {}", torque_solution.objective());
let mut new_soln = ThrustSolution {
thrusters_on: BTreeSet::default(),
@@ 235,15 282,16 @@ fn solve_thrust(
};
for thruster in all_thrusters.iter().enumerate() {
- trace!("solution: thruster #{} ({:?}): {} @ coeff {}", thruster.0, thruster.1.0, ssolution.var_value(variables[thruster.0]), coefficients[thruster.0]);
+ trace!("thrust solution: thruster #{} ({:?}): {} @ coeff {}", thruster.0, thruster.1.0, thrust_solution.var_value(variables[thruster.0].0), coefficients[thruster.0].0);
+ trace!("torque solution: thruster #{} ({:?}): {} @ coeff {}", thruster.0, thruster.1.0, torque_solution.var_value(variables[thruster.0].1), coefficients[thruster.0].1);
// TODO: make this more easily adjustable
- if *ssolution.var_value(variables[thruster.0]) > 0.8 {
+ if *thrust_solution.var_value(variables[thruster.0].0) > 0.8 || *torque_solution.var_value(variables[thruster.0].1) > 0.8 {
new_soln.thrusters_on.insert(*thruster.1.0);
}
}
let elapsed = start.elapsed();
- debug!(?elapsed, ?target_unit_vector, "solved for thrust");
+ debug!(?elapsed, ?target_unit_vector, ?target_torque_vector, "solved for thrust and torque");
*solution = new_soln;
events.write(solution.clone());
return;