PWM automatic trigger system (ATS) for parachutes (#13726)

* parameter and logic to commander for triggering failsafe from external automatic trigger system.
* logic to startup script for enabling ATS. Added uORB publishing to pwm_input module.
* Refactored out CDev usage from pwm_input and ll40ls. Refactored out ll40ls specifics from pwm_input and cleaned up dead code.
This commit is contained in:
Jacob Dahl
2020-01-06 18:14:06 -07:00
committed by Daniel Agar
parent 5d110101b5
commit d08ec05bab
13 changed files with 350 additions and 566 deletions
+6
View File
@@ -58,6 +58,12 @@ then
fi fi
fi fi
# External automatic trigger system
if param compare FD_EXT_ATS_EN 1
then
pwm_input start
fi
# Lidar-Lite on I2C # Lidar-Lite on I2C
if param compare -s SENS_EN_LL40LS 2 if param compare -s SENS_EN_LL40LS 2
then then
+9
View File
@@ -360,6 +360,15 @@ else
set AUX_MODE pwm4 set AUX_MODE pwm4
fi fi
# Check if ATS is enabled
if param compare FD_EXT_ATS_EN 1
then
# Clear pins 5 and 6.
set FMU_MODE pwm4
set AUX_MODE pwm4
fi
if param greater TRIG_MODE 0 if param greater TRIG_MODE 0
then then
# We ONLY support trigger on pins 5 and 6 when simultanously using AUX for actuator output. # We ONLY support trigger on pins 5 and 6 when simultanously using AUX for actuator output.
+2 -2
View File
@@ -1,4 +1,4 @@
uint64 timestamp # time since system start (microseconds) uint64 timestamp # Time since system start (microseconds)
uint64 error_count uint64 error_count # Timer overcapture error flag (AUX5 or MAIN5)
uint32 pulse_width # Pulse width, timer counts uint32 pulse_width # Pulse width, timer counts
uint32 period # Period, timer counts uint32 period # Period, timer counts
+1
View File
@@ -15,6 +15,7 @@ uint8 FAILURE_NONE = 0
uint8 FAILURE_ROLL = 1 # (1 << 0) uint8 FAILURE_ROLL = 1 # (1 << 0)
uint8 FAILURE_PITCH = 2 # (1 << 1) uint8 FAILURE_PITCH = 2 # (1 << 1)
uint8 FAILURE_ALT = 4 # (1 << 2) uint8 FAILURE_ALT = 4 # (1 << 2)
uint8 FAILURE_EXT = 8 # (1 << 3)
# HIL # HIL
uint8 HIL_STATE_OFF = 0 uint8 HIL_STATE_OFF = 0
@@ -44,10 +44,13 @@
#include "LidarLitePWM.h" #include "LidarLitePWM.h"
#ifdef LIDAR_LITE_PWM_SUPPORTED
LidarLitePWM::LidarLitePWM(const uint8_t rotation) : LidarLitePWM::LidarLitePWM(const uint8_t rotation) :
LidarLite(rotation), LidarLite(rotation),
ScheduledWorkItem(MODULE_NAME, px4::wq_configurations::hp_default) ScheduledWorkItem(MODULE_NAME, px4::wq_configurations::hp_default)
{ {
px4_arch_configgpio(GPIO_VDD_RANGEFINDER_EN);
} }
LidarLitePWM::~LidarLitePWM() LidarLitePWM::~LidarLitePWM()
@@ -113,17 +116,16 @@ LidarLitePWM::measure()
int int
LidarLitePWM::collect() LidarLitePWM::collect()
{ {
int fd = ::open(PWMIN0_DEVICE_PATH, O_RDONLY); pwm_input_s pwm_input;
if (fd == -1) { if (_sub_pwm_input.update(&pwm_input)) {
return PX4_ERROR;
} _pwm = pwm_input;
if (::read(fd, &_pwm, sizeof(_pwm)) == sizeof(_pwm)) {
::close(fd);
return PX4_OK; return PX4_OK;
} }
::close(fd);
return EAGAIN; return EAGAIN;
} }
#endif
@@ -45,14 +45,15 @@
#include "LidarLite.h" #include "LidarLite.h"
#include <stdio.h>
#include <string.h>
#include <drivers/drv_hrt.h>
#include <drivers/drv_pwm_input.h>
#include <px4_platform_common/defines.h>
#include <px4_platform_common/px4_work_queue/ScheduledWorkItem.hpp> #include <px4_platform_common/px4_work_queue/ScheduledWorkItem.hpp>
#include <uORB/topics/pwm_input.h> #include <uORB/topics/pwm_input.h>
#include <uORB/Subscription.hpp>
#ifdef GPIO_GPIO5_OUTPUT
#define LIDAR_LITE_PWM_SUPPORTED
#define GPIO_VDD_RANGEFINDER_EN GPIO_GPIO5_OUTPUT
class LidarLitePWM : public LidarLite, public px4::ScheduledWorkItem class LidarLitePWM : public LidarLite, public px4::ScheduledWorkItem
{ {
@@ -73,7 +74,9 @@ protected:
private: private:
int _pwmSub{-1}; uORB::Subscription _sub_pwm_input{ORB_ID(pwm_input)};
pwm_input_s _pwm{}; pwm_input_s _pwm{};
}; };
#endif
@@ -164,7 +164,12 @@ start_pwm(const uint8_t rotation)
return PX4_OK; return PX4_OK;
} }
#ifdef LIDAR_LITE_PWM_SUPPORTED
instance = new LidarLitePWM(rotation); instance = new LidarLitePWM(rotation);
#else
instance = nullptr;
PX4_ERR("PWM input not supported.");
#endif
if (instance == nullptr) { if (instance == nullptr) {
PX4_ERR("Failed to instantiate the driver"); PX4_ERR("Failed to instantiate the driver");
-51
View File
@@ -1,51 +0,0 @@
/****************************************************************************
*
* Copyright (C) 2012 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
#pragma once
#include <sys/types.h>
#include <stdbool.h>
#include <time.h>
#include <queue.h>
#define PWMIN0_DEVICE_PATH "/dev/pwmin0"
__BEGIN_DECLS
/*
* Initialise the timer
*/
__EXPORT extern int pwm_input_main(int argc, char *argv[]);
__END_DECLS
File diff suppressed because it is too large Load Diff
+151
View File
@@ -0,0 +1,151 @@
/****************************************************************************
*
* Copyright (c) 2019 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
#include <drivers/drv_hrt.h>
#include <drivers/device/device.h>
#include <px4_platform_common/module.h>
#include <uORB/uORB.h>
#include <uORB/Publication.hpp>
#include <uORB/topics/pwm_input.h>
#if HRT_TIMER == PWMIN_TIMER
#error cannot share timer between HRT and PWMIN
#endif
#if !defined(GPIO_PWM_IN) || !defined(PWMIN_TIMER) || !defined(PWMIN_TIMER_CHANNEL)
#error PWMIN defines are needed in board_config.h for this board
#endif
/* Get the timer defines */
#define INPUT_TIMER PWMIN_TIMER
#include "timer_registers.h"
#define PWMIN_TIMER_BASE TIMER_BASE
#define PWMIN_TIMER_CLOCK TIMER_CLOCK
#define PWMIN_TIMER_POWER_REG TIMER_CLOCK_POWER_REG
#define PWMIN_TIMER_POWER_BIT TIMER_CLOCK_POWER_BIT
#define PWMIN_TIMER_VECTOR TIMER_IRQ_REG
/*
* HRT clock must be at least 1MHz
*/
#if PWMIN_TIMER_CLOCK <= 1000000
# error PWMIN_TIMER_CLOCK must be greater than 1MHz
#endif
/*
* Timer register accessors
*/
#define REG(_reg) (*(volatile uint32_t *)(PWMIN_TIMER_BASE + _reg))
#define rCR1 REG(STM32_GTIM_CR1_OFFSET)
#define rCR2 REG(STM32_GTIM_CR2_OFFSET)
#define rSMCR REG(STM32_GTIM_SMCR_OFFSET)
#define rDIER REG(STM32_GTIM_DIER_OFFSET)
#define rSR REG(STM32_GTIM_SR_OFFSET)
#define rEGR REG(STM32_GTIM_EGR_OFFSET)
#define rCCMR1 REG(STM32_GTIM_CCMR1_OFFSET)
#define rCCMR2 REG(STM32_GTIM_CCMR2_OFFSET)
#define rCCER REG(STM32_GTIM_CCER_OFFSET)
#define rCNT REG(STM32_GTIM_CNT_OFFSET)
#define rPSC REG(STM32_GTIM_PSC_OFFSET)
#define rARR REG(STM32_GTIM_ARR_OFFSET)
#define rCCR1 REG(STM32_GTIM_CCR1_OFFSET)
#define rCCR2 REG(STM32_GTIM_CCR2_OFFSET)
#define rCCR3 REG(STM32_GTIM_CCR3_OFFSET)
#define rCCR4 REG(STM32_GTIM_CCR4_OFFSET)
#define rDCR REG(STM32_GTIM_DCR_OFFSET)
#define rDMAR REG(STM32_GTIM_DMAR_OFFSET)
/*
* Specific registers and bits used by HRT sub-functions
*/
#if PWMIN_TIMER_CHANNEL == 1
#define rCCR_PWMIN_A rCCR1 /* compare register for PWMIN */
#define DIER_PWMIN_A (GTIM_DIER_CC1IE) /* interrupt enable for PWMIN */
#define SR_INT_PWMIN_A GTIM_SR_CC1IF /* interrupt status for PWMIN */
#define rCCR_PWMIN_B rCCR2 /* compare register for PWMIN */
#define SR_INT_PWMIN_B GTIM_SR_CC2IF /* interrupt status for PWMIN */
#define CCMR1_PWMIN ((0x02 << GTIM_CCMR1_CC2S_SHIFT) | (0x01 << GTIM_CCMR1_CC1S_SHIFT))
#define CCMR2_PWMIN 0
#define CCER_PWMIN (GTIM_CCER_CC2P | GTIM_CCER_CC1E | GTIM_CCER_CC2E)
#define SR_OVF_PWMIN (GTIM_SR_CC1OF | GTIM_SR_CC2OF)
#define SMCR_PWMIN_1 (0x05 << GTIM_SMCR_TS_SHIFT)
#define SMCR_PWMIN_2 ((0x04 << GTIM_SMCR_SMS_SHIFT) | SMCR_PWMIN_1)
#elif PWMIN_TIMER_CHANNEL == 2
#define rCCR_PWMIN_A rCCR2 /* compare register for PWMIN */
#define DIER_PWMIN_A (GTIM_DIER_CC2IE) /* interrupt enable for PWMIN */
#define SR_INT_PWMIN_A GTIM_SR_CC2IF /* interrupt status for PWMIN */
#define rCCR_PWMIN_B rCCR1 /* compare register for PWMIN */
#define DIER_PWMIN_B GTIM_DIER_CC1IE /* interrupt enable for PWMIN */
#define SR_INT_PWMIN_B GTIM_SR_CC1IF /* interrupt status for PWMIN */
#define CCMR1_PWMIN ((0x01 << GTIM_CCMR1_CC2S_SHIFT) | (0x02 << GTIM_CCMR1_CC1S_SHIFT))
#define CCMR2_PWMIN 0
#define CCER_PWMIN (GTIM_CCER_CC1P | GTIM_CCER_CC1E | GTIM_CCER_CC2E)
#define SR_OVF_PWMIN (GTIM_SR_CC1OF | GTIM_SR_CC2OF)
#define SMCR_PWMIN_1 (0x06 << GTIM_SMCR_TS_SHIFT)
#define SMCR_PWMIN_2 ((0x04 << GTIM_SMCR_SMS_SHIFT) | SMCR_PWMIN_1)
#else
#error PWMIN_TIMER_CHANNEL must be either 1 and 2.
#endif
class PWMIN : public ModuleBase<PWMIN>
{
public:
void start();
void publish(uint16_t status, uint32_t period, uint32_t pulse_width);
void print_info(void);
static int pwmin_tim_isr(int irq, void *context, void *arg);
static int custom_command(int argc, char *argv[]);
static int print_usage(const char *reason = nullptr);
static int task_spawn(int argc, char *argv[]);
private:
void timer_init(void);
uint32_t _error_count {};
uint32_t _pulses_captured {};
uint32_t _last_period {};
uint32_t _last_width {};
bool _timer_started {};
pwm_input_s _pwm {};
uORB::PublicationData<pwm_input_s> _pwm_input_pub{ORB_ID(pwm_input)};
};
@@ -40,6 +40,8 @@
#include "FailureDetector.hpp" #include "FailureDetector.hpp"
using namespace time_literals;
FailureDetector::FailureDetector(ModuleParams *parent) : FailureDetector::FailureDetector(ModuleParams *parent) :
ModuleParams(parent) ModuleParams(parent)
{ {
@@ -61,6 +63,10 @@ FailureDetector::update(const vehicle_status_s &vehicle_status)
if (isAttitudeStabilized(vehicle_status)) { if (isAttitudeStabilized(vehicle_status)) {
updated = updateAttitudeStatus(); updated = updateAttitudeStatus();
if (_param_fd_ext_ats_en.get()) {
updated |= updateExternalAtsStatus();
}
} else { } else {
updated = resetStatus(); updated = resetStatus();
} }
@@ -111,8 +117,8 @@ FailureDetector::updateAttitudeStatus()
hrt_abstime time_now = hrt_absolute_time(); hrt_abstime time_now = hrt_absolute_time();
// Update hysteresis // Update hysteresis
_roll_failure_hysteresis.set_hysteresis_time_from(false, (hrt_abstime)(1e6f * _param_fd_fail_r_ttri.get())); _roll_failure_hysteresis.set_hysteresis_time_from(false, (hrt_abstime)(1_s * _param_fd_fail_r_ttri.get()));
_pitch_failure_hysteresis.set_hysteresis_time_from(false, (hrt_abstime)(1e6f * _param_fd_fail_p_ttri.get())); _pitch_failure_hysteresis.set_hysteresis_time_from(false, (hrt_abstime)(1_s * _param_fd_fail_p_ttri.get()));
_roll_failure_hysteresis.set_state_and_update(roll_status, time_now); _roll_failure_hysteresis.set_state_and_update(roll_status, time_now);
_pitch_failure_hysteresis.set_state_and_update(pitch_status, time_now); _pitch_failure_hysteresis.set_state_and_update(pitch_status, time_now);
@@ -132,3 +138,30 @@ FailureDetector::updateAttitudeStatus()
return updated; return updated;
} }
bool
FailureDetector::updateExternalAtsStatus()
{
pwm_input_s pwm_input;
bool updated = _sub_pwm_input.update(&pwm_input);
if (updated) {
uint32_t pulse_width = pwm_input.pulse_width;
bool ats_trigger_status = (pulse_width >= (uint32_t)_param_fd_ext_ats_trig.get()) && (pulse_width < 3_ms);
hrt_abstime time_now = hrt_absolute_time();
// Update hysteresis
_ext_ats_failure_hysteresis.set_hysteresis_time_from(false, 100_ms); // 5 consecutive pulses at 50hz
_ext_ats_failure_hysteresis.set_state_and_update(ats_trigger_status, time_now);
_status &= ~FAILURE_EXT;
if (_ext_ats_failure_hysteresis.get_state()) {
_status |= FAILURE_EXT;
}
}
return updated;
}
@@ -48,17 +48,20 @@
#include <px4_platform_common/module_params.h> #include <px4_platform_common/module_params.h>
#include <hysteresis/hysteresis.h> #include <hysteresis/hysteresis.h>
// subscriptions // subscriptions
#include <uORB/Subscription.hpp> #include <uORB/Subscription.hpp>
#include <uORB/topics/vehicle_attitude_setpoint.h> #include <uORB/topics/vehicle_attitude_setpoint.h>
#include <uORB/topics/vehicle_attitude.h> #include <uORB/topics/vehicle_attitude.h>
#include <uORB/topics/vehicle_status.h> #include <uORB/topics/vehicle_status.h>
#include <uORB/topics/pwm_input.h>
typedef enum { typedef enum {
FAILURE_NONE = vehicle_status_s::FAILURE_NONE, FAILURE_NONE = vehicle_status_s::FAILURE_NONE,
FAILURE_ROLL = vehicle_status_s::FAILURE_ROLL, FAILURE_ROLL = vehicle_status_s::FAILURE_ROLL,
FAILURE_PITCH = vehicle_status_s::FAILURE_PITCH, FAILURE_PITCH = vehicle_status_s::FAILURE_PITCH,
FAILURE_ALT = vehicle_status_s::FAILURE_ALT, FAILURE_ALT = vehicle_status_s::FAILURE_ALT,
FAILURE_EXT = vehicle_status_s::FAILURE_EXT,
} failure_detector_bitmak; } failure_detector_bitmak;
using uORB::SubscriptionData; using uORB::SubscriptionData;
@@ -79,18 +82,24 @@ private:
(ParamInt<px4::params::FD_FAIL_P>) _param_fd_fail_p, (ParamInt<px4::params::FD_FAIL_P>) _param_fd_fail_p,
(ParamInt<px4::params::FD_FAIL_R>) _param_fd_fail_r, (ParamInt<px4::params::FD_FAIL_R>) _param_fd_fail_r,
(ParamFloat<px4::params::FD_FAIL_R_TTRI>) _param_fd_fail_r_ttri, (ParamFloat<px4::params::FD_FAIL_R_TTRI>) _param_fd_fail_r_ttri,
(ParamFloat<px4::params::FD_FAIL_P_TTRI>) _param_fd_fail_p_ttri (ParamFloat<px4::params::FD_FAIL_P_TTRI>) _param_fd_fail_p_ttri,
(ParamBool<px4::params::FD_EXT_ATS_EN>) _param_fd_ext_ats_en,
(ParamInt<px4::params::FD_EXT_ATS_TRIG>) _param_fd_ext_ats_trig
) )
// Subscriptions // Subscriptions
uORB::Subscription _sub_vehicule_attitude{ORB_ID(vehicle_attitude)}; uORB::Subscription _sub_vehicule_attitude{ORB_ID(vehicle_attitude)};
uORB::Subscription _sub_pwm_input{ORB_ID(pwm_input)};
uint8_t _status{FAILURE_NONE}; uint8_t _status{FAILURE_NONE};
systemlib::Hysteresis _roll_failure_hysteresis{false}; systemlib::Hysteresis _roll_failure_hysteresis{false};
systemlib::Hysteresis _pitch_failure_hysteresis{false}; systemlib::Hysteresis _pitch_failure_hysteresis{false};
systemlib::Hysteresis _ext_ats_failure_hysteresis{false};
bool resetStatus(); bool resetStatus();
bool isAttitudeStabilized(const vehicle_status_s &vehicle_status); bool isAttitudeStabilized(const vehicle_status_s &vehicle_status);
bool updateAttitudeStatus(); bool updateAttitudeStatus();
bool updateExternalAtsStatus();
}; };
@@ -103,3 +103,27 @@ PARAM_DEFINE_FLOAT(FD_FAIL_R_TTRI, 0.3);
* @group Failure Detector * @group Failure Detector
*/ */
PARAM_DEFINE_FLOAT(FD_FAIL_P_TTRI, 0.3); PARAM_DEFINE_FLOAT(FD_FAIL_P_TTRI, 0.3);
/**
* Enable PWM input on AUX5 or MAIN5 (depending on board) for engaging failsafe from an external
* automatic trigger system (ATS).
*
* External ATS is required by ASTM F3322-18.
*
* @boolean
* @reboot_required true
* @group Failure Detector
*/
PARAM_DEFINE_INT32(FD_EXT_ATS_EN, 0);
/**
* The PWM threshold from external automatic trigger system for engaging failsafe.
*
* External ATS is required by ASTM F3322-18.
*
* @unit microseconds
* @decimal 2
*
* @group Failure Detector
*/
PARAM_DEFINE_INT32(FD_EXT_ATS_TRIG, 1900);