Code changes in src/ (1 file).
- Most activity in
src/(+5/−3).
Full analysis → Summary: automatic analysis
src/ (+5/−3).Full analysis → Summary: automatic analysis
None.
No post: no meaningful change.
| Module | Added | Modified | Removed | Lines + | Lines − |
|---|---|---|---|---|---|
src | 0 | 1 | 0 | +5 | −3 |
| Path | Lines | Note | |
|---|---|---|---|
| M | src/modules/mc_nn_control/mc_nn_control_params.yaml | +5/−3 |
fix(mc_nn_control): correct errors and add the first unit tests (#28433) * fix(mc_nn_control): use single precision sqrt and correct two parameter/comment errors Three small corrections in the neural network controller, none of which change the commanded thrust for a valid configuration: - RescaleActions() called sqrt() rather than sqrtf(), promoting to double in a loop that runs once per angular velocity sample. On an FPU without double precision that is a software routine, four times per cycle, in the path whose execution time the module exists to measure. - MC_NN_THRST_COEF declared a minimum of 0.0, but the value is used as a divisor in RescaleActions(). Zero is therefore an in-range setting that makes the motor scaling non-finite. Raise the minimum off zero. - The comment above PopulateInputTensor() gives the observation order as [pos_err(3), lin_vel(3), att(6), ang_vel(3)], but the code below it, NeuralControl.msg and the module usage text all use [pos_err(3), att(6), lin_vel(3), ang_vel(3)]. Attitude and linear velocity are transposed in the comment only. Assisted-by: Claude:claude-fable-5 Signed-off-by: Saibernard Yogendran <bernie97@seas.upenn.edu> * refactor(mc_nn_control): extract the action rescaling into a testable header The mapping from network action to motor command lived inside a private member operating on the TFLM output tensor, so it could not be unit tested. Move the per element math into a dependency free header function. Behaviour is unchanged. Assisted-by: Claude:claude-fable-5 Signed-off-by: Saibernard Yogendran <bernie97@seas.upenn.edu> * fix(mc_nn_control): keep motor commands between idle and full scale The action to motor command mapping ran past both ends of the motor. On the shipped defaults action -1 mapped to -0.0077, which the motor output treats as a stopped motor while the other three keep thrusting, and every action above 0.61 mapped past full scale. With a minimum rpm above a ninth of the maximum the last stage also ran backwards for the first few thousandths of the range. All three come from normalizing the rpm against limits the thrust coefficient does not reach. Reported in #28417. Bound the normalized rpm between the limits, so a thrust below what the minimum rpm gives idles the motor and one above the maximum runs it at full scale, and write the thrust curve compensation as a x^2 + (1 - a) x so idle is exactly 0 and full scale exactly 1. The curve inside the limits is unchanged. Validate the three parameters at start and on every parameter update: finite, the coefficient above zero, the minimum at least zero and below the maximum, and a part of the action range wider than float resolution reaching the motor, so rounding cannot pass a window with no action inside it. Raw parameter writes are not bounded by the metadata, so this is checked in code. The mapping only ever uses a set that passed. An invalid set is reported as an error event, repeated while it stands, and the arming check for the mode is refused until it is corrected, so the commander neither arms into the mode nor keeps flying it. The mapping keeps the last valid set meanwhile, so the write itself never steps the motors. A valid set that covers less than the whole action range is reported as a warning naming what it does cover, when it changes and again when the mode is entered. The arming check reply was not zero initialized, which left two mode requirement fields to whatever was on the stack. Also from #28417: the loop performance counter was left open on the two early returns after inference, and actuator_motors.timestamp_sample was never set. Assisted-by: Claude:claude-fable-5 Signed-off-by: Saibernard Yogendran <bernie97@seas.upenn.edu> * test(mc_nn_control): add the module's first unit tests The action to motor command mapping had no tests. These assert the properties it has to keep rather than any particular output value: actions beyond the boundary clamp, every command stays between 0 and 1, the lowest action idles the motor and the highest runs it at full scale, the mapping never decreases and rises inside the achievable range, actions outside that range sit on the bounds, the output stays finite for every normal action and across the documented parameter ranges, a non finite action gives no command, and invalid limits are rejected. Every threshold comes from the mapping's own achievable range, and each property is checked for the shipped defaults, a smaller motor, and a motor whose limits cover the whole action range, so a change to the defaults only fails them when a property is broken. Assisted-by: Claude:claude-fable-5 Signed-off-by: Saibernard Yogendran <bernie97@seas.upenn.edu> * ci(tests): run the mc_nn_control unit tests in the neural configuration make tests builds px4_sitl_test, which does not enable MC_NN_CONTROL, so the unit tests the module registers were never built or run upstream. The only configuration that enables the module is px4_sitl_neural. Add a tests_neural target that builds that configuration with testing on and runs the module's tests, the same shape as tests_daa_crosstrack and tests_vtest_moving, and run it from the Unit Tests job. Assisted-by: Claude:claude-fable-5-1 Signed-off-by: Saibernard Yogendran <bernie97@seas.upenn.edu> --------- Signed-off-by: Saibernard Yogendran <bernie97@seas.upenn.edu>