Compare commits

...

3 Commits

Author SHA1 Message Date
Matthias Grob b5f6699f2e mixer_module: send a last sample out after all outputs were disabled
This matters for PWM when the last output gets disabled on either FMU or IO
it would just keep on running.

Also when rebooting with a parameters reset or new airframe with no mapped outputs
it would previously keep outputting PWM with the disarmed value of the new airframe
e.g. 1000us which is a safety hazard because servos could break the physical limit of the
model or miscalibrated ESCs spinning motors.
2024-03-25 19:21:54 +01:00
Matthias Grob 1096384a38 px4iofirmware: don't switch to disarmed or failsafe value on disabled PWM outputs
If the output is set to 0 then the FMU had this channel disabled/no function mapped
to it. In that case we do not want to suddenly start outputing failsafe or disarmed
signals.
2024-03-25 19:21:54 +01:00
Matthias Grob 999a71c4dd px4io: don't output on disabled PWM pins
Same logic as on the FMU PWM updateOutputs() in PWMOut.cpp
2024-03-25 19:21:54 +01:00
19 changed files with 26 additions and 7 deletions

View File

@ -364,6 +364,13 @@ PX4IO::~PX4IO()
bool PX4IO::updateOutputs(bool stop_motors, uint16_t outputs[MAX_ACTUATORS], bool PX4IO::updateOutputs(bool stop_motors, uint16_t outputs[MAX_ACTUATORS],
unsigned num_outputs, unsigned num_control_groups_updated) unsigned num_outputs, unsigned num_control_groups_updated)
{ {
for (size_t i = 0; i < num_outputs; i++) {
if (!_mixing_output.isFunctionSet(i)) {
// do not run any signal on disabled channels
outputs[i] = 0;
}
}
if (!_test_fmu_fail) { if (!_test_fmu_fail) {
/* output to the servos */ /* output to the servos */
io_reg_set(PX4IO_PAGE_DIRECT_PWM, 0, outputs, num_outputs); io_reg_set(PX4IO_PAGE_DIRECT_PWM, 0, outputs, num_outputs);

View File

@ -455,7 +455,8 @@ bool MixingOutput::update()
} }
} }
if (!all_disabled) { // Send output if any function mapped or one last disabling sample
if (!all_disabled || !_was_all_disabled) {
if (!_armed.armed && !_armed.manual_lockdown) { if (!_armed.armed && !_armed.manual_lockdown) {
_actuator_test.overrideValues(outputs, _max_num_outputs); _actuator_test.overrideValues(outputs, _max_num_outputs);
} }
@ -463,6 +464,8 @@ bool MixingOutput::update()
limitAndUpdateOutputs(outputs, has_updates); limitAndUpdateOutputs(outputs, has_updates);
} }
_was_all_disabled = all_disabled;
return true; return true;
} }

View File

@ -288,6 +288,7 @@ private:
hrt_abstime _lowrate_schedule_interval{300_ms}; hrt_abstime _lowrate_schedule_interval{300_ms};
ActuatorTest _actuator_test{_function_assignment}; ActuatorTest _actuator_test{_function_assignment};
uint32_t _reversible_mask{0}; ///< per-output bits. If set, the output is configured to be reversible (motors only) uint32_t _reversible_mask{0}; ///< per-output bits. If set, the output is configured to be reversible (motors only)
bool _was_all_disabled{false};
uORB::SubscriptionCallbackWorkItem *_subscription_callback{nullptr}; ///< current scheduling callback uORB::SubscriptionCallbackWorkItem *_subscription_callback{nullptr}; ///< current scheduling callback

View File

@ -191,11 +191,15 @@ TEST_F(MixerModuleTest, basic)
mixing_output.setAllMaxValues(MAX_VALUE); mixing_output.setAllMaxValues(MAX_VALUE);
EXPECT_EQ(test_module.num_updates, 0); EXPECT_EQ(test_module.num_updates, 0);
// all functions disabled: not expected to get an update // all functions disabled: expect to get one single update to process disabling the output signal
mixing_output.update(); mixing_output.update();
mixing_output.updateSubscriptions(false); mixing_output.updateSubscriptions(false);
mixing_output.update(); mixing_output.update();
EXPECT_EQ(test_module.num_updates, 0); EXPECT_EQ(test_module.num_updates, 1);
mixing_output.update();
mixing_output.updateSubscriptions(false);
mixing_output.update();
EXPECT_EQ(test_module.num_updates, 1);
test_module.reset(); test_module.reset();
// configure motor, ensure all still disarmed // configure motor, ensure all still disarmed

View File

@ -180,15 +180,19 @@ mixer_tick()
* Run the mixers. * Run the mixers.
*/ */
if (source == MIX_FAILSAFE) { if (source == MIX_FAILSAFE) {
/* copy failsafe values to the servo outputs */ // Set failsafe value if the PWM output isn't disabled
for (unsigned i = 0; i < PX4IO_SERVO_COUNT; i++) { for (unsigned i = 0; i < PX4IO_SERVO_COUNT; i++) {
r_page_servos[i] = r_page_servo_failsafe[i]; if (r_page_servos[i] != 0) {
r_page_servos[i] = r_page_servo_failsafe[i];
}
} }
} else if (source == MIX_DISARMED) { } else if (source == MIX_DISARMED) {
/* copy disarmed values to the servo outputs */ // Set disarmed value if the PWM output isn't disabled
for (unsigned i = 0; i < PX4IO_SERVO_COUNT; i++) { for (unsigned i = 0; i < PX4IO_SERVO_COUNT; i++) {
r_page_servos[i] = r_page_servo_disarmed[i]; if (r_page_servos[i] != 0) {
r_page_servos[i] = r_page_servo_disarmed[i];
}
} }
} }