mirror of
https://gitee.com/mirrors_PX4/PX4-Autopilot.git
synced 2026-07-17 19:10:34 +08:00
Merge branch 'master' into st24
This commit is contained in:
@@ -4,3 +4,6 @@
|
||||
[submodule "NuttX"]
|
||||
path = NuttX
|
||||
url = git://github.com/PX4/NuttX.git
|
||||
[submodule "uavcan"]
|
||||
path = uavcan
|
||||
url = git://github.com/pavel-kirienko/uavcan.git
|
||||
|
||||
@@ -210,11 +210,14 @@ menuconfig:
|
||||
endif
|
||||
|
||||
$(NUTTX_SRC):
|
||||
$(Q) ($(PX4_BASE)/Tools/check_submodules.sh)
|
||||
|
||||
$(UAVCAN_DIR):
|
||||
$(Q) (./Tools/check_submodules.sh)
|
||||
|
||||
.PHONY: checksubmodules
|
||||
checksubmodules:
|
||||
$(Q) (./Tools/check_submodules.sh)
|
||||
$(Q) ($(PX4_BASE)/Tools/check_submodules.sh)
|
||||
|
||||
.PHONY: updatesubmodules
|
||||
updatesubmodules:
|
||||
|
||||
+1
-1
Submodule NuttX updated: 2a94cc8e5b...41fffa0df1
@@ -30,3 +30,6 @@ fi
|
||||
set MIXER FMU_quad_w
|
||||
|
||||
set PWM_OUTPUTS 1234
|
||||
|
||||
set PWM_MIN 1200
|
||||
set PWM_MAX 1950
|
||||
|
||||
@@ -26,15 +26,6 @@ then
|
||||
param set FW_RR_P 0.1
|
||||
param set FW_R_LIM 45
|
||||
param set FW_R_RMAX 0
|
||||
param set FW_T_CLMB_MAX 5
|
||||
param set FW_T_HRATE_P 0.02
|
||||
param set FW_T_PTCH_DAMP 0
|
||||
param set FW_T_RLL2THR 15
|
||||
param set FW_T_SINK_MAX 5
|
||||
param set FW_T_SINK_MIN 2
|
||||
param set FW_T_SRATE_P 0.01
|
||||
param set FW_T_TIME_CONST 3
|
||||
param set FW_T_VERT_ACC 7
|
||||
param set FW_YR_FF 0.0
|
||||
param set FW_YR_I 0
|
||||
param set FW_YR_IMAX 0.2
|
||||
|
||||
@@ -30,13 +30,12 @@ then
|
||||
param set FW_RR_P 0.08
|
||||
param set FW_R_LIM 50
|
||||
param set FW_R_RMAX 0
|
||||
param set FW_T_HRATE_P 0.01
|
||||
param set FW_T_RLL2THR 15
|
||||
param set FW_T_SRATE_P 0.01
|
||||
param set FW_T_TIME_CONST 5
|
||||
# Bottom of bay and nominal zero-pitch attitude differ
|
||||
# the payload bay is pitched up about 7 degrees
|
||||
param set SENS_BOARD_Y_OFF 7.0
|
||||
fi
|
||||
|
||||
set MIXER FMU_Q
|
||||
set MIXER phantom
|
||||
|
||||
# Provide ESC a constant 1000 us pulse
|
||||
set PWM_OUTPUTS 4
|
||||
|
||||
@@ -30,10 +30,6 @@ then
|
||||
param set FW_RR_P 0.03
|
||||
param set FW_R_LIM 60
|
||||
param set FW_R_RMAX 0
|
||||
param set FW_T_HRATE_P 0.01
|
||||
param set FW_T_RLL2THR 15
|
||||
param set FW_T_SRATE_P 0.01
|
||||
param set FW_T_TIME_CONST 5
|
||||
fi
|
||||
|
||||
set MIXER FMU_X5
|
||||
|
||||
@@ -11,28 +11,38 @@ if [ $DO_AUTOCONFIG == yes ]
|
||||
then
|
||||
param set BAT_N_CELLS 2
|
||||
param set FW_AIRSPD_MAX 15
|
||||
param set FW_AIRSPD_MIN 7
|
||||
param set FW_AIRSPD_TRIM 11
|
||||
param set FW_AIRSPD_MIN 10
|
||||
param set FW_AIRSPD_TRIM 13
|
||||
param set FW_ATT_TC 0.3
|
||||
param set FW_L1_DAMPING 0.74
|
||||
param set FW_L1_PERIOD 12
|
||||
param set FW_L1_PERIOD 16
|
||||
param set FW_LND_ANG 15
|
||||
param set FW_LND_FLALT 5
|
||||
param set FW_LND_HHDIST 15
|
||||
param set FW_LND_HVIRT 13
|
||||
param set FW_LND_TLALT 5
|
||||
param set FW_THR_LND_MAX 0
|
||||
param set FW_P_ROLLFF 2
|
||||
param set FW_PR_FF 0.6
|
||||
param set FW_PR_IMAX 0.2
|
||||
param set FW_PR_P 0.06
|
||||
param set FW_PR_FF 0.35
|
||||
param set FW_PR_I 0.005
|
||||
param set FW_PR_IMAX 0.4
|
||||
param set FW_PR_P 0.08
|
||||
param set FW_RR_FF 0.6
|
||||
param set FW_RR_I 0.005
|
||||
param set FW_RR_IMAX 0.2
|
||||
param set FW_RR_P 0.09
|
||||
param set FW_THR_CRUISE 0.65
|
||||
param set FW_RR_P 0.04
|
||||
param set MT_TKF_PIT_MAX 30.0
|
||||
param set MT_ACC_D 0.2
|
||||
param set MT_ACC_P 0.6
|
||||
param set MT_A_LP 0.5
|
||||
param set MT_PIT_OFF 0.1
|
||||
param set MT_PIT_I 0.1
|
||||
param set MT_THR_OFF 0.65
|
||||
param set MT_THR_I 0.35
|
||||
param set MT_THR_P 0.2
|
||||
param set MT_THR_FF 1.5
|
||||
fi
|
||||
|
||||
set MIXER FMU_Q
|
||||
set MIXER wingwing
|
||||
# Provide ESC a constant 1000 us pulse
|
||||
set PWM_OUTPUTS 4
|
||||
set PWM_DISARMED 1000
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
#!nsh
|
||||
#
|
||||
# Viper
|
||||
#
|
||||
# Simon Wilks <sjwilks@gmail.com>
|
||||
#
|
||||
|
||||
sh /etc/init.d/rc.fw_defaults
|
||||
|
||||
set MIXER Viper
|
||||
|
||||
set FAILSAFE "-c567 -p 1000"
|
||||
@@ -33,10 +33,6 @@ then
|
||||
param set FW_RR_P 0.03
|
||||
param set FW_R_LIM 60
|
||||
param set FW_R_RMAX 0
|
||||
param set FW_T_HRATE_P 0.01
|
||||
param set FW_T_RLL2THR 15
|
||||
param set FW_T_SRATE_P 0.01
|
||||
param set FW_T_TIME_CONST 5
|
||||
fi
|
||||
|
||||
set MIXER FMU_Q
|
||||
|
||||
@@ -23,5 +23,5 @@ then
|
||||
param set MC_YAWRATE_D 0.0
|
||||
fi
|
||||
|
||||
set PWM_MIN 1175
|
||||
set PWM_MAX 1900
|
||||
set PWM_MIN 1200
|
||||
set PWM_MAX 1950
|
||||
|
||||
@@ -24,5 +24,5 @@ then
|
||||
param set MC_YAWRATE_D 0.0
|
||||
fi
|
||||
|
||||
set PWM_MIN 1175
|
||||
set PWM_MAX 1900
|
||||
set PWM_MIN 1230
|
||||
set PWM_MAX 1950
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
#!nsh
|
||||
#
|
||||
# F450-sized quadrotor with CAN
|
||||
#
|
||||
# Lorenz Meier <lm@inf.ethz.ch>
|
||||
#
|
||||
|
||||
sh /etc/init.d/4001_quad_x
|
||||
|
||||
if [ $DO_AUTOCONFIG == yes ]
|
||||
then
|
||||
# TODO REVIEW
|
||||
param set MC_ROLL_P 7.0
|
||||
param set MC_ROLLRATE_P 0.1
|
||||
param set MC_ROLLRATE_I 0.0
|
||||
param set MC_ROLLRATE_D 0.003
|
||||
param set MC_PITCH_P 7.0
|
||||
param set MC_PITCHRATE_P 0.1
|
||||
param set MC_PITCHRATE_I 0.0
|
||||
param set MC_PITCHRATE_D 0.003
|
||||
param set MC_YAW_P 2.8
|
||||
param set MC_YAWRATE_P 0.2
|
||||
param set MC_YAWRATE_I 0.0
|
||||
param set MC_YAWRATE_D 0.0
|
||||
fi
|
||||
|
||||
set OUTPUT_MODE uavcan_esc
|
||||
@@ -103,6 +103,11 @@ then
|
||||
sh /etc/init.d/3034_fx79
|
||||
fi
|
||||
|
||||
if param compare SYS_AUTOSTART 3035 35
|
||||
then
|
||||
sh /etc/init.d/3035_viper
|
||||
fi
|
||||
|
||||
if param compare SYS_AUTOSTART 3100
|
||||
then
|
||||
sh /etc/init.d/3100_tbs_caipirinha
|
||||
@@ -136,6 +141,11 @@ then
|
||||
sh /etc/init.d/4011_dji_f450
|
||||
fi
|
||||
|
||||
if param compare SYS_AUTOSTART 4012
|
||||
then
|
||||
sh /etc/init.d/4012_quad_x_can
|
||||
fi
|
||||
|
||||
if param compare SYS_AUTOSTART 4020
|
||||
then
|
||||
sh /etc/init.d/4020_hk_micro_pcb
|
||||
|
||||
@@ -11,4 +11,8 @@ then
|
||||
param set NAV_RTL_ALT 100
|
||||
param set NAV_RTL_LAND_T -1
|
||||
param set NAV_ACCEPT_RAD 50
|
||||
param set FW_T_HRATE_P 0.01
|
||||
param set FW_T_RLL2THR 15
|
||||
param set FW_T_SRATE_P 0.01
|
||||
param set FW_T_TIME_CONST 5
|
||||
fi
|
||||
@@ -24,6 +24,11 @@ then
|
||||
else
|
||||
set OUTPUT_DEV /dev/pwm_output
|
||||
fi
|
||||
|
||||
if [ $OUTPUT_MODE == uavcan_esc ]
|
||||
then
|
||||
set OUTPUT_DEV /dev/uavcan/esc
|
||||
fi
|
||||
|
||||
if mixer load $OUTPUT_DEV $MIXER_FILE
|
||||
then
|
||||
@@ -72,4 +77,9 @@ then
|
||||
pwm max -c $PWM_OUTPUTS -p $PWM_MAX
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ $FAILSAFE != none ]
|
||||
then
|
||||
pwm failsafe -d $OUTPUT_DEV $FAILSAFE
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -6,27 +6,51 @@
|
||||
ms5611 start
|
||||
adc start
|
||||
|
||||
# Mag might be external
|
||||
if hmc5883 start
|
||||
if mpu6000 -X start
|
||||
then
|
||||
echo "[init] Using HMC5883"
|
||||
fi
|
||||
|
||||
if mpu6000 start
|
||||
then
|
||||
echo "[init] Using MPU6000"
|
||||
fi
|
||||
|
||||
if l3gd20 -X start
|
||||
then
|
||||
fi
|
||||
|
||||
if l3gd20 start
|
||||
then
|
||||
echo "[init] Using L3GD20(H)"
|
||||
fi
|
||||
|
||||
# MAG selection
|
||||
if param compare SENS_EXT_MAG 2
|
||||
then
|
||||
if hmc5883 -I start
|
||||
then
|
||||
fi
|
||||
else
|
||||
# Use only external as primary
|
||||
if param compare SENS_EXT_MAG 1
|
||||
then
|
||||
if hmc5883 -X start
|
||||
then
|
||||
fi
|
||||
else
|
||||
# auto-detect the primary, prefer external
|
||||
if hmc5883 start
|
||||
then
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if ver hwcmp PX4FMU_V2
|
||||
then
|
||||
if lsm303d -X start
|
||||
then
|
||||
fi
|
||||
|
||||
if lsm303d start
|
||||
then
|
||||
echo "[init] Using LSM303D"
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -37,11 +61,9 @@ then
|
||||
else
|
||||
if ets_airspeed start
|
||||
then
|
||||
echo "[init] Using ETS airspeed sensor (bus 3)"
|
||||
else
|
||||
if ets_airspeed start -b 1
|
||||
then
|
||||
echo "[init] Using ETS airspeed sensor (bus 1)"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
#!nsh
|
||||
#
|
||||
# UAVCAN initialization script.
|
||||
#
|
||||
|
||||
if param compare UAVCAN_ENABLE 1
|
||||
then
|
||||
if uavcan start
|
||||
then
|
||||
# First sensor publisher to initialize takes lowest instance ID
|
||||
# This delay ensures that UAVCAN-interfaced sensors would be allocated on lowest instance IDs
|
||||
sleep 1
|
||||
echo "[init] UAVCAN started"
|
||||
else
|
||||
echo "[init] ERROR: Could not start UAVCAN"
|
||||
tone_alarm $TUNE_OUT_ERROR
|
||||
fi
|
||||
fi
|
||||
@@ -3,8 +3,12 @@
|
||||
# USB MAVLink start
|
||||
#
|
||||
|
||||
mavlink start -r 10000 -d /dev/ttyACM0 -x
|
||||
mavlink start -r 20000 -d /dev/ttyACM0 -x
|
||||
# Enable a number of interesting streams we want via USB
|
||||
mavlink stream -d /dev/ttyACM0 -s PARAM_VALUE -r 200
|
||||
usleep 100000
|
||||
mavlink stream -d /dev/ttyACM0 -s MISSION_ITEM -r 50
|
||||
usleep 100000
|
||||
mavlink stream -d /dev/ttyACM0 -s NAMED_VALUE_FLOAT -r 10
|
||||
usleep 100000
|
||||
mavlink stream -d /dev/ttyACM0 -s OPTICAL_FLOW -r 10
|
||||
@@ -15,9 +19,11 @@ mavlink stream -d /dev/ttyACM0 -s ATTITUDE -r 20
|
||||
usleep 100000
|
||||
mavlink stream -d /dev/ttyACM0 -s ATTITUDE_CONTROLS -r 30
|
||||
usleep 100000
|
||||
mavlink stream -d /dev/ttyACM0 -s RC_CHANNELS_RAW -r 5
|
||||
usleep 100000
|
||||
mavlink stream -d /dev/ttyACM0 -s SERVO_OUTPUT_RAW_0 -r 20
|
||||
usleep 100000
|
||||
mavlink stream -d /dev/ttyACM0 -s GLOBAL_POSITION_SETPOINT_INT -r 20
|
||||
mavlink stream -d /dev/ttyACM0 -s POSITION_TARGET_GLOBAL_INT -r 10
|
||||
usleep 100000
|
||||
|
||||
# Exit shell to make it available to MAVLink
|
||||
|
||||
@@ -66,6 +66,9 @@ then
|
||||
#
|
||||
sercon
|
||||
|
||||
# Try to get an USB console
|
||||
nshterm /dev/ttyACM0 &
|
||||
|
||||
#
|
||||
# Start the ORB (first app to start)
|
||||
#
|
||||
@@ -83,9 +86,12 @@ then
|
||||
param select $PARAM_FILE
|
||||
if param load
|
||||
then
|
||||
echo "[init] Params loaded: $PARAM_FILE"
|
||||
echo "[param] Loaded: $PARAM_FILE"
|
||||
else
|
||||
echo "[init] ERROR: Params loading failed: $PARAM_FILE"
|
||||
echo "[param] FAILED loading $PARAM_FILE"
|
||||
if param reset
|
||||
then
|
||||
fi
|
||||
fi
|
||||
|
||||
#
|
||||
@@ -93,11 +99,9 @@ then
|
||||
#
|
||||
if rgbled start
|
||||
then
|
||||
echo "[init] RGB Led"
|
||||
else
|
||||
if blinkm start
|
||||
then
|
||||
echo "[init] BlinkM"
|
||||
blinkm systemstate
|
||||
fi
|
||||
fi
|
||||
@@ -126,6 +130,7 @@ then
|
||||
set LOAD_DEFAULT_APPS yes
|
||||
set GPS yes
|
||||
set GPS_FAKE no
|
||||
set FAILSAFE none
|
||||
|
||||
#
|
||||
# Set DO_AUTOCONFIG flag to use it in AUTOSTART scripts
|
||||
@@ -276,8 +281,12 @@ then
|
||||
fi
|
||||
fi
|
||||
|
||||
# Try to get an USB console
|
||||
nshterm /dev/ttyACM0 &
|
||||
#
|
||||
# Start the datamanager (and do not abort boot if it fails)
|
||||
#
|
||||
if dataman start
|
||||
then
|
||||
fi
|
||||
|
||||
#
|
||||
# Start the Commander (needs to be this early for in-air-restarts)
|
||||
@@ -292,7 +301,16 @@ then
|
||||
# If OUTPUT_MODE == none then something is wrong with setup and we shouldn't try to enable output
|
||||
if [ $OUTPUT_MODE != none ]
|
||||
then
|
||||
if [ $OUTPUT_MODE == io ]
|
||||
if [ $OUTPUT_MODE == uavcan_esc ]
|
||||
then
|
||||
if param compare UAVCAN_ENABLE 0
|
||||
then
|
||||
echo "[init] OVERRIDING UAVCAN_ENABLE = 1"
|
||||
param set UAVCAN_ENABLE 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ $OUTPUT_MODE == io -o $OUTPUT_MODE == uavcan_esc ]
|
||||
then
|
||||
echo "[init] Use PX4IO PWM as primary output"
|
||||
if px4io start
|
||||
@@ -427,6 +445,11 @@ then
|
||||
|
||||
mavlink start $MAVLINK_FLAGS
|
||||
|
||||
#
|
||||
# UAVCAN
|
||||
#
|
||||
sh /etc/init.d/rc.uavcan
|
||||
|
||||
#
|
||||
# Sensors, Logging, GPS
|
||||
#
|
||||
@@ -547,11 +570,6 @@ then
|
||||
fi
|
||||
fi
|
||||
|
||||
#
|
||||
# Start the datamanager
|
||||
#
|
||||
dataman start
|
||||
|
||||
#
|
||||
# Start the navigator
|
||||
#
|
||||
|
||||
@@ -64,21 +64,22 @@ O: 10000 10000 0 -10000 10000
|
||||
S: 0 3 0 20000 -10000 -10000 10000
|
||||
|
||||
|
||||
Gimbal / flaps / payload mixer for last four channels
|
||||
Gimbal / flaps / payload mixer for last four channels,
|
||||
using the payload control group
|
||||
-----------------------------------------------------
|
||||
|
||||
M: 1
|
||||
O: 10000 10000 0 -10000 10000
|
||||
S: 0 4 10000 10000 0 -10000 10000
|
||||
S: 2 0 10000 10000 0 -10000 10000
|
||||
|
||||
M: 1
|
||||
O: 10000 10000 0 -10000 10000
|
||||
S: 0 5 10000 10000 0 -10000 10000
|
||||
S: 2 1 10000 10000 0 -10000 10000
|
||||
|
||||
M: 1
|
||||
O: 10000 10000 0 -10000 10000
|
||||
S: 0 6 10000 10000 0 -10000 10000
|
||||
S: 2 2 10000 10000 0 -10000 10000
|
||||
|
||||
M: 1
|
||||
O: 10000 10000 0 -10000 10000
|
||||
S: 0 7 10000 10000 0 -10000 10000
|
||||
S: 2 3 10000 10000 0 -10000 10000
|
||||
|
||||
@@ -27,12 +27,12 @@ for the elevons.
|
||||
|
||||
M: 2
|
||||
O: 10000 10000 0 -10000 10000
|
||||
S: 0 0 5000 8000 0 -10000 10000
|
||||
S: 0 0 7500 7500 0 -10000 10000
|
||||
S: 0 1 8000 8000 0 -10000 10000
|
||||
|
||||
M: 2
|
||||
O: 10000 10000 0 -10000 10000
|
||||
S: 0 0 8000 5000 0 -10000 10000
|
||||
S: 0 0 7500 7500 0 -10000 10000
|
||||
S: 0 1 -8000 -8000 0 -10000 10000
|
||||
|
||||
Output 2
|
||||
|
||||
Executable
+71
@@ -0,0 +1,71 @@
|
||||
Viper Delta-wing mixer
|
||||
=================================
|
||||
|
||||
Designed for Viper.
|
||||
|
||||
TODO (sjwilks): Add mixers for flaps.
|
||||
|
||||
This file defines mixers suitable for controlling a delta wing aircraft using
|
||||
PX4FMU. The configuration assumes the elevon servos are connected to PX4FMU
|
||||
servo outputs 0 and 1 and the motor speed control to output 3. Output 2 is
|
||||
assumed to be unused.
|
||||
|
||||
Inputs to the mixer come from channel group 0 (vehicle attitude), channels 0
|
||||
(roll), 1 (pitch) and 3 (thrust).
|
||||
|
||||
See the README for more information on the scaler format.
|
||||
|
||||
Elevon mixers
|
||||
-------------
|
||||
Three scalers total (output, roll, pitch).
|
||||
|
||||
On the assumption that the two elevon servos are physically reversed, the pitch
|
||||
input is inverted between the two servos.
|
||||
|
||||
The scaling factor for roll inputs is adjusted to implement differential travel
|
||||
for the elevons.
|
||||
|
||||
M: 2
|
||||
O: 10000 10000 0 -10000 10000
|
||||
S: 0 0 7500 7500 0 -10000 10000
|
||||
S: 0 1 8000 8000 0 -10000 10000
|
||||
|
||||
M: 2
|
||||
O: 10000 10000 0 -10000 10000
|
||||
S: 0 0 7500 7500 0 -10000 10000
|
||||
S: 0 1 -8000 -8000 0 -10000 10000
|
||||
|
||||
Output 2
|
||||
--------
|
||||
This mixer is empty.
|
||||
|
||||
Z:
|
||||
|
||||
Motor speed mixer
|
||||
-----------------
|
||||
Two scalers total (output, thrust).
|
||||
|
||||
This mixer generates a full-range output (-1 to 1) from an input in the (0 - 1)
|
||||
range. Inputs below zero are treated as zero.
|
||||
|
||||
M: 1
|
||||
O: 10000 10000 0 -10000 10000
|
||||
S: 0 3 0 20000 -10000 -10000 10000
|
||||
|
||||
Inputs to the mixer come from channel group 2 (payload), channels 0
|
||||
(bay servo 1), 1 (bay servo 2) and 3 (drop release).
|
||||
-----------------------------------------------------
|
||||
|
||||
M: 1
|
||||
O: 10000 10000 0 -10000 10000
|
||||
S: 2 0 10000 10000 0 -10000 10000
|
||||
|
||||
M: 1
|
||||
O: 10000 10000 0 -10000 10000
|
||||
S: 2 1 10000 10000 0 -10000 10000
|
||||
|
||||
M: 1
|
||||
O: 10000 10000 0 -10000 10000
|
||||
S: 2 2 -10000 -10000 0 -10000 10000
|
||||
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
Phantom FX-61 mixer
|
||||
===================
|
||||
|
||||
This file defines mixers suitable for controlling a delta wing aircraft using
|
||||
PX4/Pixhawk. The configuration assumes the elevon servos are connected to
|
||||
servo outputs 0 and 1 and the motor speed control to output 3. Output 2 is
|
||||
assumed to be unused.
|
||||
|
||||
Inputs to the mixer come from channel group 0 (vehicle attitude), channels 0
|
||||
(roll), 1 (pitch) and 3 (thrust).
|
||||
|
||||
See the README for more information on the scaler format.
|
||||
|
||||
Elevon mixers
|
||||
-------------
|
||||
Three scalers total (output, roll, pitch).
|
||||
|
||||
On the assumption that the two elevon servos are physically reversed, the pitch
|
||||
input is inverted between the two servos.
|
||||
|
||||
The scaling factor are set so that pitch will have more travel than roll.
|
||||
|
||||
M: 2
|
||||
O: 10000 10000 0 -10000 10000
|
||||
S: 0 0 -6000 -6000 0 -10000 10000
|
||||
S: 0 1 6500 6500 0 -10000 10000
|
||||
|
||||
M: 2
|
||||
O: 10000 10000 0 -10000 10000
|
||||
S: 0 0 -6000 -6000 0 -10000 10000
|
||||
S: 0 1 -6500 -6500 0 -10000 10000
|
||||
|
||||
Output 2
|
||||
--------
|
||||
This mixer is empty.
|
||||
|
||||
Z:
|
||||
|
||||
Motor speed mixer
|
||||
-----------------
|
||||
Two scalers total (output, thrust).
|
||||
|
||||
This mixer generates a full-range output (-1 to 1) from an input in the (0 - 1)
|
||||
range. Inputs below zero are treated as zero.
|
||||
|
||||
M: 1
|
||||
O: 10000 10000 0 -10000 10000
|
||||
S: 0 3 0 20000 -10000 -10000 10000
|
||||
|
||||
Gimbal / flaps / payload mixer for last four channels
|
||||
-----------------------------------------------------
|
||||
|
||||
M: 1
|
||||
O: 10000 10000 0 -10000 10000
|
||||
S: 0 4 10000 10000 0 -10000 10000
|
||||
|
||||
M: 1
|
||||
O: 10000 10000 0 -10000 10000
|
||||
S: 0 5 10000 10000 0 -10000 10000
|
||||
|
||||
M: 1
|
||||
O: 10000 10000 0 -10000 10000
|
||||
S: 0 6 10000 10000 0 -10000 10000
|
||||
|
||||
M: 1
|
||||
O: 10000 10000 0 -10000 10000
|
||||
S: 0 7 10000 10000 0 -10000 10000
|
||||
@@ -0,0 +1,51 @@
|
||||
Delta-wing mixer for PX4FMU
|
||||
===========================
|
||||
|
||||
Designed for Wing Wing Z-84
|
||||
|
||||
This file defines mixers suitable for controlling a delta wing aircraft using
|
||||
PX4FMU. The configuration assumes the elevon servos are connected to PX4FMU
|
||||
servo outputs 0 and 1 and the motor speed control to output 3. Output 2 is
|
||||
assumed to be unused.
|
||||
|
||||
Inputs to the mixer come from channel group 0 (vehicle attitude), channels 0
|
||||
(roll), 1 (pitch) and 3 (thrust).
|
||||
|
||||
See the README for more information on the scaler format.
|
||||
|
||||
Elevon mixers
|
||||
-------------
|
||||
Three scalers total (output, roll, pitch).
|
||||
|
||||
On the assumption that the two elevon servos are physically reversed, the pitch
|
||||
input is inverted between the two servos.
|
||||
|
||||
The scaling factor for roll inputs is adjusted to implement differential travel
|
||||
for the elevons.
|
||||
|
||||
M: 2
|
||||
O: 10000 10000 0 -10000 10000
|
||||
S: 0 0 -6000 -6000 0 -10000 10000
|
||||
S: 0 1 6500 6500 0 -10000 10000
|
||||
|
||||
M: 2
|
||||
O: 10000 10000 0 -10000 10000
|
||||
S: 0 0 -6000 -6000 0 -10000 10000
|
||||
S: 0 1 -6500 -6500 0 -10000 10000
|
||||
|
||||
Output 2
|
||||
--------
|
||||
This mixer is empty.
|
||||
|
||||
Z:
|
||||
|
||||
Motor speed mixer
|
||||
-----------------
|
||||
Two scalers total (output, thrust).
|
||||
|
||||
This mixer generates a full-range output (-1 to 1) from an input in the (0 - 1)
|
||||
range. Inputs below zero are treated as zero.
|
||||
|
||||
M: 1
|
||||
O: 10000 10000 0 -10000 10000
|
||||
S: 0 3 0 20000 -10000 -10000 10000
|
||||
@@ -1,13 +1,28 @@
|
||||
#!/bin/sh
|
||||
|
||||
[ -n "$GIT_SUBMODULES_ARE_EVIL" ] && {
|
||||
# GIT_SUBMODULES_ARE_EVIL is set, meaning user doesn't want submodules
|
||||
echo "Skipping submodules. NUTTX_SRC is set to $NUTTX_SRC"
|
||||
exit 0
|
||||
}
|
||||
|
||||
if [ -d NuttX/nuttx ];
|
||||
then
|
||||
STATUSRETVAL=$(git status --porcelain | grep -i "NuttX")
|
||||
STATUSRETVAL=$(git submodule summary | grep -A20 -i "NuttX" | grep "<")
|
||||
if [ -z "$STATUSRETVAL" ]; then
|
||||
echo "Checked NuttX submodule, correct version found"
|
||||
else
|
||||
echo "NuttX sub repo not at correct version. Try 'make updatesubmodules'"
|
||||
echo "or follow instructions on http://pixhawk.org/dev/git/submodules"
|
||||
echo ""
|
||||
echo ""
|
||||
echo " NuttX sub repo not at correct version. Try 'git submodule update'"
|
||||
echo " or follow instructions on http://pixhawk.org/dev/git/submodules"
|
||||
echo ""
|
||||
echo " DO NOT FORGET TO RUN 'make distclean && make archives' AFTER EACH NUTTX UPDATE!"
|
||||
echo ""
|
||||
echo ""
|
||||
echo "New commits required:"
|
||||
echo "$(git submodule summary)"
|
||||
echo ""
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
@@ -18,12 +33,43 @@ fi
|
||||
|
||||
if [ -d mavlink/include/mavlink/v1.0 ];
|
||||
then
|
||||
STATUSRETVAL=$(git status --porcelain | grep -i "mavlink/include/mavlink/v1.0")
|
||||
STATUSRETVAL=$(git submodule summary | grep -A20 -i "mavlink/include/mavlink/v1.0" | grep "<")
|
||||
if [ -z "$STATUSRETVAL" ]; then
|
||||
echo "Checked mavlink submodule, correct version found"
|
||||
else
|
||||
echo "mavlink sub repo not at correct version. Try 'make updatesubmodules'"
|
||||
echo ""
|
||||
echo ""
|
||||
echo "mavlink sub repo not at correct version. Try 'git submodule update'"
|
||||
echo "or follow instructions on http://pixhawk.org/dev/git/submodules"
|
||||
echo ""
|
||||
echo ""
|
||||
echo "New commits required:"
|
||||
echo "$(git submodule summary)"
|
||||
echo ""
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
git submodule init;
|
||||
git submodule update;
|
||||
fi
|
||||
|
||||
|
||||
if [ -d uavcan ]
|
||||
then
|
||||
STATUSRETVAL=$(git submodule summary | grep -A20 -i uavcan | grep "<")
|
||||
if [ -z "$STATUSRETVAL" ]
|
||||
then
|
||||
echo "Checked uavcan submodule, correct version found"
|
||||
else
|
||||
echo ""
|
||||
echo ""
|
||||
echo "uavcan sub repo not at correct version. Try 'git submodule update'"
|
||||
echo "or follow instructions on http://pixhawk.org/dev/git/submodules"
|
||||
echo ""
|
||||
echo ""
|
||||
echo "New commits required:"
|
||||
echo "$(git submodule summary)"
|
||||
echo ""
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
|
||||
@@ -0,0 +1,207 @@
|
||||
#!/usr/bin/env python
|
||||
############################################################################
|
||||
#
|
||||
# Copyright (C) 2013-2014 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.
|
||||
#
|
||||
############################################################################
|
||||
|
||||
"""Fetch files via nsh console
|
||||
|
||||
Usage: python fetch_file.py [-l] [-f] [-d device] [-s speed] [-o out_path] path
|
||||
\t-l\tList files
|
||||
\t-f\tOverwrite existing files
|
||||
\t-d\tSerial device
|
||||
\t-s\tSerial baudrate
|
||||
\t-o\tOutput path
|
||||
\tpath\tPath to list/fetch, if ends with "/" then directory will be fetched recursively"""
|
||||
|
||||
__author__ = "Anton Babushkin"
|
||||
__version__ = "1.1"
|
||||
|
||||
import serial, time, sys, os
|
||||
|
||||
def _wait_for_string(ser, s, timeout):
|
||||
t0 = time.time()
|
||||
buf = []
|
||||
res = []
|
||||
while (True):
|
||||
c = ser.read()
|
||||
buf.append(c)
|
||||
if len(buf) > len(s):
|
||||
res.append(buf.pop(0))
|
||||
if "".join(buf) == s:
|
||||
break
|
||||
if timeout > 0.0 and time.time() - t0 > timeout:
|
||||
raise Exception("Timeout while waiting for: " + s)
|
||||
return "".join(res)
|
||||
|
||||
def _exec_cmd(ser, cmd, timeout):
|
||||
ser.write(cmd + "\n")
|
||||
ser.flush()
|
||||
_wait_for_string(ser, cmd + "\r\n", timeout)
|
||||
return _wait_for_string(ser, "nsh> \x1b[K", timeout)
|
||||
|
||||
def _ls_dir_raw(ser, dir, timeout):
|
||||
return _exec_cmd(ser, "ls -l " + dir, timeout)
|
||||
|
||||
def _ls_dir(ser, dir, timeout):
|
||||
res = []
|
||||
for line in _ls_dir_raw(ser, dir, timeout).splitlines():
|
||||
if line == dir + ":":
|
||||
continue
|
||||
if line.startswith("nsh: ls: no such directory:"):
|
||||
raise Exception("No such file: " + dir)
|
||||
res.append((line[20:], int(line[11:19].strip()), line[1] == "d"))
|
||||
return res
|
||||
|
||||
def _get_file(ser, fn, fn_out, force, timeout):
|
||||
print "Get %s:" % fn,
|
||||
if not force:
|
||||
# Check if file already exists with the same size
|
||||
try:
|
||||
os.stat(fn_out)
|
||||
except:
|
||||
pass
|
||||
else:
|
||||
print "already fetched, skip"
|
||||
return
|
||||
|
||||
cmd = "dumpfile " + fn
|
||||
ser.write(cmd + "\n")
|
||||
ser.flush()
|
||||
_wait_for_string(ser, cmd + "\r\n", timeout)
|
||||
res = _wait_for_string(ser, "\n", timeout)
|
||||
if res.startswith("OK"):
|
||||
# Got correct responce, open temp file
|
||||
fn_out_part = fn_out + ".part"
|
||||
fout = open(fn_out_part, "wb")
|
||||
|
||||
size = int(res.split()[1])
|
||||
sys.stdout.write(" [%i bytes] " % size)
|
||||
n = 0
|
||||
while (n < size):
|
||||
buf = ser.read(min(size - n, 8192))
|
||||
n += len(buf)
|
||||
sys.stdout.write(".")
|
||||
sys.stdout.flush()
|
||||
fout.write(buf)
|
||||
print " done"
|
||||
fout.close()
|
||||
os.rename(fn_out_part, fn_out)
|
||||
else:
|
||||
raise Exception("Error reading file")
|
||||
_wait_for_string(ser, "nsh> \x1b[K", timeout)
|
||||
|
||||
def _get_files_in_dir(ser, path, path_out, force, timeout):
|
||||
try:
|
||||
os.mkdir(path_out)
|
||||
except:
|
||||
pass
|
||||
for fn in _ls_dir(ser, path, timeout):
|
||||
path_fn = os.path.join(path, fn[0])
|
||||
path_fn_out = os.path.join(path_out, fn[0])
|
||||
if fn[2]:
|
||||
_get_files_in_dir(ser, path_fn[:-1], path_fn_out[:-1], force, timeout)
|
||||
else:
|
||||
_get_file(ser, path_fn, path_fn_out, force, timeout)
|
||||
|
||||
def _usage():
|
||||
print """Usage: python fetch_file.py [-l] [-f] [-d device] [-s speed] [-o out_path] path
|
||||
\t-l\tList files
|
||||
\t-f\tOverwrite existing files
|
||||
\t-d\tSerial device
|
||||
\t-s\tSerial baudrate
|
||||
\t-o\tOutput path
|
||||
\tpath\tPath to list/fetch, if ends with "/" then directory will be fetched recursively"""
|
||||
|
||||
def _main():
|
||||
dev = "/dev/tty.usbmodem1"
|
||||
speed = "57600"
|
||||
cmd = "get"
|
||||
path = None
|
||||
path_out = None
|
||||
force = False
|
||||
|
||||
opt = None
|
||||
for arg in sys.argv[1:]:
|
||||
if opt != None:
|
||||
if opt == "d":
|
||||
dev = arg
|
||||
elif opt == "s":
|
||||
speed = arg
|
||||
elif opt == "o":
|
||||
path_out = arg
|
||||
opt = None
|
||||
else:
|
||||
if arg == "-l":
|
||||
cmd = "ls"
|
||||
elif arg == "-f":
|
||||
force = True
|
||||
elif arg == "-d":
|
||||
opt = "d"
|
||||
elif arg == "-s":
|
||||
opt = "s"
|
||||
elif arg == "-o":
|
||||
opt = "o"
|
||||
elif path == None:
|
||||
path = arg
|
||||
|
||||
if path == None:
|
||||
_usage()
|
||||
exit(0)
|
||||
|
||||
# Connect to serial port
|
||||
ser = serial.Serial(dev, speed, timeout=0.2)
|
||||
|
||||
timeout = 1.0
|
||||
|
||||
try:
|
||||
if cmd == "ls":
|
||||
# List directory
|
||||
print _ls_dir_raw(ser, path, timeout)
|
||||
elif cmd == "get":
|
||||
# Get file(s)
|
||||
if path.endswith("/"):
|
||||
# Get all files from directory recursively
|
||||
if path_out == None:
|
||||
path_out = os.path.split(path[:-1])[1]
|
||||
_get_files_in_dir(ser, path[:-1], path_out, force, timeout)
|
||||
else:
|
||||
# Get one file
|
||||
if path_out == None:
|
||||
path_out = os.path.split(path)[1]
|
||||
_get_file(ser, path, os.path.split(path)[1], force, timeout)
|
||||
except Exception as e:
|
||||
print e
|
||||
|
||||
ser.close()
|
||||
|
||||
if __name__ == "__main__":
|
||||
_main()
|
||||
@@ -1,133 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
############################################################################
|
||||
#
|
||||
# Copyright (C) 2012, 2013 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.
|
||||
#
|
||||
############################################################################
|
||||
|
||||
#
|
||||
# Log fetcher
|
||||
#
|
||||
# Print list of logs:
|
||||
# python fetch_log.py
|
||||
#
|
||||
# Fetch log:
|
||||
# python fetch_log.py sess001/log001.bin
|
||||
#
|
||||
|
||||
import serial, time, sys, os
|
||||
|
||||
def wait_for_string(ser, s, timeout=1.0, debug=False):
|
||||
t0 = time.time()
|
||||
buf = []
|
||||
res = []
|
||||
n = 0
|
||||
while (True):
|
||||
c = ser.read()
|
||||
if debug:
|
||||
sys.stderr.write(c)
|
||||
buf.append(c)
|
||||
if len(buf) > len(s):
|
||||
res.append(buf.pop(0))
|
||||
n += 1
|
||||
if n % 10000 == 0:
|
||||
sys.stderr.write(str(n) + "\n")
|
||||
if "".join(buf) == s:
|
||||
break
|
||||
if timeout > 0.0 and time.time() - t0 > timeout:
|
||||
raise Exception("Timeout while waiting for: " + s)
|
||||
return "".join(res)
|
||||
|
||||
def exec_cmd(ser, cmd, timeout):
|
||||
ser.write(cmd + "\n")
|
||||
ser.flush()
|
||||
wait_for_string(ser, cmd + "\r\n", timeout)
|
||||
return wait_for_string(ser, "nsh> \x1b[K", timeout)
|
||||
|
||||
def ls_dir(ser, dir, timeout=1.0):
|
||||
res = []
|
||||
for line in exec_cmd(ser, "ls -l " + dir, timeout).splitlines()[1:]:
|
||||
res.append((line[20:], int(line[11:19].strip()), line[1] == "d"))
|
||||
return res
|
||||
|
||||
def list_logs(ser):
|
||||
logs_dir = "/fs/microsd/log"
|
||||
res = []
|
||||
for d in ls_dir(ser, logs_dir):
|
||||
if d[2]:
|
||||
sess_dir = d[0][:-1]
|
||||
for f in ls_dir(ser, logs_dir + "/" + sess_dir):
|
||||
log_file = f[0]
|
||||
log_size = f[1]
|
||||
res.append(sess_dir + "/" + log_file + "\t" + str(log_size))
|
||||
return "\n".join(res)
|
||||
|
||||
def fetch_log(ser, fn, timeout):
|
||||
cmd = "dumpfile " + fn
|
||||
ser.write(cmd + "\n")
|
||||
ser.flush()
|
||||
wait_for_string(ser, cmd + "\r\n", timeout, True)
|
||||
res = wait_for_string(ser, "\n", timeout, True)
|
||||
data = []
|
||||
if res.startswith("OK"):
|
||||
size = int(res.split()[1])
|
||||
n = 0
|
||||
print "Reading data:"
|
||||
while (n < size):
|
||||
buf = ser.read(min(size - n, 8192))
|
||||
data.append(buf)
|
||||
n += len(buf)
|
||||
sys.stdout.write(".")
|
||||
sys.stdout.flush()
|
||||
print
|
||||
else:
|
||||
raise Exception("Error reading log")
|
||||
wait_for_string(ser, "nsh> \x1b[K", timeout)
|
||||
return "".join(data)
|
||||
|
||||
def main():
|
||||
dev = "/dev/tty.usbmodem1"
|
||||
ser = serial.Serial(dev, "115200", timeout=0.2)
|
||||
if len(sys.argv) < 2:
|
||||
print list_logs(ser)
|
||||
else:
|
||||
log_file = sys.argv[1]
|
||||
data = fetch_log(ser, "/fs/microsd/log/" + log_file, 1.0)
|
||||
try:
|
||||
os.mkdir(log_file.split("/")[0])
|
||||
except:
|
||||
pass
|
||||
fout = open(log_file, "wb")
|
||||
fout.write(data)
|
||||
fout.close()
|
||||
ser.close()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
+10
-3
@@ -63,6 +63,7 @@ import zlib
|
||||
import base64
|
||||
import time
|
||||
import array
|
||||
import os
|
||||
|
||||
from sys import platform as _platform
|
||||
|
||||
@@ -177,9 +178,9 @@ class uploader(object):
|
||||
MAVLINK_REBOOT_ID1 = bytearray(b'\xfe\x21\x72\xff\x00\x4c\x00\x00\x80\x3f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf6\x00\x01\x00\x00\x48\xf0')
|
||||
MAVLINK_REBOOT_ID0 = bytearray(b'\xfe\x21\x45\xff\x00\x4c\x00\x00\x80\x3f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf6\x00\x00\x00\x00\xd7\xac')
|
||||
|
||||
def __init__(self, portname, baudrate):
|
||||
def __init__(self, portname, baudrate, interCharTimeout=0.001, timeout=0.5):
|
||||
# open the port, keep the default timeout short so we can poll quickly
|
||||
self.port = serial.Serial(portname, baudrate, timeout=0.5)
|
||||
self.port = serial.Serial(portname, baudrate)
|
||||
self.otp = b''
|
||||
self.sn = b''
|
||||
|
||||
@@ -194,7 +195,7 @@ class uploader(object):
|
||||
def __recv(self, count=1):
|
||||
c = self.port.read(count)
|
||||
if len(c) < 1:
|
||||
raise RuntimeError("timeout waiting for data")
|
||||
raise RuntimeError("timeout waiting for data (%u bytes)", count)
|
||||
# print("recv " + binascii.hexlify(c))
|
||||
return c
|
||||
|
||||
@@ -449,6 +450,12 @@ parser.add_argument('--baud', action="store", type=int, default=115200, help="Ba
|
||||
parser.add_argument('firmware', action="store", help="Firmware file to be uploaded")
|
||||
args = parser.parse_args()
|
||||
|
||||
# warn people about ModemManager which interferes badly with Pixhawk
|
||||
if os.path.exists("/usr/sbin/ModemManager"):
|
||||
print("==========================================================================================================")
|
||||
print("WARNING: You should uninstall ModemManager as it conflicts with any non-modem serial device (like Pixhawk)")
|
||||
print("==========================================================================================================")
|
||||
|
||||
# Load the firmware file
|
||||
fw = firmware(args.firmware)
|
||||
print("Loaded firmware for %x,%x, waiting for the bootloader..." % (fw.property('board_id'), fw.property('board_revision')))
|
||||
|
||||
@@ -149,7 +149,8 @@ class SDLog2Parser:
|
||||
break
|
||||
if first_data_msg:
|
||||
# build CSV columns and init data map
|
||||
self.__initCSV()
|
||||
if not self.__debug_out:
|
||||
self.__initCSV()
|
||||
first_data_msg = False
|
||||
self.__parseMsg(msg_descr)
|
||||
bytes_read += self.__ptr
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
close all;
|
||||
clear all;
|
||||
M = importdata('px4io_v1.3.csv');
|
||||
voltage = M.data(:, 1);
|
||||
counts = M.data(:, 2);
|
||||
plot(counts, voltage, 'b*-', 'LineWidth', 2, 'MarkerSize', 15);
|
||||
coeffs = polyfit(counts, voltage, 1);
|
||||
fittedC = linspace(min(counts), max(counts), 500);
|
||||
fittedV = polyval(coeffs, fittedC);
|
||||
hold on
|
||||
plot(fittedC, fittedV, 'r-', 'LineWidth', 3);
|
||||
|
||||
slope = coeffs(1)
|
||||
y_intersection = coeffs(2)
|
||||
@@ -0,0 +1,70 @@
|
||||
voltage, counts
|
||||
4.3, 950
|
||||
4.4, 964
|
||||
4.5, 986
|
||||
4.6, 1009
|
||||
4.7, 1032
|
||||
4.8, 1055
|
||||
4.9, 1078
|
||||
5.0, 1101
|
||||
5.2, 1124
|
||||
5.3, 1148
|
||||
5.4, 1171
|
||||
5.5, 1195
|
||||
6.0, 1304
|
||||
6.1, 1329
|
||||
6.2, 1352
|
||||
7.0, 1517
|
||||
7.1, 1540
|
||||
7.2, 1564
|
||||
7.3, 1585
|
||||
7.4, 1610
|
||||
7.5, 1636
|
||||
8.0, 1728
|
||||
8.1, 1752
|
||||
8.2, 1755
|
||||
8.3, 1798
|
||||
8.4, 1821
|
||||
9.0, 1963
|
||||
9.1, 1987
|
||||
9.3, 2010
|
||||
9.4, 2033
|
||||
10.0, 2174
|
||||
10.1, 2198
|
||||
10.2, 2221
|
||||
10.3, 2245
|
||||
10.4, 2268
|
||||
11.0, 2385
|
||||
11.1, 2409
|
||||
11.2, 2432
|
||||
11.3, 2456
|
||||
11.4, 2480
|
||||
11.5, 2502
|
||||
11.6, 2526
|
||||
11.7, 2550
|
||||
11.8, 2573
|
||||
11.9, 2597
|
||||
12.0, 2621
|
||||
12.1, 2644
|
||||
12.3, 2668
|
||||
12.4, 2692
|
||||
12.5, 2716
|
||||
12.6, 2737
|
||||
12.7, 2761
|
||||
13.0, 2832
|
||||
13.5, 2950
|
||||
13.6, 2973
|
||||
14.1, 3068
|
||||
14.2, 3091
|
||||
14.7, 3209
|
||||
15.0, 3280
|
||||
15.1, 3304
|
||||
15.5, 3374
|
||||
15.6, 3397
|
||||
15.7, 3420
|
||||
16.0, 3492
|
||||
16.1, 3514
|
||||
16.2, 3538
|
||||
16.9, 3680
|
||||
17.0, 3704
|
||||
17.1, 3728
|
||||
|
@@ -80,6 +80,7 @@ LIBRARIES += lib/mathlib/CMSIS
|
||||
MODULES += lib/mathlib
|
||||
MODULES += lib/mathlib/math/filter
|
||||
MODULES += lib/ecl
|
||||
MODULES += lib/external_lgpl
|
||||
MODULES += lib/geo
|
||||
MODULES += lib/geo_lookup
|
||||
MODULES += lib/conversion
|
||||
|
||||
@@ -43,7 +43,6 @@ MODULES += modules/sensors
|
||||
#
|
||||
MODULES += systemcmds/mtd
|
||||
MODULES += systemcmds/bl_update
|
||||
MODULES += systemcmds/i2c
|
||||
MODULES += systemcmds/mixer
|
||||
MODULES += systemcmds/param
|
||||
MODULES += systemcmds/perf
|
||||
@@ -107,6 +106,7 @@ LIBRARIES += lib/mathlib/CMSIS
|
||||
MODULES += lib/mathlib
|
||||
MODULES += lib/mathlib/math/filter
|
||||
MODULES += lib/ecl
|
||||
MODULES += lib/external_lgpl
|
||||
MODULES += lib/geo
|
||||
MODULES += lib/geo_lookup
|
||||
MODULES += lib/conversion
|
||||
@@ -150,5 +150,4 @@ endef
|
||||
# command priority stack entrypoint
|
||||
BUILTIN_COMMANDS := \
|
||||
$(call _B, sercon, , 2048, sercon_main ) \
|
||||
$(call _B, serdis, , 2048, serdis_main ) \
|
||||
$(call _B, sysinfo, , 2048, sysinfo_main )
|
||||
$(call _B, serdis, , 2048, serdis_main )
|
||||
|
||||
@@ -28,6 +28,7 @@ MODULES += drivers/hmc5883
|
||||
MODULES += drivers/ms5611
|
||||
MODULES += drivers/mb12xx
|
||||
MODULES += drivers/sf0x
|
||||
MODULES += drivers/ll40ls
|
||||
MODULES += drivers/gps
|
||||
MODULES += drivers/hil
|
||||
MODULES += drivers/hott/hott_telemetry
|
||||
@@ -40,6 +41,7 @@ MODULES += drivers/frsky_telemetry
|
||||
MODULES += modules/sensors
|
||||
MODULES += drivers/mkblctrl
|
||||
MODULES += drivers/pca8574
|
||||
MODULES += drivers/px4flow
|
||||
|
||||
|
||||
# Needs to be burned to the ground and re-written; for now,
|
||||
@@ -73,6 +75,7 @@ MODULES += modules/commander
|
||||
MODULES += modules/navigator
|
||||
MODULES += modules/mavlink
|
||||
MODULES += modules/gpio_led
|
||||
MODULES += modules/uavcan
|
||||
|
||||
#
|
||||
# Estimation modules (EKF/ SO3 / other filters)
|
||||
@@ -119,6 +122,7 @@ LIBRARIES += lib/mathlib/CMSIS
|
||||
MODULES += lib/mathlib
|
||||
MODULES += lib/mathlib/math/filter
|
||||
MODULES += lib/ecl
|
||||
MODULES += lib/external_lgpl
|
||||
MODULES += lib/geo
|
||||
MODULES += lib/geo_lookup
|
||||
MODULES += lib/conversion
|
||||
|
||||
@@ -33,6 +33,11 @@ MODULES += systemcmds/nshterm
|
||||
MODULES += systemcmds/mtd
|
||||
MODULES += systemcmds/ver
|
||||
|
||||
#
|
||||
# Testing modules
|
||||
#
|
||||
MODULES += examples/matlab_csv_serial
|
||||
|
||||
#
|
||||
# Library modules
|
||||
#
|
||||
@@ -42,6 +47,7 @@ MODULES += modules/uORB
|
||||
LIBRARIES += lib/mathlib/CMSIS
|
||||
MODULES += lib/mathlib
|
||||
MODULES += lib/mathlib/math/filter
|
||||
MODULES += lib/conversion
|
||||
|
||||
#
|
||||
# Libraries
|
||||
|
||||
@@ -64,6 +64,7 @@ LDSCRIPT += $(NUTTX_EXPORT_DIR)build/ld.script
|
||||
# Add directories from the NuttX export to the relevant search paths
|
||||
#
|
||||
INCLUDE_DIRS += $(NUTTX_EXPORT_DIR)include \
|
||||
$(NUTTX_EXPORT_DIR)include/cxx \
|
||||
$(NUTTX_EXPORT_DIR)arch/chip \
|
||||
$(NUTTX_EXPORT_DIR)arch/common
|
||||
|
||||
|
||||
@@ -49,6 +49,7 @@ export NUTTX_SRC = $(abspath $(PX4_BASE)/NuttX/nuttx)/
|
||||
export MAVLINK_SRC = $(abspath $(PX4_BASE)/mavlink/include/mavlink/v1.0)/
|
||||
export NUTTX_APP_SRC = $(abspath $(PX4_BASE)/NuttX/apps)/
|
||||
export MAVLINK_SRC = $(abspath $(PX4_BASE)/mavlink)/
|
||||
export UAVCAN_DIR = $(abspath $(PX4_BASE)/uavcan)/
|
||||
export ROMFS_SRC = $(abspath $(PX4_BASE)/ROMFS)/
|
||||
export IMAGE_DIR = $(abspath $(PX4_BASE)/Images)/
|
||||
export BUILD_DIR = $(abspath $(PX4_BASE)/Build)/
|
||||
|
||||
@@ -121,7 +121,7 @@ INSTRUMENTATIONDEFINES = $(ARCHINSTRUMENTATIONDEFINES_$(CONFIG_ARCH))
|
||||
# Language-specific flags
|
||||
#
|
||||
ARCHCFLAGS = -std=gnu99
|
||||
ARCHCXXFLAGS = -fno-exceptions -fno-rtti -std=gnu++0x
|
||||
ARCHCXXFLAGS = -fno-exceptions -fno-rtti -std=gnu++0x -fno-threadsafe-statics
|
||||
|
||||
# Generic warnings
|
||||
#
|
||||
|
||||
Submodule mavlink/include/mavlink/v1.0 updated: d1ebe85eb6...2423e47b4f
@@ -314,7 +314,7 @@ CONFIG_STM32_I2CTIMEOTICKS=500
|
||||
# CONFIG_ARCH_NOINTC is not set
|
||||
# CONFIG_ARCH_VECNOTIRQ is not set
|
||||
CONFIG_ARCH_DMA=y
|
||||
CONFIG_ARCH_IRQPRIO=y
|
||||
# CONFIG_ARCH_IRQPRIO is not set
|
||||
# CONFIG_CUSTOM_STACK is not set
|
||||
# CONFIG_ADDRENV is not set
|
||||
CONFIG_ARCH_HAVE_VFORK=y
|
||||
|
||||
@@ -287,8 +287,7 @@ CONFIG_STM32_USART_SINGLEWIRE=y
|
||||
#
|
||||
# CONFIG_STM32_I2C_DYNTIMEO is not set
|
||||
CONFIG_STM32_I2CTIMEOSEC=0
|
||||
CONFIG_STM32_I2CTIMEOMS=10
|
||||
CONFIG_STM32_I2CTIMEOTICKS=500
|
||||
CONFIG_STM32_I2CTIMEOMS=1
|
||||
# CONFIG_STM32_I2C_DUTY16_9 is not set
|
||||
|
||||
#
|
||||
@@ -309,7 +308,7 @@ CONFIG_STM32_I2CTIMEOTICKS=500
|
||||
# CONFIG_ARCH_NOINTC is not set
|
||||
# CONFIG_ARCH_VECNOTIRQ is not set
|
||||
CONFIG_ARCH_DMA=y
|
||||
CONFIG_ARCH_IRQPRIO=y
|
||||
# CONFIG_ARCH_IRQPRIO is not set
|
||||
# CONFIG_CUSTOM_STACK is not set
|
||||
# CONFIG_ADDRENV is not set
|
||||
CONFIG_ARCH_HAVE_VFORK=y
|
||||
@@ -417,8 +416,8 @@ CONFIG_PREALLOC_TIMERS=50
|
||||
#
|
||||
# Stack and heap information
|
||||
#
|
||||
CONFIG_IDLETHREAD_STACKSIZE=4096
|
||||
CONFIG_USERMAIN_STACKSIZE=3500
|
||||
CONFIG_IDLETHREAD_STACKSIZE=3500
|
||||
CONFIG_USERMAIN_STACKSIZE=3000
|
||||
CONFIG_PTHREAD_STACK_MIN=512
|
||||
CONFIG_PTHREAD_STACK_DEFAULT=2048
|
||||
|
||||
@@ -679,7 +678,7 @@ CONFIG_BUILTIN=y
|
||||
#
|
||||
# Standard C Library Options
|
||||
#
|
||||
CONFIG_STDIO_BUFFER_SIZE=256
|
||||
CONFIG_STDIO_BUFFER_SIZE=180
|
||||
CONFIG_STDIO_LINEBUFFER=y
|
||||
CONFIG_NUNGET_CHARS=2
|
||||
CONFIG_LIB_HOMEDIR="/"
|
||||
|
||||
@@ -323,8 +323,7 @@ CONFIG_STM32_USART_SINGLEWIRE=y
|
||||
#
|
||||
# CONFIG_STM32_I2C_DYNTIMEO is not set
|
||||
CONFIG_STM32_I2CTIMEOSEC=0
|
||||
CONFIG_STM32_I2CTIMEOMS=10
|
||||
CONFIG_STM32_I2CTIMEOTICKS=500
|
||||
CONFIG_STM32_I2CTIMEOMS=1
|
||||
# CONFIG_STM32_I2C_DUTY16_9 is not set
|
||||
|
||||
#
|
||||
@@ -350,7 +349,7 @@ CONFIG_SDIO_PRI=128
|
||||
# CONFIG_ARCH_NOINTC is not set
|
||||
# CONFIG_ARCH_VECNOTIRQ is not set
|
||||
CONFIG_ARCH_DMA=y
|
||||
CONFIG_ARCH_IRQPRIO=y
|
||||
# CONFIG_ARCH_IRQPRIO is not set
|
||||
# CONFIG_CUSTOM_STACK is not set
|
||||
# CONFIG_ADDRENV is not set
|
||||
CONFIG_ARCH_HAVE_VFORK=y
|
||||
@@ -451,8 +450,8 @@ CONFIG_PREALLOC_TIMERS=50
|
||||
#
|
||||
# Stack and heap information
|
||||
#
|
||||
CONFIG_IDLETHREAD_STACKSIZE=6000
|
||||
CONFIG_USERMAIN_STACKSIZE=4096
|
||||
CONFIG_IDLETHREAD_STACKSIZE=3500
|
||||
CONFIG_USERMAIN_STACKSIZE=3000
|
||||
CONFIG_PTHREAD_STACK_MIN=512
|
||||
CONFIG_PTHREAD_STACK_DEFAULT=2048
|
||||
|
||||
|
||||
@@ -83,7 +83,6 @@ CONFIG_ARCH_BOARD="px4io-v1"
|
||||
CONFIG_BOARD_LOOPSPERMSEC=2000
|
||||
CONFIG_DRAM_SIZE=0x00002000
|
||||
CONFIG_DRAM_START=0x20000000
|
||||
CONFIG_ARCH_IRQPRIO=y
|
||||
CONFIG_ARCH_INTERRUPTSTACK=n
|
||||
CONFIG_ARCH_STACKDUMP=y
|
||||
CONFIG_ARCH_BOOTLOADER=n
|
||||
@@ -134,6 +133,8 @@ CONFIG_STM32_USART2=y
|
||||
CONFIG_STM32_USART3=y
|
||||
CONFIG_STM32_I2C1=y
|
||||
CONFIG_STM32_I2C2=n
|
||||
CONFIG_STM32_I2CTIMEOSEC=0
|
||||
CONFIG_STM32_I2CTIMEOMS=1
|
||||
CONFIG_STM32_BKP=n
|
||||
CONFIG_STM32_PWR=n
|
||||
CONFIG_STM32_DAC=n
|
||||
|
||||
@@ -79,7 +79,6 @@ CONFIG_ARCH_BOARD_PX4IO_V2=y
|
||||
CONFIG_BOARD_LOOPSPERMSEC=2000
|
||||
CONFIG_DRAM_SIZE=0x00002000
|
||||
CONFIG_DRAM_START=0x20000000
|
||||
CONFIG_ARCH_IRQPRIO=y
|
||||
CONFIG_ARCH_INTERRUPTSTACK=n
|
||||
CONFIG_ARCH_STACKDUMP=y
|
||||
CONFIG_ARCH_BOOTLOADER=n
|
||||
|
||||
@@ -165,7 +165,7 @@ Airspeed::probe()
|
||||
*/
|
||||
_retries = 4;
|
||||
int ret = measure();
|
||||
_retries = 2;
|
||||
_retries = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -381,7 +381,10 @@ Airspeed::cycle_trampoline(void *arg)
|
||||
Airspeed *dev = (Airspeed *)arg;
|
||||
|
||||
dev->cycle();
|
||||
dev->update_status();
|
||||
// XXX we do not know if this is
|
||||
// really helping - do not update the
|
||||
// subsys state right now
|
||||
//dev->update_status();
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -107,6 +107,10 @@ private:
|
||||
RingBuffer *_reports;
|
||||
perf_counter_t _buffer_overflows;
|
||||
|
||||
/* this class has pointer data members and should not be copied */
|
||||
Airspeed(const Airspeed&);
|
||||
Airspeed& operator=(const Airspeed&);
|
||||
|
||||
protected:
|
||||
virtual int probe();
|
||||
|
||||
|
||||
@@ -36,3 +36,5 @@
|
||||
#
|
||||
|
||||
SRCS = airspeed.cpp
|
||||
|
||||
MAXOPTIMIZATION = -Os
|
||||
|
||||
@@ -39,3 +39,5 @@ MODULE_COMMAND = ardrone_interface
|
||||
SRCS = ardrone_interface.c \
|
||||
ardrone_motor_control.c
|
||||
MODULE_STACKSIZE = 1200
|
||||
|
||||
MAXOPTIMIZATION = -Os
|
||||
|
||||
@@ -38,3 +38,5 @@
|
||||
MODULE_COMMAND = blinkm
|
||||
|
||||
SRCS = blinkm.cpp
|
||||
|
||||
MAXOPTIMIZATION = -Os
|
||||
|
||||
@@ -38,3 +38,5 @@
|
||||
MODULE_COMMAND = bma180
|
||||
|
||||
SRCS = bma180.cpp
|
||||
|
||||
MAXOPTIMIZATION = -Os
|
||||
|
||||
@@ -86,7 +86,6 @@ __BEGIN_DECLS
|
||||
#define GPIO_SPI_CS_SDCARD (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_SPEED_50MHz|GPIO_OUTPUT_SET|GPIO_PORTA|GPIO_PIN4)
|
||||
|
||||
#define PX4_SPI_BUS_SENSORS 1
|
||||
#define PX4_SPI_BUS_EXT 2
|
||||
|
||||
/*
|
||||
* Use these in place of the spi_dev_e enumeration to
|
||||
|
||||
@@ -108,6 +108,8 @@ __BEGIN_DECLS
|
||||
#define GPIO_SPI_CS_MPU (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_SPEED_2MHz|GPIO_OUTPUT_SET|GPIO_PORTC|GPIO_PIN2)
|
||||
#define GPIO_SPI_CS_EXT0 (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_SPEED_50MHz|GPIO_OUTPUT_SET|GPIO_PORTE|GPIO_PIN4)
|
||||
#define GPIO_SPI_CS_EXT1 (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_SPEED_50MHz|GPIO_OUTPUT_SET|GPIO_PORTC|GPIO_PIN14)
|
||||
#define GPIO_SPI_CS_EXT2 (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_SPEED_50MHz|GPIO_OUTPUT_SET|GPIO_PORTC|GPIO_PIN15)
|
||||
#define GPIO_SPI_CS_EXT3 (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_SPEED_50MHz|GPIO_OUTPUT_SET|GPIO_PORTC|GPIO_PIN13)
|
||||
|
||||
#define PX4_SPI_BUS_SENSORS 1
|
||||
#define PX4_SPI_BUS_EXT 4
|
||||
@@ -121,10 +123,19 @@ __BEGIN_DECLS
|
||||
/* External bus */
|
||||
#define PX4_SPIDEV_EXT0 1
|
||||
#define PX4_SPIDEV_EXT1 2
|
||||
#define PX4_SPIDEV_EXT2 3
|
||||
#define PX4_SPIDEV_EXT3 4
|
||||
|
||||
/* FMUv3 SPI on external bus */
|
||||
#define PX4_SPIDEV_EXT_MPU PX4_SPIDEV_EXT0
|
||||
#define PX4_SPIDEV_EXT_BARO PX4_SPIDEV_EXT1
|
||||
#define PX4_SPIDEV_EXT_ACCEL_MAG PX4_SPIDEV_EXT2
|
||||
#define PX4_SPIDEV_EXT_GYRO PX4_SPIDEV_EXT3
|
||||
|
||||
/* I2C busses */
|
||||
#define PX4_I2C_BUS_EXPANSION 1
|
||||
#define PX4_I2C_BUS_LED 2
|
||||
#define PX4_I2C_BUS_ONBOARD 2
|
||||
#define PX4_I2C_BUS_LED PX4_I2C_BUS_ONBOARD
|
||||
|
||||
/* Devices on the onboard bus.
|
||||
*
|
||||
|
||||
@@ -98,8 +98,12 @@ __EXPORT void weak_function stm32_spiinitialize(void)
|
||||
#ifdef CONFIG_STM32_SPI4
|
||||
stm32_configgpio(GPIO_SPI_CS_EXT0);
|
||||
stm32_configgpio(GPIO_SPI_CS_EXT1);
|
||||
stm32_configgpio(GPIO_SPI_CS_EXT2);
|
||||
stm32_configgpio(GPIO_SPI_CS_EXT3);
|
||||
stm32_gpiowrite(GPIO_SPI_CS_EXT0, 1);
|
||||
stm32_gpiowrite(GPIO_SPI_CS_EXT1, 1);
|
||||
stm32_gpiowrite(GPIO_SPI_CS_EXT2, 1);
|
||||
stm32_gpiowrite(GPIO_SPI_CS_EXT3, 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -174,12 +178,32 @@ __EXPORT void stm32_spi4select(FAR struct spi_dev_s *dev, enum spi_dev_e devid,
|
||||
/* Making sure the other peripherals are not selected */
|
||||
stm32_gpiowrite(GPIO_SPI_CS_EXT0, !selected);
|
||||
stm32_gpiowrite(GPIO_SPI_CS_EXT1, 1);
|
||||
stm32_gpiowrite(GPIO_SPI_CS_EXT2, 1);
|
||||
stm32_gpiowrite(GPIO_SPI_CS_EXT3, 1);
|
||||
break;
|
||||
|
||||
case PX4_SPIDEV_EXT1:
|
||||
/* Making sure the other peripherals are not selected */
|
||||
stm32_gpiowrite(GPIO_SPI_CS_EXT1, !selected);
|
||||
stm32_gpiowrite(GPIO_SPI_CS_EXT0, 1);
|
||||
stm32_gpiowrite(GPIO_SPI_CS_EXT1, !selected);
|
||||
stm32_gpiowrite(GPIO_SPI_CS_EXT2, 1);
|
||||
stm32_gpiowrite(GPIO_SPI_CS_EXT3, 1);
|
||||
break;
|
||||
|
||||
case PX4_SPIDEV_EXT2:
|
||||
/* Making sure the other peripherals are not selected */
|
||||
stm32_gpiowrite(GPIO_SPI_CS_EXT0, 1);
|
||||
stm32_gpiowrite(GPIO_SPI_CS_EXT1, 1);
|
||||
stm32_gpiowrite(GPIO_SPI_CS_EXT2, !selected);
|
||||
stm32_gpiowrite(GPIO_SPI_CS_EXT3, 1);
|
||||
break;
|
||||
|
||||
case PX4_SPIDEV_EXT3:
|
||||
/* Making sure the other peripherals are not selected */
|
||||
stm32_gpiowrite(GPIO_SPI_CS_EXT0, 1);
|
||||
stm32_gpiowrite(GPIO_SPI_CS_EXT1, 1);
|
||||
stm32_gpiowrite(GPIO_SPI_CS_EXT2, 1);
|
||||
stm32_gpiowrite(GPIO_SPI_CS_EXT3, !selected);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
@@ -268,6 +268,13 @@ CDev::ioctl(struct file *filp, int cmd, unsigned long arg)
|
||||
break;
|
||||
}
|
||||
|
||||
/* try the superclass. The different ioctl() function form
|
||||
* means we need to copy arg */
|
||||
unsigned arg2 = arg;
|
||||
int ret = Device::ioctl(cmd, arg2);
|
||||
if (ret != -ENODEV)
|
||||
return ret;
|
||||
|
||||
return -ENOTTY;
|
||||
}
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
#include <nuttx/arch.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <drivers/drv_device.h>
|
||||
|
||||
namespace device
|
||||
{
|
||||
@@ -93,6 +94,13 @@ Device::Device(const char *name,
|
||||
_irq_attached(false)
|
||||
{
|
||||
sem_init(&_lock, 0, 1);
|
||||
|
||||
/* setup a default device ID. When bus_type is UNKNOWN the
|
||||
other fields are invalid */
|
||||
_device_id.devid_s.bus_type = DeviceBusType_UNKNOWN;
|
||||
_device_id.devid_s.bus = 0;
|
||||
_device_id.devid_s.address = 0;
|
||||
_device_id.devid_s.devtype = 0;
|
||||
}
|
||||
|
||||
Device::~Device()
|
||||
@@ -238,6 +246,10 @@ Device::write(unsigned offset, void *data, unsigned count)
|
||||
int
|
||||
Device::ioctl(unsigned operation, unsigned &arg)
|
||||
{
|
||||
switch (operation) {
|
||||
case DEVIOCGDEVICEID:
|
||||
return (int)_device_id.devid;
|
||||
}
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
|
||||
@@ -124,9 +124,37 @@ public:
|
||||
*/
|
||||
virtual int ioctl(unsigned operation, unsigned &arg);
|
||||
|
||||
/*
|
||||
device bus types for DEVID
|
||||
*/
|
||||
enum DeviceBusType {
|
||||
DeviceBusType_UNKNOWN = 0,
|
||||
DeviceBusType_I2C = 1,
|
||||
DeviceBusType_SPI = 2
|
||||
};
|
||||
|
||||
/*
|
||||
broken out device elements. The bitfields are used to keep
|
||||
the overall value small enough to fit in a float accurately,
|
||||
which makes it possible to transport over the MAVLink
|
||||
parameter protocol without loss of information.
|
||||
*/
|
||||
struct DeviceStructure {
|
||||
enum DeviceBusType bus_type:3;
|
||||
uint8_t bus:5; // which instance of the bus type
|
||||
uint8_t address; // address on the bus (eg. I2C address)
|
||||
uint8_t devtype; // device class specific device type
|
||||
};
|
||||
|
||||
union DeviceId {
|
||||
struct DeviceStructure devid_s;
|
||||
uint32_t devid;
|
||||
};
|
||||
|
||||
protected:
|
||||
const char *_name; /**< driver name */
|
||||
bool _debug_enabled; /**< if true, debug messages are printed */
|
||||
union DeviceId _device_id; /**< device identifier information */
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
@@ -212,6 +240,7 @@ private:
|
||||
* @param context Pointer to the interrupted context.
|
||||
*/
|
||||
static void dev_interrupt(int irq, void *context);
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -441,6 +470,10 @@ private:
|
||||
* @return OK, or -errno on error.
|
||||
*/
|
||||
int remove_poll_waiter(struct pollfd *fds);
|
||||
|
||||
/* do not allow copying this class */
|
||||
CDev(const CDev&);
|
||||
CDev operator=(const CDev&);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -510,6 +543,10 @@ private:
|
||||
} // namespace device
|
||||
|
||||
// class instance for primary driver of each class
|
||||
#define CLASS_DEVICE_PRIMARY 0
|
||||
enum CLASS_DEVICE {
|
||||
CLASS_DEVICE_PRIMARY=0,
|
||||
CLASS_DEVICE_SECONDARY=1,
|
||||
CLASS_DEVICE_TERTIARY=2
|
||||
};
|
||||
|
||||
#endif /* _DEVICE_DEVICE_H */
|
||||
|
||||
@@ -62,6 +62,12 @@ I2C::I2C(const char *name,
|
||||
_frequency(frequency),
|
||||
_dev(nullptr)
|
||||
{
|
||||
// fill in _device_id fields for a I2C device
|
||||
_device_id.devid_s.bus_type = DeviceBusType_I2C;
|
||||
_device_id.devid_s.bus = bus;
|
||||
_device_id.devid_s.address = address;
|
||||
// devtype needs to be filled in by the driver
|
||||
_device_id.devid_s.devtype = 0;
|
||||
}
|
||||
|
||||
I2C::~I2C()
|
||||
@@ -201,4 +207,4 @@ I2C::transfer(i2c_msg_s *msgv, unsigned msgs)
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // namespace device
|
||||
} // namespace device
|
||||
|
||||
@@ -138,6 +138,9 @@ private:
|
||||
uint16_t _address;
|
||||
uint32_t _frequency;
|
||||
struct i2c_dev_s *_dev;
|
||||
|
||||
I2C(const device::I2C&);
|
||||
I2C operator=(const device::I2C&);
|
||||
};
|
||||
|
||||
} // namespace device
|
||||
|
||||
@@ -162,6 +162,10 @@ private:
|
||||
volatile unsigned _tail; /**< removal point in _item_size units */
|
||||
|
||||
unsigned _next(unsigned index);
|
||||
|
||||
/* we don't want this class to be copied */
|
||||
RingBuffer(const RingBuffer&);
|
||||
RingBuffer operator=(const RingBuffer&);
|
||||
};
|
||||
|
||||
RingBuffer::RingBuffer(unsigned num_items, size_t item_size) :
|
||||
|
||||
@@ -69,12 +69,18 @@ SPI::SPI(const char *name,
|
||||
// protected
|
||||
locking_mode(LOCK_PREEMPTION),
|
||||
// private
|
||||
_bus(bus),
|
||||
_device(device),
|
||||
_mode(mode),
|
||||
_frequency(frequency),
|
||||
_dev(nullptr)
|
||||
_dev(nullptr),
|
||||
_bus(bus)
|
||||
{
|
||||
// fill in _device_id fields for a SPI device
|
||||
_device_id.devid_s.bus_type = DeviceBusType_SPI;
|
||||
_device_id.devid_s.bus = bus;
|
||||
_device_id.devid_s.address = (uint8_t)device;
|
||||
// devtype needs to be filled in by the driver
|
||||
_device_id.devid_s.devtype = 0;
|
||||
}
|
||||
|
||||
SPI::~SPI()
|
||||
|
||||
@@ -124,13 +124,20 @@ protected:
|
||||
LockMode locking_mode; /**< selected locking mode */
|
||||
|
||||
private:
|
||||
int _bus;
|
||||
enum spi_dev_e _device;
|
||||
enum spi_mode_e _mode;
|
||||
uint32_t _frequency;
|
||||
struct spi_dev_s *_dev;
|
||||
|
||||
/* this class does not allow copying */
|
||||
SPI(const SPI&);
|
||||
SPI operator=(const SPI&);
|
||||
|
||||
protected:
|
||||
int _bus;
|
||||
|
||||
int _transfer(uint8_t *send, uint8_t *recv, unsigned len);
|
||||
|
||||
};
|
||||
|
||||
} // namespace device
|
||||
|
||||
@@ -81,7 +81,9 @@ struct accel_scale {
|
||||
/*
|
||||
* ObjDev tag for raw accelerometer data.
|
||||
*/
|
||||
ORB_DECLARE(sensor_accel);
|
||||
ORB_DECLARE(sensor_accel0);
|
||||
ORB_DECLARE(sensor_accel1);
|
||||
ORB_DECLARE(sensor_accel2);
|
||||
|
||||
/*
|
||||
* ioctl() definitions
|
||||
|
||||
@@ -63,7 +63,8 @@ struct baro_report {
|
||||
/*
|
||||
* ObjDev tag for raw barometer data.
|
||||
*/
|
||||
ORB_DECLARE(sensor_baro);
|
||||
ORB_DECLARE(sensor_baro0);
|
||||
ORB_DECLARE(sensor_baro1);
|
||||
|
||||
/*
|
||||
* ioctl() definitions
|
||||
|
||||
@@ -59,4 +59,11 @@
|
||||
/** check publication block status */
|
||||
#define DEVIOCGPUBBLOCK _DEVICEIOC(1)
|
||||
|
||||
/**
|
||||
* Return device ID, to enable matching of configuration parameters
|
||||
* (such as compass offsets) to specific sensors
|
||||
*/
|
||||
#define DEVIOCGDEVICEID _DEVICEIOC(2)
|
||||
|
||||
|
||||
#endif /* _DRV_DEVICE_H */
|
||||
|
||||
@@ -81,7 +81,9 @@ struct gyro_scale {
|
||||
/*
|
||||
* ObjDev tag for raw gyro data.
|
||||
*/
|
||||
ORB_DECLARE(sensor_gyro);
|
||||
ORB_DECLARE(sensor_gyro0);
|
||||
ORB_DECLARE(sensor_gyro1);
|
||||
ORB_DECLARE(sensor_gyro2);
|
||||
|
||||
/*
|
||||
* ioctl() definitions
|
||||
|
||||
@@ -79,7 +79,15 @@ struct mag_scale {
|
||||
/*
|
||||
* ObjDev tag for raw magnetometer data.
|
||||
*/
|
||||
ORB_DECLARE(sensor_mag);
|
||||
ORB_DECLARE(sensor_mag0);
|
||||
ORB_DECLARE(sensor_mag1);
|
||||
ORB_DECLARE(sensor_mag2);
|
||||
|
||||
/*
|
||||
* mag device types, for _device_id
|
||||
*/
|
||||
#define DRV_MAG_DEVTYPE_HMC5883 1
|
||||
#define DRV_MAG_DEVTYPE_LSM303D 2
|
||||
|
||||
/*
|
||||
* ioctl() definitions
|
||||
|
||||
@@ -94,6 +94,11 @@ __BEGIN_DECLS
|
||||
*/
|
||||
#define PWM_LOWEST_MAX 1700
|
||||
|
||||
/**
|
||||
* Do not output a channel with this value
|
||||
*/
|
||||
#define PWM_IGNORE_THIS_CHANNEL UINT16_MAX
|
||||
|
||||
/**
|
||||
* Servo output signal type, value is actual servo output pulse
|
||||
* width in microseconds.
|
||||
@@ -202,6 +207,9 @@ ORB_DECLARE(output_pwm);
|
||||
/** force safety switch off (to disable use of safety switch) */
|
||||
#define PWM_SERVO_SET_FORCE_SAFETY_OFF _IOC(_PWM_SERVO_BASE, 23)
|
||||
|
||||
/** force failsafe mode (failsafe values are set immediately even if failsafe condition not met) */
|
||||
#define PWM_SERVO_SET_FORCE_FAILSAFE _IOC(_PWM_SERVO_BASE, 24)
|
||||
|
||||
/*
|
||||
*
|
||||
*
|
||||
|
||||
@@ -46,25 +46,6 @@
|
||||
|
||||
#define PX4FLOW_DEVICE_PATH "/dev/px4flow"
|
||||
|
||||
/**
|
||||
* Optical flow in NED body frame in SI units.
|
||||
*
|
||||
* @see http://en.wikipedia.org/wiki/International_System_of_Units
|
||||
*/
|
||||
struct px4flow_report {
|
||||
|
||||
uint64_t timestamp; /**< in microseconds since system start */
|
||||
|
||||
int16_t flow_raw_x; /**< flow in pixels in X direction, not rotation-compensated */
|
||||
int16_t flow_raw_y; /**< flow in pixels in Y direction, not rotation-compensated */
|
||||
float flow_comp_x_m; /**< speed over ground in meters, rotation-compensated */
|
||||
float flow_comp_y_m; /**< speed over ground in meters, rotation-compensated */
|
||||
float ground_distance_m; /**< Altitude / distance to ground in meters */
|
||||
uint8_t quality; /**< Quality of the measurement, 0: bad quality, 255: maximum quality */
|
||||
uint8_t sensor_id; /**< id of the sensor emitting the flow value */
|
||||
|
||||
};
|
||||
|
||||
/*
|
||||
* ObjDev tag for px4flow data.
|
||||
*/
|
||||
|
||||
@@ -50,6 +50,11 @@ enum RANGE_FINDER_TYPE {
|
||||
RANGE_FINDER_TYPE_LASER = 0,
|
||||
};
|
||||
|
||||
/**
|
||||
* @addtogroup topics
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* range finder report structure. Reads from the device must be in multiples of this
|
||||
* structure.
|
||||
@@ -64,6 +69,10 @@ struct range_finder_report {
|
||||
uint8_t valid; /**< 1 == within sensor range, 0 = outside sensor range */
|
||||
};
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/*
|
||||
* ObjDev tag for raw range finder data.
|
||||
*/
|
||||
|
||||
@@ -67,6 +67,11 @@
|
||||
*/
|
||||
#define RC_INPUT_RSSI_MAX 255
|
||||
|
||||
/**
|
||||
* @addtogroup topics
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Input signal type, value is a control position from zero to 100
|
||||
* percent.
|
||||
@@ -141,6 +146,10 @@ struct rc_input_values {
|
||||
rc_input_t values[RC_INPUT_MAX_CHANNELS];
|
||||
};
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/*
|
||||
* ObjDev tag for R/C inputs.
|
||||
*/
|
||||
|
||||
@@ -149,6 +149,8 @@ enum {
|
||||
TONE_GPS_WARNING_TUNE,
|
||||
TONE_ARMING_FAILURE_TUNE,
|
||||
TONE_PARACHUTE_RELEASE_TUNE,
|
||||
TONE_EKF_WARNING_TUNE,
|
||||
TONE_BARO_WARNING_TUNE,
|
||||
TONE_NUMBER_OF_TUNES
|
||||
};
|
||||
|
||||
|
||||
@@ -155,7 +155,6 @@ ETSAirspeed::collect()
|
||||
}
|
||||
|
||||
uint16_t diff_pres_pa_raw = val[1] << 8 | val[0];
|
||||
uint16_t diff_pres_pa;
|
||||
if (diff_pres_pa_raw == 0) {
|
||||
// a zero value means the pressure sensor cannot give us a
|
||||
// value. We need to return, and not report a value or the
|
||||
@@ -166,27 +165,22 @@ ETSAirspeed::collect()
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (diff_pres_pa_raw < _diff_pres_offset + MIN_ACCURATE_DIFF_PRES_PA) {
|
||||
diff_pres_pa = 0;
|
||||
} else {
|
||||
diff_pres_pa = diff_pres_pa_raw - _diff_pres_offset;
|
||||
}
|
||||
// The raw value still should be compensated for the known offset
|
||||
diff_pres_pa_raw -= _diff_pres_offset;
|
||||
|
||||
// Track maximum differential pressure measured (so we can work out top speed).
|
||||
if (diff_pres_pa > _max_differential_pressure_pa) {
|
||||
_max_differential_pressure_pa = diff_pres_pa;
|
||||
if (diff_pres_pa_raw > _max_differential_pressure_pa) {
|
||||
_max_differential_pressure_pa = diff_pres_pa_raw;
|
||||
}
|
||||
|
||||
differential_pressure_s report;
|
||||
report.timestamp = hrt_absolute_time();
|
||||
report.error_count = perf_event_count(_comms_errors);
|
||||
report.differential_pressure_pa = (float)diff_pres_pa;
|
||||
|
||||
// XXX we may want to smooth out the readings to remove noise.
|
||||
report.differential_pressure_filtered_pa = (float)diff_pres_pa;
|
||||
report.differential_pressure_raw_pa = (float)diff_pres_pa_raw;
|
||||
report.differential_pressure_filtered_pa = diff_pres_pa_raw;
|
||||
report.differential_pressure_raw_pa = diff_pres_pa_raw;
|
||||
report.temperature = -1000.0f;
|
||||
report.voltage = 0;
|
||||
report.max_differential_pressure_pa = _max_differential_pressure_pa;
|
||||
|
||||
if (_airspeed_pub > 0 && !(_pub_blocked)) {
|
||||
@@ -284,6 +278,9 @@ void info();
|
||||
|
||||
/**
|
||||
* Start the driver.
|
||||
*
|
||||
* This function only returns if the sensor is up and running
|
||||
* or could not be detected successfully.
|
||||
*/
|
||||
void
|
||||
start(int i2c_bus)
|
||||
@@ -364,7 +361,7 @@ test()
|
||||
err(1, "immediate read failed");
|
||||
|
||||
warnx("single read");
|
||||
warnx("diff pressure: %f pa", (double)report.differential_pressure_pa);
|
||||
warnx("diff pressure: %f pa", (double)report.differential_pressure_filtered_pa);
|
||||
|
||||
/* start the sensor polling at 2Hz */
|
||||
if (OK != ioctl(fd, SENSORIOCSPOLLRATE, 2))
|
||||
@@ -389,7 +386,7 @@ test()
|
||||
err(1, "periodic read failed");
|
||||
|
||||
warnx("periodic read %u", i);
|
||||
warnx("diff pressure: %f pa", (double)report.differential_pressure_pa);
|
||||
warnx("diff pressure: %f pa", (double)report.differential_pressure_filtered_pa);
|
||||
}
|
||||
|
||||
/* reset the sensor polling to its default rate */
|
||||
|
||||
@@ -36,6 +36,9 @@
|
||||
#
|
||||
|
||||
MODULE_COMMAND = ets_airspeed
|
||||
MODULE_STACKSIZE = 2048
|
||||
|
||||
SRCS = ets_airspeed.cpp
|
||||
|
||||
MODULE_STACKSIZE = 1200
|
||||
|
||||
MAXOPTIMIZATION = -Os
|
||||
|
||||
@@ -41,3 +41,5 @@ SRCS = frsky_data.c \
|
||||
frsky_telemetry.c
|
||||
|
||||
MODULE_STACKSIZE = 1200
|
||||
|
||||
MAXOPTIMIZATION = -Os
|
||||
|
||||
@@ -127,7 +127,7 @@ private:
|
||||
/**
|
||||
* Try to configure the GPS, handle outgoing communication to the GPS
|
||||
*/
|
||||
void config();
|
||||
void config();
|
||||
|
||||
/**
|
||||
* Trampoline to the worker task
|
||||
@@ -486,6 +486,8 @@ GPS::print_info()
|
||||
warnx("position lock: %dD, satellites: %d, last update: %8.4fms ago", (int)_report_gps_pos.fix_type,
|
||||
_report_gps_pos.satellites_used, (double)(hrt_absolute_time() - _report_gps_pos.timestamp_position) / 1000.0);
|
||||
warnx("lat: %d, lon: %d, alt: %d", _report_gps_pos.lat, _report_gps_pos.lon, _report_gps_pos.alt);
|
||||
warnx("vel: %.2fm/s, %.2fm/s, %.2fm/s", (double)_report_gps_pos.vel_n_m_s,
|
||||
(double)_report_gps_pos.vel_e_m_s, (double)_report_gps_pos.vel_d_m_s);
|
||||
warnx("eph: %.2fm, epv: %.2fm", (double)_report_gps_pos.eph, (double)_report_gps_pos.epv);
|
||||
warnx("rate position: \t%6.2f Hz", (double)_Helper->get_position_update_rate());
|
||||
warnx("rate velocity: \t%6.2f Hz", (double)_Helper->get_velocity_update_rate());
|
||||
|
||||
@@ -43,3 +43,5 @@ SRCS = gps.cpp \
|
||||
ubx.cpp
|
||||
|
||||
MODULE_STACKSIZE = 1200
|
||||
|
||||
MAXOPTIMIZATION = -Os
|
||||
|
||||
@@ -38,3 +38,5 @@
|
||||
MODULE_COMMAND = hil
|
||||
|
||||
SRCS = hil.cpp
|
||||
|
||||
MAXOPTIMIZATION = -Os
|
||||
|
||||
+286
-80
@@ -71,13 +71,16 @@
|
||||
#include <uORB/topics/subsystem_info.h>
|
||||
|
||||
#include <float.h>
|
||||
#include <getopt.h>
|
||||
#include <lib/conversion/rotation.h>
|
||||
|
||||
/*
|
||||
* HMC5883 internal constants and data structures.
|
||||
*/
|
||||
|
||||
#define HMC5883L_ADDRESS PX4_I2C_OBDEV_HMC5883
|
||||
#define HMC5883L_DEVICE_PATH "/dev/hmc5883"
|
||||
#define HMC5883L_DEVICE_PATH_INT "/dev/hmc5883_int"
|
||||
#define HMC5883L_DEVICE_PATH_EXT "/dev/hmc5883_ext"
|
||||
|
||||
/* Max measurement rate is 160Hz, however with 160 it will be set to 166 Hz, therefore workaround using 150 */
|
||||
#define HMC5883_CONVERSION_INTERVAL (1000000 / 150) /* microseconds */
|
||||
@@ -130,7 +133,7 @@ static const int ERROR = -1;
|
||||
class HMC5883 : public device::I2C
|
||||
{
|
||||
public:
|
||||
HMC5883(int bus);
|
||||
HMC5883(int bus, const char *path, enum Rotation rotation);
|
||||
virtual ~HMC5883();
|
||||
|
||||
virtual int init();
|
||||
@@ -159,19 +162,26 @@ private:
|
||||
|
||||
orb_advert_t _mag_topic;
|
||||
orb_advert_t _subsystem_pub;
|
||||
orb_id_t _mag_orb_id;
|
||||
|
||||
perf_counter_t _sample_perf;
|
||||
perf_counter_t _comms_errors;
|
||||
perf_counter_t _buffer_overflows;
|
||||
perf_counter_t _range_errors;
|
||||
perf_counter_t _conf_errors;
|
||||
|
||||
/* status reporting */
|
||||
bool _sensor_ok; /**< sensor was found and reports ok */
|
||||
bool _calibrated; /**< the calibration is valid */
|
||||
|
||||
int _bus; /**< the bus the device is connected to */
|
||||
enum Rotation _rotation;
|
||||
|
||||
struct mag_report _last_report; /**< used for info() */
|
||||
|
||||
uint8_t _range_bits;
|
||||
uint8_t _conf_reg;
|
||||
|
||||
/**
|
||||
* Test whether the device supported by the driver is present at a
|
||||
* specific address.
|
||||
@@ -229,6 +239,23 @@ private:
|
||||
*/
|
||||
int set_range(unsigned range);
|
||||
|
||||
/**
|
||||
* check the sensor range.
|
||||
*
|
||||
* checks that the range of the sensor is correctly set, to
|
||||
* cope with communication errors causing the range to change
|
||||
*/
|
||||
void check_range(void);
|
||||
|
||||
/**
|
||||
* check the sensor configuration.
|
||||
*
|
||||
* checks that the config of the sensor is correctly set, to
|
||||
* cope with communication errors causing the configuration to
|
||||
* change
|
||||
*/
|
||||
void check_conf(void);
|
||||
|
||||
/**
|
||||
* Perform a poll cycle; collect from the previous measurement
|
||||
* and start a new one.
|
||||
@@ -311,6 +338,9 @@ private:
|
||||
*/
|
||||
int check_offset();
|
||||
|
||||
/* this class has pointer data members, do not allow copying it */
|
||||
HMC5883(const HMC5883&);
|
||||
HMC5883 operator=(const HMC5883&);
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -319,23 +349,34 @@ private:
|
||||
extern "C" __EXPORT int hmc5883_main(int argc, char *argv[]);
|
||||
|
||||
|
||||
HMC5883::HMC5883(int bus) :
|
||||
I2C("HMC5883", HMC5883L_DEVICE_PATH, bus, HMC5883L_ADDRESS, 400000),
|
||||
HMC5883::HMC5883(int bus, const char *path, enum Rotation rotation) :
|
||||
I2C("HMC5883", path, bus, HMC5883L_ADDRESS, 400000),
|
||||
_work{},
|
||||
_measure_ticks(0),
|
||||
_reports(nullptr),
|
||||
_scale{},
|
||||
_range_scale(0), /* default range scale from counts to gauss */
|
||||
_range_ga(1.3f),
|
||||
_collect_phase(false),
|
||||
_class_instance(-1),
|
||||
_mag_topic(-1),
|
||||
_subsystem_pub(-1),
|
||||
_mag_orb_id(nullptr),
|
||||
_sample_perf(perf_alloc(PC_ELAPSED, "hmc5883_read")),
|
||||
_comms_errors(perf_alloc(PC_COUNT, "hmc5883_comms_errors")),
|
||||
_buffer_overflows(perf_alloc(PC_COUNT, "hmc5883_buffer_overflows")),
|
||||
_range_errors(perf_alloc(PC_COUNT, "hmc5883_range_errors")),
|
||||
_conf_errors(perf_alloc(PC_COUNT, "hmc5883_conf_errors")),
|
||||
_sensor_ok(false),
|
||||
_calibrated(false),
|
||||
_bus(bus)
|
||||
_bus(bus),
|
||||
_rotation(rotation),
|
||||
_last_report{0},
|
||||
_range_bits(0),
|
||||
_conf_reg(0)
|
||||
{
|
||||
_device_id.devid_s.devtype = DRV_MAG_DEVTYPE_HMC5883;
|
||||
|
||||
// enable debug() calls
|
||||
_debug_enabled = false;
|
||||
|
||||
@@ -366,6 +407,8 @@ HMC5883::~HMC5883()
|
||||
perf_free(_sample_perf);
|
||||
perf_free(_comms_errors);
|
||||
perf_free(_buffer_overflows);
|
||||
perf_free(_range_errors);
|
||||
perf_free(_conf_errors);
|
||||
}
|
||||
|
||||
int
|
||||
@@ -387,6 +430,20 @@ HMC5883::init()
|
||||
|
||||
_class_instance = register_class_devname(MAG_DEVICE_PATH);
|
||||
|
||||
switch (_class_instance) {
|
||||
case CLASS_DEVICE_PRIMARY:
|
||||
_mag_orb_id = ORB_ID(sensor_mag0);
|
||||
break;
|
||||
|
||||
case CLASS_DEVICE_SECONDARY:
|
||||
_mag_orb_id = ORB_ID(sensor_mag1);
|
||||
break;
|
||||
|
||||
case CLASS_DEVICE_TERTIARY:
|
||||
_mag_orb_id = ORB_ID(sensor_mag2);
|
||||
break;
|
||||
}
|
||||
|
||||
ret = OK;
|
||||
/* sensor is ok, but not calibrated */
|
||||
_sensor_ok = true;
|
||||
@@ -396,45 +453,43 @@ out:
|
||||
|
||||
int HMC5883::set_range(unsigned range)
|
||||
{
|
||||
uint8_t range_bits;
|
||||
|
||||
if (range < 1) {
|
||||
range_bits = 0x00;
|
||||
_range_bits = 0x00;
|
||||
_range_scale = 1.0f / 1370.0f;
|
||||
_range_ga = 0.88f;
|
||||
|
||||
} else if (range <= 1) {
|
||||
range_bits = 0x01;
|
||||
_range_bits = 0x01;
|
||||
_range_scale = 1.0f / 1090.0f;
|
||||
_range_ga = 1.3f;
|
||||
|
||||
} else if (range <= 2) {
|
||||
range_bits = 0x02;
|
||||
_range_bits = 0x02;
|
||||
_range_scale = 1.0f / 820.0f;
|
||||
_range_ga = 1.9f;
|
||||
|
||||
} else if (range <= 3) {
|
||||
range_bits = 0x03;
|
||||
_range_bits = 0x03;
|
||||
_range_scale = 1.0f / 660.0f;
|
||||
_range_ga = 2.5f;
|
||||
|
||||
} else if (range <= 4) {
|
||||
range_bits = 0x04;
|
||||
_range_bits = 0x04;
|
||||
_range_scale = 1.0f / 440.0f;
|
||||
_range_ga = 4.0f;
|
||||
|
||||
} else if (range <= 4.7f) {
|
||||
range_bits = 0x05;
|
||||
_range_bits = 0x05;
|
||||
_range_scale = 1.0f / 390.0f;
|
||||
_range_ga = 4.7f;
|
||||
|
||||
} else if (range <= 5.6f) {
|
||||
range_bits = 0x06;
|
||||
_range_bits = 0x06;
|
||||
_range_scale = 1.0f / 330.0f;
|
||||
_range_ga = 5.6f;
|
||||
|
||||
} else {
|
||||
range_bits = 0x07;
|
||||
_range_bits = 0x07;
|
||||
_range_scale = 1.0f / 230.0f;
|
||||
_range_ga = 8.1f;
|
||||
}
|
||||
@@ -444,7 +499,7 @@ int HMC5883::set_range(unsigned range)
|
||||
/*
|
||||
* Send the command to set the range
|
||||
*/
|
||||
ret = write_reg(ADDR_CONF_B, (range_bits << 5));
|
||||
ret = write_reg(ADDR_CONF_B, (_range_bits << 5));
|
||||
|
||||
if (OK != ret)
|
||||
perf_count(_comms_errors);
|
||||
@@ -455,7 +510,53 @@ int HMC5883::set_range(unsigned range)
|
||||
if (OK != ret)
|
||||
perf_count(_comms_errors);
|
||||
|
||||
return !(range_bits_in == (range_bits << 5));
|
||||
return !(range_bits_in == (_range_bits << 5));
|
||||
}
|
||||
|
||||
/**
|
||||
check that the range register has the right value. This is done
|
||||
periodically to cope with I2C bus noise causing the range of the
|
||||
compass changing.
|
||||
*/
|
||||
void HMC5883::check_range(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
uint8_t range_bits_in;
|
||||
ret = read_reg(ADDR_CONF_B, range_bits_in);
|
||||
if (OK != ret) {
|
||||
perf_count(_comms_errors);
|
||||
return;
|
||||
}
|
||||
if (range_bits_in != (_range_bits<<5)) {
|
||||
perf_count(_range_errors);
|
||||
ret = write_reg(ADDR_CONF_B, (_range_bits << 5));
|
||||
if (OK != ret)
|
||||
perf_count(_comms_errors);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
check that the configuration register has the right value. This is
|
||||
done periodically to cope with I2C bus noise causing the
|
||||
configuration of the compass to change.
|
||||
*/
|
||||
void HMC5883::check_conf(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
uint8_t conf_reg_in;
|
||||
ret = read_reg(ADDR_CONF_A, conf_reg_in);
|
||||
if (OK != ret) {
|
||||
perf_count(_comms_errors);
|
||||
return;
|
||||
}
|
||||
if (conf_reg_in != _conf_reg) {
|
||||
perf_count(_conf_errors);
|
||||
ret = write_reg(ADDR_CONF_A, _conf_reg);
|
||||
if (OK != ret)
|
||||
perf_count(_comms_errors);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
@@ -787,9 +888,10 @@ HMC5883::collect()
|
||||
struct {
|
||||
int16_t x, y, z;
|
||||
} report;
|
||||
int ret = -EIO;
|
||||
uint8_t cmd;
|
||||
|
||||
int ret;
|
||||
uint8_t cmd;
|
||||
uint8_t check_counter;
|
||||
|
||||
perf_begin(_sample_perf);
|
||||
struct mag_report new_report;
|
||||
@@ -862,16 +964,19 @@ HMC5883::collect()
|
||||
/* z remains z */
|
||||
new_report.z = ((report.z * _range_scale) - _scale.z_offset) * _scale.z_scale;
|
||||
|
||||
if (_class_instance == CLASS_DEVICE_PRIMARY && !(_pub_blocked)) {
|
||||
// apply user specified rotation
|
||||
rotate_3f(_rotation, new_report.x, new_report.y, new_report.z);
|
||||
|
||||
if (!(_pub_blocked)) {
|
||||
|
||||
if (_mag_topic != -1) {
|
||||
/* publish it */
|
||||
orb_publish(ORB_ID(sensor_mag), _mag_topic, &new_report);
|
||||
orb_publish(_mag_orb_id, _mag_topic, &new_report);
|
||||
} else {
|
||||
_mag_topic = orb_advertise(ORB_ID(sensor_mag), &new_report);
|
||||
_mag_topic = orb_advertise(_mag_orb_id, &new_report);
|
||||
|
||||
if (_mag_topic < 0)
|
||||
debug("failed to create sensor_mag publication");
|
||||
debug("ADVERT FAIL");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -885,6 +990,21 @@ HMC5883::collect()
|
||||
/* notify anyone waiting for data */
|
||||
poll_notify(POLLIN);
|
||||
|
||||
/*
|
||||
periodically check the range register and configuration
|
||||
registers. With a bad I2C cable it is possible for the
|
||||
registers to become corrupt, leading to bad readings. It
|
||||
doesn't happen often, but given the poor cables some
|
||||
vehicles have it is worth checking for.
|
||||
*/
|
||||
check_counter = perf_event_count(_sample_perf) % 256;
|
||||
if (check_counter == 0) {
|
||||
check_range();
|
||||
}
|
||||
if (check_counter == 128) {
|
||||
check_conf();
|
||||
}
|
||||
|
||||
ret = OK;
|
||||
|
||||
out:
|
||||
@@ -1059,7 +1179,7 @@ int HMC5883::calibrate(struct file *filp, unsigned enable)
|
||||
out:
|
||||
|
||||
if (OK != ioctl(filp, MAGIOCSSCALE, (long unsigned int)&mscale_previous)) {
|
||||
warn("WARNING: failed to set new scale / offsets for mag");
|
||||
warn("failed to set new scale / offsets for mag");
|
||||
}
|
||||
|
||||
/* set back to normal mode */
|
||||
@@ -1158,25 +1278,23 @@ int HMC5883::set_excitement(unsigned enable)
|
||||
{
|
||||
int ret;
|
||||
/* arm the excitement strap */
|
||||
uint8_t conf_reg;
|
||||
ret = read_reg(ADDR_CONF_A, conf_reg);
|
||||
ret = read_reg(ADDR_CONF_A, _conf_reg);
|
||||
|
||||
if (OK != ret)
|
||||
perf_count(_comms_errors);
|
||||
|
||||
_conf_reg &= ~0x03; // reset previous excitement mode
|
||||
if (((int)enable) < 0) {
|
||||
conf_reg |= 0x01;
|
||||
_conf_reg |= 0x01;
|
||||
|
||||
} else if (enable > 0) {
|
||||
conf_reg |= 0x02;
|
||||
_conf_reg |= 0x02;
|
||||
|
||||
} else {
|
||||
conf_reg &= ~0x03;
|
||||
}
|
||||
|
||||
// ::printf("set_excitement enable=%d regA=0x%x\n", (int)enable, (unsigned)conf_reg);
|
||||
// ::printf("set_excitement enable=%d regA=0x%x\n", (int)enable, (unsigned)_conf_reg);
|
||||
|
||||
ret = write_reg(ADDR_CONF_A, conf_reg);
|
||||
ret = write_reg(ADDR_CONF_A, _conf_reg);
|
||||
|
||||
if (OK != ret)
|
||||
perf_count(_comms_errors);
|
||||
@@ -1186,7 +1304,7 @@ int HMC5883::set_excitement(unsigned enable)
|
||||
|
||||
//print_info();
|
||||
|
||||
return !(conf_reg == conf_reg_ret);
|
||||
return !(_conf_reg == conf_reg_ret);
|
||||
}
|
||||
|
||||
int
|
||||
@@ -1244,63 +1362,95 @@ namespace hmc5883
|
||||
#endif
|
||||
const int ERROR = -1;
|
||||
|
||||
HMC5883 *g_dev;
|
||||
HMC5883 *g_dev_int = nullptr;
|
||||
HMC5883 *g_dev_ext = nullptr;
|
||||
|
||||
void start();
|
||||
void test();
|
||||
void reset();
|
||||
void info();
|
||||
int calibrate();
|
||||
void start(int bus, enum Rotation rotation);
|
||||
void test(int bus);
|
||||
void reset(int bus);
|
||||
void info(int bus);
|
||||
int calibrate(int bus);
|
||||
void usage();
|
||||
|
||||
/**
|
||||
* Start the driver.
|
||||
*
|
||||
* This function call only returns once the driver
|
||||
* is either successfully up and running or failed to start.
|
||||
*/
|
||||
void
|
||||
start()
|
||||
start(int bus, enum Rotation rotation)
|
||||
{
|
||||
int fd;
|
||||
|
||||
if (g_dev != nullptr)
|
||||
/* if already started, the still command succeeded */
|
||||
errx(0, "already started");
|
||||
|
||||
/* create the driver, attempt expansion bus first */
|
||||
g_dev = new HMC5883(PX4_I2C_BUS_EXPANSION);
|
||||
if (g_dev != nullptr && OK != g_dev->init()) {
|
||||
delete g_dev;
|
||||
g_dev = nullptr;
|
||||
if (bus == -1 || bus == PX4_I2C_BUS_EXPANSION) {
|
||||
if (g_dev_ext != nullptr)
|
||||
errx(0, "already started external");
|
||||
g_dev_ext = new HMC5883(PX4_I2C_BUS_EXPANSION, HMC5883L_DEVICE_PATH_EXT, rotation);
|
||||
if (g_dev_ext != nullptr && OK != g_dev_ext->init()) {
|
||||
delete g_dev_ext;
|
||||
g_dev_ext = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef PX4_I2C_BUS_ONBOARD
|
||||
/* if this failed, attempt onboard sensor */
|
||||
if (g_dev == nullptr) {
|
||||
g_dev = new HMC5883(PX4_I2C_BUS_ONBOARD);
|
||||
if (g_dev != nullptr && OK != g_dev->init()) {
|
||||
if (bus == -1 || bus == PX4_I2C_BUS_ONBOARD) {
|
||||
if (g_dev_int != nullptr)
|
||||
errx(0, "already started internal");
|
||||
g_dev_int = new HMC5883(PX4_I2C_BUS_ONBOARD, HMC5883L_DEVICE_PATH_INT, rotation);
|
||||
if (g_dev_int != nullptr && OK != g_dev_int->init()) {
|
||||
|
||||
/* tear down the failing onboard instance */
|
||||
delete g_dev_int;
|
||||
g_dev_int = nullptr;
|
||||
|
||||
if (bus == PX4_I2C_BUS_ONBOARD) {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
if (g_dev_int == nullptr && bus == PX4_I2C_BUS_ONBOARD) {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (g_dev == nullptr)
|
||||
if (g_dev_int == nullptr && g_dev_ext == nullptr)
|
||||
goto fail;
|
||||
|
||||
/* set the poll rate to default, starts automatic data collection */
|
||||
fd = open(HMC5883L_DEVICE_PATH, O_RDONLY);
|
||||
if (g_dev_int != nullptr) {
|
||||
fd = open(HMC5883L_DEVICE_PATH_INT, O_RDONLY);
|
||||
if (fd < 0)
|
||||
goto fail;
|
||||
|
||||
if (fd < 0)
|
||||
goto fail;
|
||||
if (ioctl(fd, SENSORIOCSPOLLRATE, SENSOR_POLLRATE_DEFAULT) < 0)
|
||||
goto fail;
|
||||
close(fd);
|
||||
}
|
||||
|
||||
if (ioctl(fd, SENSORIOCSPOLLRATE, SENSOR_POLLRATE_DEFAULT) < 0)
|
||||
goto fail;
|
||||
if (g_dev_ext != nullptr) {
|
||||
fd = open(HMC5883L_DEVICE_PATH_EXT, O_RDONLY);
|
||||
if (fd < 0)
|
||||
goto fail;
|
||||
|
||||
if (ioctl(fd, SENSORIOCSPOLLRATE, SENSOR_POLLRATE_DEFAULT) < 0)
|
||||
goto fail;
|
||||
close(fd);
|
||||
}
|
||||
|
||||
exit(0);
|
||||
|
||||
fail:
|
||||
|
||||
if (g_dev != nullptr) {
|
||||
delete g_dev;
|
||||
g_dev = nullptr;
|
||||
if (g_dev_int != nullptr && (bus == -1 || bus == PX4_I2C_BUS_ONBOARD)) {
|
||||
delete g_dev_int;
|
||||
g_dev_int = nullptr;
|
||||
}
|
||||
if (g_dev_ext != nullptr && (bus == -1 || bus == PX4_I2C_BUS_EXPANSION)) {
|
||||
delete g_dev_ext;
|
||||
g_dev_ext = nullptr;
|
||||
}
|
||||
|
||||
errx(1, "driver start failed");
|
||||
@@ -1312,16 +1462,17 @@ fail:
|
||||
* and automatic modes.
|
||||
*/
|
||||
void
|
||||
test()
|
||||
test(int bus)
|
||||
{
|
||||
struct mag_report report;
|
||||
ssize_t sz;
|
||||
int ret;
|
||||
const char *path = (bus==PX4_I2C_BUS_ONBOARD?HMC5883L_DEVICE_PATH_INT:HMC5883L_DEVICE_PATH_EXT);
|
||||
|
||||
int fd = open(HMC5883L_DEVICE_PATH, O_RDONLY);
|
||||
int fd = open(path, O_RDONLY);
|
||||
|
||||
if (fd < 0)
|
||||
err(1, "%s open failed (try 'hmc5883 start' if the driver is not running", HMC5883L_DEVICE_PATH);
|
||||
err(1, "%s open failed (try 'hmc5883 start')", path);
|
||||
|
||||
/* do a simple demand read */
|
||||
sz = read(fd, &report, sizeof(report));
|
||||
@@ -1414,14 +1565,15 @@ test()
|
||||
* configuration register A back to 00 (Normal Measurement Mode), e.g. 0x10.
|
||||
* Using the self test method described above, the user can scale sensor
|
||||
*/
|
||||
int calibrate()
|
||||
int calibrate(int bus)
|
||||
{
|
||||
int ret;
|
||||
const char *path = (bus==PX4_I2C_BUS_ONBOARD?HMC5883L_DEVICE_PATH_INT:HMC5883L_DEVICE_PATH_EXT);
|
||||
|
||||
int fd = open(HMC5883L_DEVICE_PATH, O_RDONLY);
|
||||
int fd = open(path, O_RDONLY);
|
||||
|
||||
if (fd < 0)
|
||||
err(1, "%s open failed (try 'hmc5883 start' if the driver is not running", HMC5883L_DEVICE_PATH);
|
||||
err(1, "%s open failed (try 'hmc5883 start' if the driver is not running", path);
|
||||
|
||||
if (OK != (ret = ioctl(fd, MAGIOCCALIBRATE, fd))) {
|
||||
warnx("failed to enable sensor calibration mode");
|
||||
@@ -1441,9 +1593,11 @@ int calibrate()
|
||||
* Reset the driver.
|
||||
*/
|
||||
void
|
||||
reset()
|
||||
reset(int bus)
|
||||
{
|
||||
int fd = open(HMC5883L_DEVICE_PATH, O_RDONLY);
|
||||
const char *path = (bus==PX4_I2C_BUS_ONBOARD?HMC5883L_DEVICE_PATH_INT:HMC5883L_DEVICE_PATH_EXT);
|
||||
|
||||
int fd = open(path, O_RDONLY);
|
||||
|
||||
if (fd < 0)
|
||||
err(1, "failed ");
|
||||
@@ -1461,8 +1615,9 @@ reset()
|
||||
* Print a little info about the driver.
|
||||
*/
|
||||
void
|
||||
info()
|
||||
info(int bus)
|
||||
{
|
||||
HMC5883 *g_dev = (bus == PX4_I2C_BUS_ONBOARD?g_dev_int:g_dev_ext);
|
||||
if (g_dev == nullptr)
|
||||
errx(1, "driver not running");
|
||||
|
||||
@@ -1472,40 +1627,91 @@ info()
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void
|
||||
usage()
|
||||
{
|
||||
warnx("missing command: try 'start', 'info', 'test', 'reset', 'info', 'calibrate'");
|
||||
warnx("options:");
|
||||
warnx(" -R rotation");
|
||||
warnx(" -C calibrate on start");
|
||||
warnx(" -X only external bus");
|
||||
#ifdef PX4_I2C_BUS_ONBOARD
|
||||
warnx(" -I only internal bus");
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int
|
||||
hmc5883_main(int argc, char *argv[])
|
||||
{
|
||||
int ch;
|
||||
int bus = -1;
|
||||
enum Rotation rotation = ROTATION_NONE;
|
||||
bool calibrate = false;
|
||||
|
||||
while ((ch = getopt(argc, argv, "XIR:C")) != EOF) {
|
||||
switch (ch) {
|
||||
case 'R':
|
||||
rotation = (enum Rotation)atoi(optarg);
|
||||
break;
|
||||
#ifdef PX4_I2C_BUS_ONBOARD
|
||||
case 'I':
|
||||
bus = PX4_I2C_BUS_ONBOARD;
|
||||
break;
|
||||
#endif
|
||||
case 'X':
|
||||
bus = PX4_I2C_BUS_EXPANSION;
|
||||
break;
|
||||
case 'C':
|
||||
calibrate = true;
|
||||
break;
|
||||
default:
|
||||
hmc5883::usage();
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
const char *verb = argv[optind];
|
||||
|
||||
/*
|
||||
* Start/load the driver.
|
||||
*/
|
||||
if (!strcmp(argv[1], "start"))
|
||||
hmc5883::start();
|
||||
if (!strcmp(verb, "start")) {
|
||||
hmc5883::start(bus, rotation);
|
||||
if (calibrate) {
|
||||
if (hmc5883::calibrate(bus) == 0) {
|
||||
errx(0, "calibration successful");
|
||||
|
||||
} else {
|
||||
errx(1, "calibration failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Test the driver/device.
|
||||
*/
|
||||
if (!strcmp(argv[1], "test"))
|
||||
hmc5883::test();
|
||||
if (!strcmp(verb, "test"))
|
||||
hmc5883::test(bus);
|
||||
|
||||
/*
|
||||
* Reset the driver.
|
||||
*/
|
||||
if (!strcmp(argv[1], "reset"))
|
||||
hmc5883::reset();
|
||||
if (!strcmp(verb, "reset"))
|
||||
hmc5883::reset(bus);
|
||||
|
||||
/*
|
||||
* Print driver information.
|
||||
*/
|
||||
if (!strcmp(argv[1], "info") || !strcmp(argv[1], "status"))
|
||||
hmc5883::info();
|
||||
if (!strcmp(verb, "info") || !strcmp(verb, "status"))
|
||||
hmc5883::info(bus);
|
||||
|
||||
/*
|
||||
* Autocalibrate the scaling
|
||||
*/
|
||||
if (!strcmp(argv[1], "calibrate")) {
|
||||
if (hmc5883::calibrate() == 0) {
|
||||
if (!strcmp(verb, "calibrate")) {
|
||||
if (hmc5883::calibrate(bus) == 0) {
|
||||
errx(0, "calibration successful");
|
||||
|
||||
} else {
|
||||
|
||||
@@ -37,7 +37,8 @@
|
||||
|
||||
MODULE_COMMAND = hmc5883
|
||||
|
||||
# XXX seems excessive, check if 2048 is sufficient
|
||||
MODULE_STACKSIZE = 4096
|
||||
|
||||
SRCS = hmc5883.cpp
|
||||
|
||||
MODULE_STACKSIZE = 1200
|
||||
|
||||
EXTRACXXFLAGS = -Weffc++
|
||||
|
||||
@@ -40,3 +40,5 @@ MODULE_COMMAND = hott_sensors
|
||||
SRCS = hott_sensors.cpp \
|
||||
../messages.cpp \
|
||||
../comms.cpp
|
||||
|
||||
MAXOPTIMIZATION = -Os
|
||||
|
||||
@@ -40,3 +40,5 @@ MODULE_COMMAND = hott_telemetry
|
||||
SRCS = hott_telemetry.cpp \
|
||||
../messages.cpp \
|
||||
../comms.cpp
|
||||
|
||||
MAXOPTIMIZATION = -Os
|
||||
|
||||
@@ -54,6 +54,7 @@
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <unistd.h>
|
||||
#include <getopt.h>
|
||||
|
||||
#include <systemlib/perf_counter.h>
|
||||
#include <systemlib/err.h>
|
||||
@@ -68,6 +69,7 @@
|
||||
|
||||
#include <board_config.h>
|
||||
#include <mathlib/math/filter/LowPassFilter2p.hpp>
|
||||
#include <lib/conversion/rotation.h>
|
||||
|
||||
#define L3GD20_DEVICE_PATH "/dev/l3gd20"
|
||||
|
||||
@@ -184,7 +186,7 @@ extern "C" { __EXPORT int l3gd20_main(int argc, char *argv[]); }
|
||||
class L3GD20 : public device::SPI
|
||||
{
|
||||
public:
|
||||
L3GD20(int bus, const char* path, spi_dev_e device);
|
||||
L3GD20(int bus, const char* path, spi_dev_e device, enum Rotation rotation);
|
||||
virtual ~L3GD20();
|
||||
|
||||
virtual int init();
|
||||
@@ -211,6 +213,7 @@ private:
|
||||
float _gyro_range_scale;
|
||||
float _gyro_range_rad_s;
|
||||
orb_advert_t _gyro_topic;
|
||||
orb_id_t _orb_id;
|
||||
int _class_instance;
|
||||
|
||||
unsigned _current_rate;
|
||||
@@ -229,6 +232,8 @@ private:
|
||||
/* true if an L3G4200D is detected */
|
||||
bool _is_l3g4200d;
|
||||
|
||||
enum Rotation _rotation;
|
||||
|
||||
/**
|
||||
* Start automatic measurement.
|
||||
*/
|
||||
@@ -326,15 +331,22 @@ private:
|
||||
* @return 0 on success, 1 on failure
|
||||
*/
|
||||
int self_test();
|
||||
|
||||
/* this class does not allow copying */
|
||||
L3GD20(const L3GD20&);
|
||||
L3GD20 operator=(const L3GD20&);
|
||||
};
|
||||
|
||||
L3GD20::L3GD20(int bus, const char* path, spi_dev_e device) :
|
||||
L3GD20::L3GD20(int bus, const char* path, spi_dev_e device, enum Rotation rotation) :
|
||||
SPI("L3GD20", path, bus, device, SPIDEV_MODE3, 11*1000*1000 /* will be rounded to 10.4 MHz, within margins for L3GD20 */),
|
||||
_call{},
|
||||
_call_interval(0),
|
||||
_reports(nullptr),
|
||||
_gyro_scale{},
|
||||
_gyro_range_scale(0.0f),
|
||||
_gyro_range_rad_s(0.0f),
|
||||
_gyro_topic(-1),
|
||||
_orb_id(nullptr),
|
||||
_class_instance(-1),
|
||||
_current_rate(0),
|
||||
_orientation(SENSOR_BOARD_ROTATION_DEFAULT),
|
||||
@@ -345,7 +357,8 @@ L3GD20::L3GD20(int bus, const char* path, spi_dev_e device) :
|
||||
_gyro_filter_x(L3GD20_DEFAULT_RATE, L3GD20_DEFAULT_FILTER_FREQ),
|
||||
_gyro_filter_y(L3GD20_DEFAULT_RATE, L3GD20_DEFAULT_FILTER_FREQ),
|
||||
_gyro_filter_z(L3GD20_DEFAULT_RATE, L3GD20_DEFAULT_FILTER_FREQ),
|
||||
_is_l3g4200d(false)
|
||||
_is_l3g4200d(false),
|
||||
_rotation(rotation)
|
||||
{
|
||||
// enable debug() calls
|
||||
_debug_enabled = true;
|
||||
@@ -394,21 +407,32 @@ L3GD20::init()
|
||||
|
||||
_class_instance = register_class_devname(GYRO_DEVICE_PATH);
|
||||
|
||||
switch (_class_instance) {
|
||||
case CLASS_DEVICE_PRIMARY:
|
||||
_orb_id = ORB_ID(sensor_gyro0);
|
||||
break;
|
||||
|
||||
case CLASS_DEVICE_SECONDARY:
|
||||
_orb_id = ORB_ID(sensor_gyro1);
|
||||
break;
|
||||
|
||||
case CLASS_DEVICE_TERTIARY:
|
||||
_orb_id = ORB_ID(sensor_gyro2);
|
||||
break;
|
||||
}
|
||||
|
||||
reset();
|
||||
|
||||
measure();
|
||||
|
||||
if (_class_instance == CLASS_DEVICE_PRIMARY) {
|
||||
/* advertise sensor topic, measure manually to initialize valid report */
|
||||
struct gyro_report grp;
|
||||
_reports->get(&grp);
|
||||
|
||||
/* advertise sensor topic, measure manually to initialize valid report */
|
||||
struct gyro_report grp;
|
||||
_reports->get(&grp);
|
||||
|
||||
_gyro_topic = orb_advertise(ORB_ID(sensor_gyro), &grp);
|
||||
|
||||
if (_gyro_topic < 0)
|
||||
debug("failed to create sensor_gyro publication");
|
||||
_gyro_topic = orb_advertise(_orb_id, &grp);
|
||||
|
||||
if (_gyro_topic < 0) {
|
||||
debug("failed to create sensor_gyro publication");
|
||||
}
|
||||
|
||||
ret = OK;
|
||||
@@ -821,7 +845,7 @@ L3GD20::measure()
|
||||
// if the gyro doesn't have any data ready then re-schedule
|
||||
// for 100 microseconds later. This ensures we don't double
|
||||
// read a value and then miss the next value
|
||||
if (stm32_gpioread(GPIO_EXTI_GYRO_DRDY) == 0) {
|
||||
if (_bus == PX4_SPI_BUS_SENSORS && stm32_gpioread(GPIO_EXTI_GYRO_DRDY) == 0) {
|
||||
perf_count(_reschedules);
|
||||
hrt_call_delay(&_call, 100);
|
||||
return;
|
||||
@@ -914,6 +938,9 @@ L3GD20::measure()
|
||||
report.y = _gyro_filter_y.apply(report.y);
|
||||
report.z = _gyro_filter_z.apply(report.z);
|
||||
|
||||
// apply user specified rotation
|
||||
rotate_3f(_rotation, report.x, report.y, report.z);
|
||||
|
||||
report.scaling = _gyro_range_scale;
|
||||
report.range_rad_s = _gyro_range_rad_s;
|
||||
|
||||
@@ -923,9 +950,9 @@ L3GD20::measure()
|
||||
poll_notify(POLLIN);
|
||||
|
||||
/* publish for subscribers */
|
||||
if (_gyro_topic > 0 && !(_pub_blocked)) {
|
||||
if (!(_pub_blocked)) {
|
||||
/* publish it */
|
||||
orb_publish(ORB_ID(sensor_gyro), _gyro_topic, &report);
|
||||
orb_publish(_orb_id, _gyro_topic, &report);
|
||||
}
|
||||
|
||||
_read++;
|
||||
@@ -974,16 +1001,20 @@ namespace l3gd20
|
||||
|
||||
L3GD20 *g_dev;
|
||||
|
||||
void start();
|
||||
void usage();
|
||||
void start(bool external_bus, enum Rotation rotation);
|
||||
void test();
|
||||
void reset();
|
||||
void info();
|
||||
|
||||
/**
|
||||
* Start the driver.
|
||||
*
|
||||
* This function call only returns once the driver
|
||||
* started or failed to detect the sensor.
|
||||
*/
|
||||
void
|
||||
start()
|
||||
start(bool external_bus, enum Rotation rotation)
|
||||
{
|
||||
int fd;
|
||||
|
||||
@@ -991,7 +1022,15 @@ start()
|
||||
errx(0, "already started");
|
||||
|
||||
/* create the driver */
|
||||
g_dev = new L3GD20(PX4_SPI_BUS_SENSORS, L3GD20_DEVICE_PATH, (spi_dev_e)PX4_SPIDEV_GYRO);
|
||||
if (external_bus) {
|
||||
#ifdef PX4_SPI_BUS_EXT
|
||||
g_dev = new L3GD20(PX4_SPI_BUS_EXT, L3GD20_DEVICE_PATH, (spi_dev_e)PX4_SPIDEV_EXT_GYRO, rotation);
|
||||
#else
|
||||
errx(0, "External SPI not available");
|
||||
#endif
|
||||
} else {
|
||||
g_dev = new L3GD20(PX4_SPI_BUS_SENSORS, L3GD20_DEVICE_PATH, (spi_dev_e)PX4_SPIDEV_GYRO, rotation);
|
||||
}
|
||||
|
||||
if (g_dev == nullptr)
|
||||
goto fail;
|
||||
@@ -1103,35 +1142,64 @@ info()
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void
|
||||
usage()
|
||||
{
|
||||
warnx("missing command: try 'start', 'info', 'test', 'reset'");
|
||||
warnx("options:");
|
||||
warnx(" -X (external bus)");
|
||||
warnx(" -R rotation");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int
|
||||
l3gd20_main(int argc, char *argv[])
|
||||
{
|
||||
bool external_bus = false;
|
||||
int ch;
|
||||
enum Rotation rotation = ROTATION_NONE;
|
||||
|
||||
/* jump over start/off/etc and look at options first */
|
||||
while ((ch = getopt(argc, argv, "XR:")) != EOF) {
|
||||
switch (ch) {
|
||||
case 'X':
|
||||
external_bus = true;
|
||||
break;
|
||||
case 'R':
|
||||
rotation = (enum Rotation)atoi(optarg);
|
||||
break;
|
||||
default:
|
||||
l3gd20::usage();
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
const char *verb = argv[optind];
|
||||
|
||||
/*
|
||||
* Start/load the driver.
|
||||
|
||||
*/
|
||||
if (!strcmp(argv[1], "start"))
|
||||
l3gd20::start();
|
||||
if (!strcmp(verb, "start"))
|
||||
l3gd20::start(external_bus, rotation);
|
||||
|
||||
/*
|
||||
* Test the driver/device.
|
||||
*/
|
||||
if (!strcmp(argv[1], "test"))
|
||||
if (!strcmp(verb, "test"))
|
||||
l3gd20::test();
|
||||
|
||||
/*
|
||||
* Reset the driver.
|
||||
*/
|
||||
if (!strcmp(argv[1], "reset"))
|
||||
if (!strcmp(verb, "reset"))
|
||||
l3gd20::reset();
|
||||
|
||||
/*
|
||||
* Print driver information.
|
||||
*/
|
||||
if (!strcmp(argv[1], "info"))
|
||||
if (!strcmp(verb, "info"))
|
||||
l3gd20::info();
|
||||
|
||||
errx(1, "unrecognized command, try 'start', 'test', 'reset' or 'info'");
|
||||
|
||||
@@ -4,3 +4,7 @@
|
||||
|
||||
MODULE_COMMAND = l3gd20
|
||||
SRCS = l3gd20.cpp
|
||||
|
||||
MODULE_STACKSIZE = 1200
|
||||
|
||||
EXTRACXXFLAGS = -Weffc++
|
||||
|
||||
@@ -36,3 +36,5 @@
|
||||
#
|
||||
|
||||
SRCS = led.cpp
|
||||
|
||||
MAXOPTIMIZATION = -Os
|
||||
|
||||
@@ -0,0 +1,882 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2013 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.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/**
|
||||
* @file ll40ls.cpp
|
||||
* @author Allyson Kreft
|
||||
*
|
||||
* Driver for the PulsedLight Lidar-Lite range finders connected via I2C.
|
||||
*/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <drivers/device/i2c.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <semaphore.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <poll.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <nuttx/arch.h>
|
||||
#include <nuttx/wqueue.h>
|
||||
#include <nuttx/clock.h>
|
||||
|
||||
#include <systemlib/perf_counter.h>
|
||||
#include <systemlib/err.h>
|
||||
|
||||
#include <drivers/drv_hrt.h>
|
||||
#include <drivers/drv_range_finder.h>
|
||||
#include <drivers/device/ringbuffer.h>
|
||||
|
||||
#include <uORB/uORB.h>
|
||||
#include <uORB/topics/subsystem_info.h>
|
||||
|
||||
#include <board_config.h>
|
||||
|
||||
/* Configuration Constants */
|
||||
#define LL40LS_BUS PX4_I2C_BUS_EXPANSION
|
||||
#define LL40LS_BASEADDR 0x42 /* 7-bit address */
|
||||
#define LL40LS_DEVICE_PATH "/dev/ll40ls"
|
||||
|
||||
/* LL40LS Registers addresses */
|
||||
|
||||
#define LL40LS_MEASURE_REG 0x00 /* Measure range register */
|
||||
#define LL40LS_MSRREG_ACQUIRE 0x04 /* Value to initiate a measurement, varies based on sensor revision */
|
||||
#define LL40LS_DISTHIGH_REG 0x8F /* High byte of distance register, auto increment */
|
||||
|
||||
/* Device limits */
|
||||
#define LL40LS_MIN_DISTANCE (0.00f)
|
||||
#define LL40LS_MAX_DISTANCE (14.00f)
|
||||
|
||||
#define LL40LS_CONVERSION_INTERVAL 100000 /* 100ms */
|
||||
|
||||
/* oddly, ERROR is not defined for c++ */
|
||||
#ifdef ERROR
|
||||
# undef ERROR
|
||||
#endif
|
||||
static const int ERROR = -1;
|
||||
|
||||
#ifndef CONFIG_SCHED_WORKQUEUE
|
||||
# error This requires CONFIG_SCHED_WORKQUEUE.
|
||||
#endif
|
||||
|
||||
class LL40LS : public device::I2C
|
||||
{
|
||||
public:
|
||||
LL40LS(int bus = LL40LS_BUS, int address = LL40LS_BASEADDR);
|
||||
virtual ~LL40LS();
|
||||
|
||||
virtual int init();
|
||||
|
||||
virtual ssize_t read(struct file *filp, char *buffer, size_t buflen);
|
||||
virtual int ioctl(struct file *filp, int cmd, unsigned long arg);
|
||||
|
||||
/**
|
||||
* Diagnostics - print some basic information about the driver.
|
||||
*/
|
||||
void print_info();
|
||||
|
||||
protected:
|
||||
virtual int probe();
|
||||
|
||||
private:
|
||||
float _min_distance;
|
||||
float _max_distance;
|
||||
work_s _work;
|
||||
RingBuffer *_reports;
|
||||
bool _sensor_ok;
|
||||
int _measure_ticks;
|
||||
bool _collect_phase;
|
||||
int _class_instance;
|
||||
|
||||
orb_advert_t _range_finder_topic;
|
||||
|
||||
perf_counter_t _sample_perf;
|
||||
perf_counter_t _comms_errors;
|
||||
perf_counter_t _buffer_overflows;
|
||||
|
||||
/**
|
||||
* Test whether the device supported by the driver is present at a
|
||||
* specific address.
|
||||
*
|
||||
* @param address The I2C bus address to probe.
|
||||
* @return True if the device is present.
|
||||
*/
|
||||
int probe_address(uint8_t address);
|
||||
|
||||
/**
|
||||
* Initialise the automatic measurement state machine and start it.
|
||||
*
|
||||
* @note This function is called at open and error time. It might make sense
|
||||
* to make it more aggressive about resetting the bus in case of errors.
|
||||
*/
|
||||
void start();
|
||||
|
||||
/**
|
||||
* Stop the automatic measurement state machine.
|
||||
*/
|
||||
void stop();
|
||||
|
||||
/**
|
||||
* Set the min and max distance thresholds if you want the end points of the sensors
|
||||
* range to be brought in at all, otherwise it will use the defaults LL40LS_MIN_DISTANCE
|
||||
* and LL40LS_MAX_DISTANCE
|
||||
*/
|
||||
void set_minimum_distance(float min);
|
||||
void set_maximum_distance(float max);
|
||||
float get_minimum_distance();
|
||||
float get_maximum_distance();
|
||||
|
||||
/**
|
||||
* Perform a poll cycle; collect from the previous measurement
|
||||
* and start a new one.
|
||||
*/
|
||||
void cycle();
|
||||
int measure();
|
||||
int collect();
|
||||
/**
|
||||
* Static trampoline from the workq context; because we don't have a
|
||||
* generic workq wrapper yet.
|
||||
*
|
||||
* @param arg Instance pointer for the driver that is polling.
|
||||
*/
|
||||
static void cycle_trampoline(void *arg);
|
||||
|
||||
|
||||
};
|
||||
|
||||
/*
|
||||
* Driver 'main' command.
|
||||
*/
|
||||
extern "C" __EXPORT int ll40ls_main(int argc, char *argv[]);
|
||||
|
||||
LL40LS::LL40LS(int bus, int address) :
|
||||
I2C("LL40LS", LL40LS_DEVICE_PATH, bus, address, 100000),
|
||||
_min_distance(LL40LS_MIN_DISTANCE),
|
||||
_max_distance(LL40LS_MAX_DISTANCE),
|
||||
_reports(nullptr),
|
||||
_sensor_ok(false),
|
||||
_measure_ticks(0),
|
||||
_collect_phase(false),
|
||||
_class_instance(-1),
|
||||
_range_finder_topic(-1),
|
||||
_sample_perf(perf_alloc(PC_ELAPSED, "ll40ls_read")),
|
||||
_comms_errors(perf_alloc(PC_COUNT, "ll40ls_comms_errors")),
|
||||
_buffer_overflows(perf_alloc(PC_COUNT, "ll40ls_buffer_overflows"))
|
||||
{
|
||||
// up the retries since the device misses the first measure attempts
|
||||
I2C::_retries = 3;
|
||||
|
||||
// enable debug() calls
|
||||
_debug_enabled = false;
|
||||
|
||||
// work_cancel in the dtor will explode if we don't do this...
|
||||
memset(&_work, 0, sizeof(_work));
|
||||
}
|
||||
|
||||
LL40LS::~LL40LS()
|
||||
{
|
||||
/* make sure we are truly inactive */
|
||||
stop();
|
||||
|
||||
/* free any existing reports */
|
||||
if (_reports != nullptr) {
|
||||
delete _reports;
|
||||
}
|
||||
|
||||
if (_class_instance != -1) {
|
||||
unregister_class_devname(RANGE_FINDER_DEVICE_PATH, _class_instance);
|
||||
}
|
||||
|
||||
// free perf counters
|
||||
perf_free(_sample_perf);
|
||||
perf_free(_comms_errors);
|
||||
perf_free(_buffer_overflows);
|
||||
}
|
||||
|
||||
int
|
||||
LL40LS::init()
|
||||
{
|
||||
int ret = ERROR;
|
||||
|
||||
/* do I2C init (and probe) first */
|
||||
if (I2C::init() != OK) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* allocate basic report buffers */
|
||||
_reports = new RingBuffer(2, sizeof(range_finder_report));
|
||||
|
||||
if (_reports == nullptr) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
_class_instance = register_class_devname(RANGE_FINDER_DEVICE_PATH);
|
||||
|
||||
if (_class_instance == CLASS_DEVICE_PRIMARY) {
|
||||
/* get a publish handle on the range finder topic */
|
||||
struct range_finder_report rf_report;
|
||||
measure();
|
||||
_reports->get(&rf_report);
|
||||
_range_finder_topic = orb_advertise(ORB_ID(sensor_range_finder), &rf_report);
|
||||
|
||||
if (_range_finder_topic < 0) {
|
||||
debug("failed to create sensor_range_finder object. Did you start uOrb?");
|
||||
}
|
||||
}
|
||||
|
||||
ret = OK;
|
||||
/* sensor is ok, but we don't really know if it is within range */
|
||||
_sensor_ok = true;
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
LL40LS::probe()
|
||||
{
|
||||
return measure();
|
||||
}
|
||||
|
||||
void
|
||||
LL40LS::set_minimum_distance(float min)
|
||||
{
|
||||
_min_distance = min;
|
||||
}
|
||||
|
||||
void
|
||||
LL40LS::set_maximum_distance(float max)
|
||||
{
|
||||
_max_distance = max;
|
||||
}
|
||||
|
||||
float
|
||||
LL40LS::get_minimum_distance()
|
||||
{
|
||||
return _min_distance;
|
||||
}
|
||||
|
||||
float
|
||||
LL40LS::get_maximum_distance()
|
||||
{
|
||||
return _max_distance;
|
||||
}
|
||||
|
||||
int
|
||||
LL40LS::ioctl(struct file *filp, int cmd, unsigned long arg)
|
||||
{
|
||||
switch (cmd) {
|
||||
|
||||
case SENSORIOCSPOLLRATE: {
|
||||
switch (arg) {
|
||||
|
||||
/* switching to manual polling */
|
||||
case SENSOR_POLLRATE_MANUAL:
|
||||
stop();
|
||||
_measure_ticks = 0;
|
||||
return OK;
|
||||
|
||||
/* external signalling (DRDY) not supported */
|
||||
case SENSOR_POLLRATE_EXTERNAL:
|
||||
|
||||
/* zero would be bad */
|
||||
case 0:
|
||||
return -EINVAL;
|
||||
|
||||
/* set default/max polling rate */
|
||||
case SENSOR_POLLRATE_MAX:
|
||||
case SENSOR_POLLRATE_DEFAULT: {
|
||||
/* do we need to start internal polling? */
|
||||
bool want_start = (_measure_ticks == 0);
|
||||
|
||||
/* set interval for next measurement to minimum legal value */
|
||||
_measure_ticks = USEC2TICK(LL40LS_CONVERSION_INTERVAL);
|
||||
|
||||
/* if we need to start the poll state machine, do it */
|
||||
if (want_start) {
|
||||
start();
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/* adjust to a legal polling interval in Hz */
|
||||
default: {
|
||||
/* do we need to start internal polling? */
|
||||
bool want_start = (_measure_ticks == 0);
|
||||
|
||||
/* convert hz to tick interval via microseconds */
|
||||
unsigned ticks = USEC2TICK(1000000 / arg);
|
||||
|
||||
/* check against maximum rate */
|
||||
if (ticks < USEC2TICK(LL40LS_CONVERSION_INTERVAL)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* update interval for next measurement */
|
||||
_measure_ticks = ticks;
|
||||
|
||||
/* if we need to start the poll state machine, do it */
|
||||
if (want_start) {
|
||||
start();
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case SENSORIOCGPOLLRATE:
|
||||
if (_measure_ticks == 0) {
|
||||
return SENSOR_POLLRATE_MANUAL;
|
||||
}
|
||||
|
||||
return (1000 / _measure_ticks);
|
||||
|
||||
case SENSORIOCSQUEUEDEPTH: {
|
||||
/* lower bound is mandatory, upper bound is a sanity check */
|
||||
if ((arg < 1) || (arg > 100)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
irqstate_t flags = irqsave();
|
||||
|
||||
if (!_reports->resize(arg)) {
|
||||
irqrestore(flags);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
irqrestore(flags);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
case SENSORIOCGQUEUEDEPTH:
|
||||
return _reports->size();
|
||||
|
||||
case SENSORIOCRESET:
|
||||
/* XXX implement this */
|
||||
return -EINVAL;
|
||||
|
||||
case RANGEFINDERIOCSETMINIUMDISTANCE: {
|
||||
set_minimum_distance(*(float *)arg);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case RANGEFINDERIOCSETMAXIUMDISTANCE: {
|
||||
set_maximum_distance(*(float *)arg);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
/* give it to the superclass */
|
||||
return I2C::ioctl(filp, cmd, arg);
|
||||
}
|
||||
}
|
||||
|
||||
ssize_t
|
||||
LL40LS::read(struct file *filp, char *buffer, size_t buflen)
|
||||
{
|
||||
unsigned count = buflen / sizeof(struct range_finder_report);
|
||||
struct range_finder_report *rbuf = reinterpret_cast<struct range_finder_report *>(buffer);
|
||||
int ret = 0;
|
||||
|
||||
/* buffer must be large enough */
|
||||
if (count < 1) {
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
/* if automatic measurement is enabled */
|
||||
if (_measure_ticks > 0) {
|
||||
|
||||
/*
|
||||
* While there is space in the caller's buffer, and reports, copy them.
|
||||
* Note that we may be pre-empted by the workq thread while we are doing this;
|
||||
* we are careful to avoid racing with them.
|
||||
*/
|
||||
while (count--) {
|
||||
if (_reports->get(rbuf)) {
|
||||
ret += sizeof(*rbuf);
|
||||
rbuf++;
|
||||
}
|
||||
}
|
||||
|
||||
/* if there was no data, warn the caller */
|
||||
return ret ? ret : -EAGAIN;
|
||||
}
|
||||
|
||||
/* manual measurement - run one conversion */
|
||||
do {
|
||||
_reports->flush();
|
||||
|
||||
/* trigger a measurement */
|
||||
if (OK != measure()) {
|
||||
ret = -EIO;
|
||||
break;
|
||||
}
|
||||
|
||||
/* wait for it to complete */
|
||||
usleep(LL40LS_CONVERSION_INTERVAL);
|
||||
|
||||
/* run the collection phase */
|
||||
if (OK != collect()) {
|
||||
ret = -EIO;
|
||||
break;
|
||||
}
|
||||
|
||||
/* state machine will have generated a report, copy it out */
|
||||
if (_reports->get(rbuf)) {
|
||||
ret = sizeof(*rbuf);
|
||||
}
|
||||
|
||||
} while (0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
LL40LS::measure()
|
||||
{
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Send the command to begin a measurement.
|
||||
*/
|
||||
const uint8_t cmd[2] = { LL40LS_MEASURE_REG, LL40LS_MSRREG_ACQUIRE };
|
||||
ret = transfer(cmd, sizeof(cmd), nullptr, 0);
|
||||
|
||||
if (OK != ret) {
|
||||
perf_count(_comms_errors);
|
||||
log("i2c::transfer returned %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = OK;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
LL40LS::collect()
|
||||
{
|
||||
int ret = -EIO;
|
||||
|
||||
/* read from the sensor */
|
||||
uint8_t val[2] = {0, 0};
|
||||
|
||||
perf_begin(_sample_perf);
|
||||
|
||||
// read the high and low byte distance registers
|
||||
uint8_t distance_reg = LL40LS_DISTHIGH_REG;
|
||||
ret = transfer(&distance_reg, 1, &val[0], sizeof(val));
|
||||
|
||||
if (ret < 0) {
|
||||
log("error reading from sensor: %d", ret);
|
||||
perf_count(_comms_errors);
|
||||
perf_end(_sample_perf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint16_t distance = (val[0] << 8) | val[1];
|
||||
float si_units = distance * 0.01f; /* cm to m */
|
||||
struct range_finder_report report;
|
||||
|
||||
/* this should be fairly close to the end of the measurement, so the best approximation of the time */
|
||||
report.timestamp = hrt_absolute_time();
|
||||
report.error_count = perf_event_count(_comms_errors);
|
||||
report.distance = si_units;
|
||||
if (si_units > get_minimum_distance() && si_units < get_maximum_distance()) {
|
||||
report.valid = 1;
|
||||
}
|
||||
else {
|
||||
report.valid = 0;
|
||||
}
|
||||
|
||||
/* publish it, if we are the primary */
|
||||
if (_range_finder_topic >= 0) {
|
||||
orb_publish(ORB_ID(sensor_range_finder), _range_finder_topic, &report);
|
||||
}
|
||||
|
||||
if (_reports->force(&report)) {
|
||||
perf_count(_buffer_overflows);
|
||||
}
|
||||
|
||||
/* notify anyone waiting for data */
|
||||
poll_notify(POLLIN);
|
||||
|
||||
ret = OK;
|
||||
|
||||
perf_end(_sample_perf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
LL40LS::start()
|
||||
{
|
||||
/* reset the report ring and state machine */
|
||||
_collect_phase = false;
|
||||
_reports->flush();
|
||||
|
||||
/* schedule a cycle to start things */
|
||||
work_queue(HPWORK, &_work, (worker_t)&LL40LS::cycle_trampoline, this, 1);
|
||||
|
||||
/* notify about state change */
|
||||
struct subsystem_info_s info = {
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
SUBSYSTEM_TYPE_RANGEFINDER
|
||||
};
|
||||
static orb_advert_t pub = -1;
|
||||
|
||||
if (pub > 0) {
|
||||
orb_publish(ORB_ID(subsystem_info), pub, &info);
|
||||
|
||||
} else {
|
||||
pub = orb_advertise(ORB_ID(subsystem_info), &info);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
LL40LS::stop()
|
||||
{
|
||||
work_cancel(HPWORK, &_work);
|
||||
}
|
||||
|
||||
void
|
||||
LL40LS::cycle_trampoline(void *arg)
|
||||
{
|
||||
LL40LS *dev = (LL40LS *)arg;
|
||||
|
||||
dev->cycle();
|
||||
}
|
||||
|
||||
void
|
||||
LL40LS::cycle()
|
||||
{
|
||||
/* collection phase? */
|
||||
if (_collect_phase) {
|
||||
|
||||
/* perform collection */
|
||||
if (OK != collect()) {
|
||||
log("collection error");
|
||||
/* restart the measurement state machine */
|
||||
start();
|
||||
return;
|
||||
}
|
||||
|
||||
/* next phase is measurement */
|
||||
_collect_phase = false;
|
||||
|
||||
/*
|
||||
* Is there a collect->measure gap?
|
||||
*/
|
||||
if (_measure_ticks > USEC2TICK(LL40LS_CONVERSION_INTERVAL)) {
|
||||
|
||||
/* schedule a fresh cycle call when we are ready to measure again */
|
||||
work_queue(HPWORK,
|
||||
&_work,
|
||||
(worker_t)&LL40LS::cycle_trampoline,
|
||||
this,
|
||||
_measure_ticks - USEC2TICK(LL40LS_CONVERSION_INTERVAL));
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* measurement phase */
|
||||
if (OK != measure()) {
|
||||
log("measure error");
|
||||
}
|
||||
|
||||
/* next phase is collection */
|
||||
_collect_phase = true;
|
||||
|
||||
/* schedule a fresh cycle call when the measurement is done */
|
||||
work_queue(HPWORK,
|
||||
&_work,
|
||||
(worker_t)&LL40LS::cycle_trampoline,
|
||||
this,
|
||||
USEC2TICK(LL40LS_CONVERSION_INTERVAL));
|
||||
}
|
||||
|
||||
void
|
||||
LL40LS::print_info()
|
||||
{
|
||||
perf_print_counter(_sample_perf);
|
||||
perf_print_counter(_comms_errors);
|
||||
perf_print_counter(_buffer_overflows);
|
||||
printf("poll interval: %u ticks\n", _measure_ticks);
|
||||
_reports->print_info("report queue");
|
||||
}
|
||||
|
||||
/**
|
||||
* Local functions in support of the shell command.
|
||||
*/
|
||||
namespace ll40ls
|
||||
{
|
||||
|
||||
/* oddly, ERROR is not defined for c++ */
|
||||
#ifdef ERROR
|
||||
# undef ERROR
|
||||
#endif
|
||||
const int ERROR = -1;
|
||||
|
||||
LL40LS *g_dev;
|
||||
|
||||
void start();
|
||||
void stop();
|
||||
void test();
|
||||
void reset();
|
||||
void info();
|
||||
|
||||
/**
|
||||
* Start the driver.
|
||||
*/
|
||||
void
|
||||
start()
|
||||
{
|
||||
int fd;
|
||||
|
||||
if (g_dev != nullptr) {
|
||||
errx(1, "already started");
|
||||
}
|
||||
|
||||
/* create the driver */
|
||||
g_dev = new LL40LS(LL40LS_BUS);
|
||||
|
||||
if (g_dev == nullptr) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (OK != g_dev->init()) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* set the poll rate to default, starts automatic data collection */
|
||||
fd = open(LL40LS_DEVICE_PATH, O_RDONLY);
|
||||
|
||||
if (fd < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (ioctl(fd, SENSORIOCSPOLLRATE, SENSOR_POLLRATE_DEFAULT) < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
exit(0);
|
||||
|
||||
fail:
|
||||
|
||||
if (g_dev != nullptr) {
|
||||
delete g_dev;
|
||||
g_dev = nullptr;
|
||||
}
|
||||
|
||||
errx(1, "driver start failed");
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop the driver
|
||||
*/
|
||||
void stop()
|
||||
{
|
||||
if (g_dev != nullptr) {
|
||||
delete g_dev;
|
||||
g_dev = nullptr;
|
||||
|
||||
} else {
|
||||
errx(1, "driver not running");
|
||||
}
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform some basic functional tests on the driver;
|
||||
* make sure we can collect data from the sensor in polled
|
||||
* and automatic modes.
|
||||
*/
|
||||
void
|
||||
test()
|
||||
{
|
||||
struct range_finder_report report;
|
||||
ssize_t sz;
|
||||
int ret;
|
||||
|
||||
int fd = open(LL40LS_DEVICE_PATH, O_RDONLY);
|
||||
|
||||
if (fd < 0) {
|
||||
err(1, "%s open failed (try 'll40ls start' if the driver is not running", LL40LS_DEVICE_PATH);
|
||||
}
|
||||
|
||||
/* do a simple demand read */
|
||||
sz = read(fd, &report, sizeof(report));
|
||||
|
||||
if (sz != sizeof(report)) {
|
||||
err(1, "immediate read failed");
|
||||
}
|
||||
|
||||
warnx("single read");
|
||||
warnx("measurement: %0.2f m", (double)report.distance);
|
||||
warnx("time: %lld", report.timestamp);
|
||||
|
||||
/* start the sensor polling at 2Hz */
|
||||
if (OK != ioctl(fd, SENSORIOCSPOLLRATE, 2)) {
|
||||
errx(1, "failed to set 2Hz poll rate");
|
||||
}
|
||||
|
||||
/* read the sensor 5x and report each value */
|
||||
for (unsigned i = 0; i < 5; i++) {
|
||||
struct pollfd fds;
|
||||
|
||||
/* wait for data to be ready */
|
||||
fds.fd = fd;
|
||||
fds.events = POLLIN;
|
||||
ret = poll(&fds, 1, 2000);
|
||||
|
||||
if (ret != 1) {
|
||||
errx(1, "timed out waiting for sensor data");
|
||||
}
|
||||
|
||||
/* now go get it */
|
||||
sz = read(fd, &report, sizeof(report));
|
||||
|
||||
if (sz != sizeof(report)) {
|
||||
err(1, "periodic read failed");
|
||||
}
|
||||
|
||||
warnx("periodic read %u", i);
|
||||
warnx("measurement: %0.3f", (double)report.distance);
|
||||
warnx("time: %lld", report.timestamp);
|
||||
}
|
||||
|
||||
/* reset the sensor polling to default rate */
|
||||
if (OK != ioctl(fd, SENSORIOCSPOLLRATE, SENSOR_POLLRATE_DEFAULT)) {
|
||||
errx(1, "failed to set default poll rate");
|
||||
}
|
||||
|
||||
errx(0, "PASS");
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the driver.
|
||||
*/
|
||||
void
|
||||
reset()
|
||||
{
|
||||
int fd = open(LL40LS_DEVICE_PATH, O_RDONLY);
|
||||
|
||||
if (fd < 0) {
|
||||
err(1, "failed ");
|
||||
}
|
||||
|
||||
if (ioctl(fd, SENSORIOCRESET, 0) < 0) {
|
||||
err(1, "driver reset failed");
|
||||
}
|
||||
|
||||
if (ioctl(fd, SENSORIOCSPOLLRATE, SENSOR_POLLRATE_DEFAULT) < 0) {
|
||||
err(1, "driver poll restart failed");
|
||||
}
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Print a little info about the driver.
|
||||
*/
|
||||
void
|
||||
info()
|
||||
{
|
||||
if (g_dev == nullptr) {
|
||||
errx(1, "driver not running");
|
||||
}
|
||||
|
||||
printf("state @ %p\n", g_dev);
|
||||
g_dev->print_info();
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int
|
||||
ll40ls_main(int argc, char *argv[])
|
||||
{
|
||||
/*
|
||||
* Start/load the driver.
|
||||
*/
|
||||
if (!strcmp(argv[1], "start")) {
|
||||
ll40ls::start();
|
||||
}
|
||||
|
||||
/*
|
||||
* Stop the driver
|
||||
*/
|
||||
if (!strcmp(argv[1], "stop")) {
|
||||
ll40ls::stop();
|
||||
}
|
||||
|
||||
/*
|
||||
* Test the driver/device.
|
||||
*/
|
||||
if (!strcmp(argv[1], "test")) {
|
||||
ll40ls::test();
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset the driver.
|
||||
*/
|
||||
if (!strcmp(argv[1], "reset")) {
|
||||
ll40ls::reset();
|
||||
}
|
||||
|
||||
/*
|
||||
* Print driver information.
|
||||
*/
|
||||
if (!strcmp(argv[1], "info") || !strcmp(argv[1], "status")) {
|
||||
ll40ls::info();
|
||||
}
|
||||
|
||||
errx(1, "unrecognized command, try 'start', 'test', 'reset' or 'info'");
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
############################################################################
|
||||
#
|
||||
# Copyright (c) 2013 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.
|
||||
#
|
||||
############################################################################
|
||||
|
||||
#
|
||||
# Makefile to build the PulsedLight Lidar-Lite driver.
|
||||
#
|
||||
|
||||
MODULE_COMMAND = ll40ls
|
||||
|
||||
SRCS = ll40ls.cpp
|
||||
|
||||
MAXOPTIMIZATION = -Os
|
||||
+133
-35
@@ -52,6 +52,7 @@
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <unistd.h>
|
||||
#include <getopt.h>
|
||||
|
||||
#include <systemlib/perf_counter.h>
|
||||
#include <systemlib/err.h>
|
||||
@@ -68,6 +69,7 @@
|
||||
|
||||
#include <board_config.h>
|
||||
#include <mathlib/math/filter/LowPassFilter2p.hpp>
|
||||
#include <lib/conversion/rotation.h>
|
||||
|
||||
/* oddly, ERROR is not defined for c++ */
|
||||
#ifdef ERROR
|
||||
@@ -75,12 +77,17 @@
|
||||
#endif
|
||||
static const int ERROR = -1;
|
||||
|
||||
// enable this to debug the buggy lsm303d sensor in very early
|
||||
// prototype pixhawk boards
|
||||
#define CHECK_EXTREMES 0
|
||||
|
||||
/* SPI protocol address bits */
|
||||
#define DIR_READ (1<<7)
|
||||
#define DIR_WRITE (0<<7)
|
||||
#define ADDR_INCREMENT (1<<6)
|
||||
|
||||
#define LSM303D_DEVICE_PATH_ACCEL "/dev/lsm303d_accel"
|
||||
#define LSM303D_DEVICE_PATH_ACCEL_EXT "/dev/lsm303d_accel_ext"
|
||||
#define LSM303D_DEVICE_PATH_MAG "/dev/lsm303d_mag"
|
||||
|
||||
/* register addresses: A: accel, M: mag, T: temp */
|
||||
@@ -216,7 +223,7 @@ class LSM303D_mag;
|
||||
class LSM303D : public device::SPI
|
||||
{
|
||||
public:
|
||||
LSM303D(int bus, const char* path, spi_dev_e device);
|
||||
LSM303D(int bus, const char* path, spi_dev_e device, enum Rotation rotation);
|
||||
virtual ~LSM303D();
|
||||
|
||||
virtual int init();
|
||||
@@ -277,6 +284,7 @@ private:
|
||||
unsigned _mag_samplerate;
|
||||
|
||||
orb_advert_t _accel_topic;
|
||||
orb_id_t _accel_orb_id;
|
||||
int _accel_class_instance;
|
||||
|
||||
unsigned _accel_read;
|
||||
@@ -305,7 +313,8 @@ private:
|
||||
uint64_t _last_log_us;
|
||||
uint64_t _last_log_sync_us;
|
||||
uint64_t _last_log_reg_us;
|
||||
uint64_t _last_log_alarm_us;
|
||||
uint64_t _last_log_alarm_us;
|
||||
enum Rotation _rotation;
|
||||
|
||||
/**
|
||||
* Start automatic measurement.
|
||||
@@ -453,6 +462,10 @@ private:
|
||||
* @return OK if the value can be supported.
|
||||
*/
|
||||
int mag_set_samplerate(unsigned frequency);
|
||||
|
||||
/* this class cannot be copied */
|
||||
LSM303D(const LSM303D&);
|
||||
LSM303D operator=(const LSM303D&);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -477,29 +490,39 @@ private:
|
||||
LSM303D *_parent;
|
||||
|
||||
orb_advert_t _mag_topic;
|
||||
orb_id_t _mag_orb_id;
|
||||
int _mag_class_instance;
|
||||
|
||||
void measure();
|
||||
|
||||
void measure_trampoline(void *arg);
|
||||
|
||||
/* this class does not allow copying due to ptr data members */
|
||||
LSM303D_mag(const LSM303D_mag&);
|
||||
LSM303D_mag operator=(const LSM303D_mag&);
|
||||
};
|
||||
|
||||
|
||||
LSM303D::LSM303D(int bus, const char* path, spi_dev_e device) :
|
||||
LSM303D::LSM303D(int bus, const char* path, spi_dev_e device, enum Rotation rotation) :
|
||||
SPI("LSM303D", path, bus, device, SPIDEV_MODE3, 11*1000*1000 /* will be rounded to 10.4 MHz, within safety margins for LSM303D */),
|
||||
_mag(new LSM303D_mag(this)),
|
||||
_accel_call{},
|
||||
_mag_call{},
|
||||
_call_accel_interval(0),
|
||||
_call_mag_interval(0),
|
||||
_accel_reports(nullptr),
|
||||
_mag_reports(nullptr),
|
||||
_accel_scale{},
|
||||
_accel_range_m_s2(0.0f),
|
||||
_accel_range_scale(0.0f),
|
||||
_accel_samplerate(0),
|
||||
_accel_onchip_filter_bandwith(0),
|
||||
_mag_scale{},
|
||||
_mag_range_ga(0.0f),
|
||||
_mag_range_scale(0.0f),
|
||||
_mag_samplerate(0),
|
||||
_accel_topic(-1),
|
||||
_accel_orb_id(nullptr),
|
||||
_accel_class_instance(-1),
|
||||
_accel_read(0),
|
||||
_mag_read(0),
|
||||
@@ -516,11 +539,15 @@ LSM303D::LSM303D(int bus, const char* path, spi_dev_e device) :
|
||||
_reg7_expected(0),
|
||||
_accel_log_fd(-1),
|
||||
_accel_logging_enabled(false),
|
||||
_last_extreme_us(0),
|
||||
_last_log_us(0),
|
||||
_last_log_sync_us(0),
|
||||
_last_log_reg_us(0),
|
||||
_last_log_alarm_us(0)
|
||||
_last_log_alarm_us(0),
|
||||
_rotation(rotation)
|
||||
{
|
||||
_device_id.devid_s.devtype = DRV_MAG_DEVTYPE_LSM303D;
|
||||
|
||||
// enable debug() calls
|
||||
_debug_enabled = true;
|
||||
|
||||
@@ -600,34 +627,56 @@ LSM303D::init()
|
||||
/* fill report structures */
|
||||
measure();
|
||||
|
||||
if (_mag->_mag_class_instance == CLASS_DEVICE_PRIMARY) {
|
||||
/* advertise sensor topic, measure manually to initialize valid report */
|
||||
struct mag_report mrp;
|
||||
_mag_reports->get(&mrp);
|
||||
|
||||
/* advertise sensor topic, measure manually to initialize valid report */
|
||||
struct mag_report mrp;
|
||||
_mag_reports->get(&mrp);
|
||||
/* measurement will have generated a report, publish */
|
||||
switch (_mag->_mag_class_instance) {
|
||||
case CLASS_DEVICE_PRIMARY:
|
||||
_mag->_mag_orb_id = ORB_ID(sensor_mag0);
|
||||
break;
|
||||
|
||||
/* measurement will have generated a report, publish */
|
||||
_mag->_mag_topic = orb_advertise(ORB_ID(sensor_mag), &mrp);
|
||||
case CLASS_DEVICE_SECONDARY:
|
||||
_mag->_mag_orb_id = ORB_ID(sensor_mag1);
|
||||
break;
|
||||
|
||||
if (_mag->_mag_topic < 0)
|
||||
debug("failed to create sensor_mag publication");
|
||||
case CLASS_DEVICE_TERTIARY:
|
||||
_mag->_mag_orb_id = ORB_ID(sensor_mag2);
|
||||
break;
|
||||
}
|
||||
|
||||
_mag->_mag_topic = orb_advertise(_mag->_mag_orb_id, &mrp);
|
||||
|
||||
if (_mag->_mag_topic < 0) {
|
||||
warnx("ADVERT ERR");
|
||||
}
|
||||
|
||||
_accel_class_instance = register_class_devname(ACCEL_DEVICE_PATH);
|
||||
|
||||
if (_accel_class_instance == CLASS_DEVICE_PRIMARY) {
|
||||
/* advertise sensor topic, measure manually to initialize valid report */
|
||||
struct accel_report arp;
|
||||
_accel_reports->get(&arp);
|
||||
|
||||
/* advertise sensor topic, measure manually to initialize valid report */
|
||||
struct accel_report arp;
|
||||
_accel_reports->get(&arp);
|
||||
/* measurement will have generated a report, publish */
|
||||
switch (_accel_class_instance) {
|
||||
case CLASS_DEVICE_PRIMARY:
|
||||
_accel_orb_id = ORB_ID(sensor_accel0);
|
||||
break;
|
||||
|
||||
/* measurement will have generated a report, publish */
|
||||
_accel_topic = orb_advertise(ORB_ID(sensor_accel), &arp);
|
||||
case CLASS_DEVICE_SECONDARY:
|
||||
_accel_orb_id = ORB_ID(sensor_accel1);
|
||||
break;
|
||||
|
||||
if (_accel_topic < 0)
|
||||
debug("failed to create sensor_accel publication");
|
||||
case CLASS_DEVICE_TERTIARY:
|
||||
_accel_orb_id = ORB_ID(sensor_accel2);
|
||||
break;
|
||||
}
|
||||
|
||||
_accel_topic = orb_advertise(_accel_orb_id, &arp);
|
||||
|
||||
if (_accel_topic < 0) {
|
||||
warnx("ADVERT ERR");
|
||||
}
|
||||
|
||||
out:
|
||||
@@ -830,7 +879,9 @@ LSM303D::read(struct file *filp, char *buffer, size_t buflen)
|
||||
*/
|
||||
while (count--) {
|
||||
if (_accel_reports->get(arb)) {
|
||||
#if CHECK_EXTREMES
|
||||
check_extremes(arb);
|
||||
#endif
|
||||
ret += sizeof(*arb);
|
||||
arb++;
|
||||
}
|
||||
@@ -1533,6 +1584,9 @@ LSM303D::measure()
|
||||
accel_report.y = _accel_filter_y.apply(y_in_new);
|
||||
accel_report.z = _accel_filter_z.apply(z_in_new);
|
||||
|
||||
// apply user specified rotation
|
||||
rotate_3f(_rotation, accel_report.x, accel_report.y, accel_report.z);
|
||||
|
||||
accel_report.scaling = _accel_range_scale;
|
||||
accel_report.range_m_s2 = _accel_range_m_s2;
|
||||
|
||||
@@ -1541,9 +1595,9 @@ LSM303D::measure()
|
||||
/* notify anyone waiting for data */
|
||||
poll_notify(POLLIN);
|
||||
|
||||
if (_accel_topic > 0 && !(_pub_blocked)) {
|
||||
if (!(_pub_blocked)) {
|
||||
/* publish it */
|
||||
orb_publish(ORB_ID(sensor_accel), _accel_topic, &accel_report);
|
||||
orb_publish(_accel_orb_id, _accel_topic, &accel_report);
|
||||
}
|
||||
|
||||
_accel_read++;
|
||||
@@ -1609,15 +1663,18 @@ LSM303D::mag_measure()
|
||||
mag_report.scaling = _mag_range_scale;
|
||||
mag_report.range_ga = (float)_mag_range_ga;
|
||||
|
||||
// apply user specified rotation
|
||||
rotate_3f(_rotation, mag_report.x, mag_report.y, mag_report.z);
|
||||
|
||||
_mag_reports->force(&mag_report);
|
||||
|
||||
/* XXX please check this poll_notify, is it the right one? */
|
||||
/* notify anyone waiting for data */
|
||||
poll_notify(POLLIN);
|
||||
|
||||
if (_mag->_mag_topic > 0 && !(_pub_blocked)) {
|
||||
if (!(_pub_blocked)) {
|
||||
/* publish it */
|
||||
orb_publish(ORB_ID(sensor_mag), _mag->_mag_topic, &mag_report);
|
||||
orb_publish(_mag->_mag_orb_id, _mag->_mag_topic, &mag_report);
|
||||
}
|
||||
|
||||
_mag_read++;
|
||||
@@ -1711,6 +1768,7 @@ LSM303D_mag::LSM303D_mag(LSM303D *parent) :
|
||||
CDev("LSM303D_mag", LSM303D_DEVICE_PATH_MAG),
|
||||
_parent(parent),
|
||||
_mag_topic(-1),
|
||||
_mag_orb_id(nullptr),
|
||||
_mag_class_instance(-1)
|
||||
{
|
||||
}
|
||||
@@ -1774,26 +1832,37 @@ namespace lsm303d
|
||||
|
||||
LSM303D *g_dev;
|
||||
|
||||
void start();
|
||||
void start(bool external_bus, enum Rotation rotation);
|
||||
void test();
|
||||
void reset();
|
||||
void info();
|
||||
void regdump();
|
||||
void logging();
|
||||
void usage();
|
||||
|
||||
/**
|
||||
* Start the driver.
|
||||
*
|
||||
* This function call only returns once the driver is
|
||||
* up and running or failed to detect the sensor.
|
||||
*/
|
||||
void
|
||||
start()
|
||||
start(bool external_bus, enum Rotation rotation)
|
||||
{
|
||||
int fd, fd_mag;
|
||||
|
||||
if (g_dev != nullptr)
|
||||
errx(0, "already started");
|
||||
|
||||
/* create the driver */
|
||||
g_dev = new LSM303D(PX4_SPI_BUS_SENSORS, LSM303D_DEVICE_PATH_ACCEL, (spi_dev_e)PX4_SPIDEV_ACCEL_MAG);
|
||||
if (external_bus) {
|
||||
#ifdef PX4_SPI_BUS_EXT
|
||||
g_dev = new LSM303D(PX4_SPI_BUS_EXT, LSM303D_DEVICE_PATH_ACCEL, (spi_dev_e)PX4_SPIDEV_EXT_ACCEL_MAG, rotation);
|
||||
#else
|
||||
errx(0, "External SPI not available");
|
||||
#endif
|
||||
} else {
|
||||
g_dev = new LSM303D(PX4_SPI_BUS_SENSORS, LSM303D_DEVICE_PATH_ACCEL, (spi_dev_e)PX4_SPIDEV_ACCEL_MAG, rotation);
|
||||
}
|
||||
|
||||
if (g_dev == nullptr) {
|
||||
warnx("failed instantiating LSM303D obj");
|
||||
@@ -1989,47 +2058,76 @@ logging()
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void
|
||||
usage()
|
||||
{
|
||||
warnx("missing command: try 'start', 'info', 'test', 'reset', 'regdump', 'logging'");
|
||||
warnx("options:");
|
||||
warnx(" -X (external bus)");
|
||||
warnx(" -R rotation");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int
|
||||
lsm303d_main(int argc, char *argv[])
|
||||
{
|
||||
bool external_bus = false;
|
||||
int ch;
|
||||
enum Rotation rotation = ROTATION_NONE;
|
||||
|
||||
/* jump over start/off/etc and look at options first */
|
||||
while ((ch = getopt(argc, argv, "XR:")) != EOF) {
|
||||
switch (ch) {
|
||||
case 'X':
|
||||
external_bus = true;
|
||||
break;
|
||||
case 'R':
|
||||
rotation = (enum Rotation)atoi(optarg);
|
||||
break;
|
||||
default:
|
||||
lsm303d::usage();
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
const char *verb = argv[optind];
|
||||
|
||||
/*
|
||||
* Start/load the driver.
|
||||
|
||||
*/
|
||||
if (!strcmp(argv[1], "start"))
|
||||
lsm303d::start();
|
||||
if (!strcmp(verb, "start"))
|
||||
lsm303d::start(external_bus, rotation);
|
||||
|
||||
/*
|
||||
* Test the driver/device.
|
||||
*/
|
||||
if (!strcmp(argv[1], "test"))
|
||||
if (!strcmp(verb, "test"))
|
||||
lsm303d::test();
|
||||
|
||||
/*
|
||||
* Reset the driver.
|
||||
*/
|
||||
if (!strcmp(argv[1], "reset"))
|
||||
if (!strcmp(verb, "reset"))
|
||||
lsm303d::reset();
|
||||
|
||||
/*
|
||||
* Print driver information.
|
||||
*/
|
||||
if (!strcmp(argv[1], "info"))
|
||||
if (!strcmp(verb, "info"))
|
||||
lsm303d::info();
|
||||
|
||||
/*
|
||||
* dump device registers
|
||||
*/
|
||||
if (!strcmp(argv[1], "regdump"))
|
||||
if (!strcmp(verb, "regdump"))
|
||||
lsm303d::regdump();
|
||||
|
||||
/*
|
||||
* dump device registers
|
||||
*/
|
||||
if (!strcmp(argv[1], "logging"))
|
||||
if (!strcmp(verb, "logging"))
|
||||
lsm303d::logging();
|
||||
|
||||
errx(1, "unrecognized command, try 'start', 'test', 'reset', 'info', 'logging' or 'regdump'");
|
||||
|
||||
@@ -5,4 +5,6 @@
|
||||
MODULE_COMMAND = lsm303d
|
||||
SRCS = lsm303d.cpp
|
||||
|
||||
MODULE_STACKSIZE = 1200
|
||||
|
||||
EXTRACXXFLAGS = -Weffc++
|
||||
|
||||
@@ -74,6 +74,7 @@
|
||||
/* Configuration Constants */
|
||||
#define MB12XX_BUS PX4_I2C_BUS_EXPANSION
|
||||
#define MB12XX_BASEADDR 0x70 /* 7-bit address. 8-bit address is 0xE0 */
|
||||
#define MB12XX_DEVICE_PATH "/dev/mb12xx"
|
||||
|
||||
/* MB12xx Registers addresses */
|
||||
|
||||
@@ -124,6 +125,7 @@ private:
|
||||
bool _sensor_ok;
|
||||
int _measure_ticks;
|
||||
bool _collect_phase;
|
||||
int _class_instance;
|
||||
|
||||
orb_advert_t _range_finder_topic;
|
||||
|
||||
@@ -187,13 +189,14 @@ private:
|
||||
extern "C" __EXPORT int mb12xx_main(int argc, char *argv[]);
|
||||
|
||||
MB12XX::MB12XX(int bus, int address) :
|
||||
I2C("MB12xx", RANGE_FINDER_DEVICE_PATH, bus, address, 100000),
|
||||
I2C("MB12xx", MB12XX_DEVICE_PATH, bus, address, 100000),
|
||||
_min_distance(MB12XX_MIN_DISTANCE),
|
||||
_max_distance(MB12XX_MAX_DISTANCE),
|
||||
_reports(nullptr),
|
||||
_sensor_ok(false),
|
||||
_measure_ticks(0),
|
||||
_collect_phase(false),
|
||||
_class_instance(-1),
|
||||
_range_finder_topic(-1),
|
||||
_sample_perf(perf_alloc(PC_ELAPSED, "mb12xx_read")),
|
||||
_comms_errors(perf_alloc(PC_COUNT, "mb12xx_comms_errors")),
|
||||
@@ -215,6 +218,15 @@ MB12XX::~MB12XX()
|
||||
if (_reports != nullptr) {
|
||||
delete _reports;
|
||||
}
|
||||
|
||||
if (_class_instance != -1) {
|
||||
unregister_class_devname(RANGE_FINDER_DEVICE_PATH, _class_instance);
|
||||
}
|
||||
|
||||
// free perf counters
|
||||
perf_free(_sample_perf);
|
||||
perf_free(_comms_errors);
|
||||
perf_free(_buffer_overflows);
|
||||
}
|
||||
|
||||
int
|
||||
@@ -234,13 +246,18 @@ MB12XX::init()
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* get a publish handle on the range finder topic */
|
||||
struct range_finder_report zero_report;
|
||||
memset(&zero_report, 0, sizeof(zero_report));
|
||||
_range_finder_topic = orb_advertise(ORB_ID(sensor_range_finder), &zero_report);
|
||||
_class_instance = register_class_devname(RANGE_FINDER_DEVICE_PATH);
|
||||
|
||||
if (_range_finder_topic < 0) {
|
||||
debug("failed to create sensor_range_finder object. Did you start uOrb?");
|
||||
if (_class_instance == CLASS_DEVICE_PRIMARY) {
|
||||
/* get a publish handle on the range finder topic */
|
||||
struct range_finder_report rf_report;
|
||||
measure();
|
||||
_reports->get(&rf_report);
|
||||
_range_finder_topic = orb_advertise(ORB_ID(sensor_range_finder), &rf_report);
|
||||
|
||||
if (_range_finder_topic < 0) {
|
||||
debug("failed to create sensor_range_finder object. Did you start uOrb?");
|
||||
}
|
||||
}
|
||||
|
||||
ret = OK;
|
||||
@@ -505,8 +522,10 @@ MB12XX::collect()
|
||||
report.distance = si_units;
|
||||
report.valid = si_units > get_minimum_distance() && si_units < get_maximum_distance() ? 1 : 0;
|
||||
|
||||
/* publish it */
|
||||
orb_publish(ORB_ID(sensor_range_finder), _range_finder_topic, &report);
|
||||
/* publish it, if we are the primary */
|
||||
if (_range_finder_topic >= 0) {
|
||||
orb_publish(ORB_ID(sensor_range_finder), _range_finder_topic, &report);
|
||||
}
|
||||
|
||||
if (_reports->force(&report)) {
|
||||
perf_count(_buffer_overflows);
|
||||
@@ -665,7 +684,7 @@ start()
|
||||
}
|
||||
|
||||
/* set the poll rate to default, starts automatic data collection */
|
||||
fd = open(RANGE_FINDER_DEVICE_PATH, O_RDONLY);
|
||||
fd = open(MB12XX_DEVICE_PATH, O_RDONLY);
|
||||
|
||||
if (fd < 0) {
|
||||
goto fail;
|
||||
@@ -715,10 +734,10 @@ test()
|
||||
ssize_t sz;
|
||||
int ret;
|
||||
|
||||
int fd = open(RANGE_FINDER_DEVICE_PATH, O_RDONLY);
|
||||
int fd = open(MB12XX_DEVICE_PATH, O_RDONLY);
|
||||
|
||||
if (fd < 0) {
|
||||
err(1, "%s open failed (try 'mb12xx start' if the driver is not running", RANGE_FINDER_DEVICE_PATH);
|
||||
err(1, "%s open failed (try 'mb12xx start' if the driver is not running", MB12XX_DEVICE_PATH);
|
||||
}
|
||||
|
||||
/* do a simple demand read */
|
||||
@@ -776,7 +795,7 @@ test()
|
||||
void
|
||||
reset()
|
||||
{
|
||||
int fd = open(RANGE_FINDER_DEVICE_PATH, O_RDONLY);
|
||||
int fd = open(MB12XX_DEVICE_PATH, O_RDONLY);
|
||||
|
||||
if (fd < 0) {
|
||||
err(1, "failed ");
|
||||
|
||||
@@ -38,3 +38,5 @@
|
||||
MODULE_COMMAND = mb12xx
|
||||
|
||||
SRCS = mb12xx.cpp
|
||||
|
||||
MAXOPTIMIZATION = -Os
|
||||
|
||||
@@ -40,3 +40,5 @@ MODULE_COMMAND = md25
|
||||
|
||||
SRCS = md25.cpp \
|
||||
md25_main.cpp
|
||||
|
||||
MAXOPTIMIZATION = -Os
|
||||
|
||||
@@ -92,7 +92,7 @@
|
||||
#include <drivers/airspeed/airspeed.h>
|
||||
|
||||
/* I2C bus address is 1010001x */
|
||||
#define I2C_ADDRESS_MS4525DO 0x28 //0x51 /* 7-bit address. */
|
||||
#define I2C_ADDRESS_MS4525DO 0x28 /**< 7-bit address. Depends on the order code (this is for code "I") */
|
||||
#define PATH_MS4525 "/dev/ms4525"
|
||||
/* The MS5525DSO address is 111011Cx, where C is the complementary value of the pin CSB */
|
||||
#define I2C_ADDRESS_MS5525DSO 0x77 //0x77/* 7-bit address, addr. pin pulled low */
|
||||
@@ -102,9 +102,9 @@
|
||||
#define ADDR_READ_MR 0x00 /* write to this address to start conversion */
|
||||
|
||||
/* Measurement rate is 100Hz */
|
||||
#define MEAS_RATE 100.0f
|
||||
#define MEAS_DRIVER_FILTER_FREQ 3.0f
|
||||
#define CONVERSION_INTERVAL (1000000 / 100) /* microseconds */
|
||||
#define MEAS_RATE 100
|
||||
#define MEAS_DRIVER_FILTER_FREQ 1.2f
|
||||
#define CONVERSION_INTERVAL (1000000 / MEAS_RATE) /* microseconds */
|
||||
|
||||
class MEASAirspeed : public Airspeed
|
||||
{
|
||||
@@ -140,9 +140,9 @@ extern "C" __EXPORT int meas_airspeed_main(int argc, char *argv[]);
|
||||
MEASAirspeed::MEASAirspeed(int bus, int address, const char *path) : Airspeed(bus, address,
|
||||
CONVERSION_INTERVAL, path),
|
||||
_filter(MEAS_RATE, MEAS_DRIVER_FILTER_FREQ),
|
||||
_t_system_power(-1)
|
||||
_t_system_power(-1),
|
||||
system_power{}
|
||||
{
|
||||
memset(&system_power, 0, sizeof(system_power));
|
||||
}
|
||||
|
||||
int
|
||||
@@ -225,47 +225,28 @@ MEASAirspeed::collect()
|
||||
// correct for 5V rail voltage if possible
|
||||
voltage_correction(diff_press_pa_raw, temperature);
|
||||
|
||||
float diff_press_pa = fabsf(diff_press_pa_raw - _diff_pres_offset);
|
||||
|
||||
/*
|
||||
note that we return both the absolute value with offset
|
||||
applied and a raw value without the offset applied. This
|
||||
makes it possible for higher level code to detect if the
|
||||
user has the tubes connected backwards, and also makes it
|
||||
possible to correctly use offsets calculated by a higher
|
||||
level airspeed driver.
|
||||
// the raw value still should be compensated for the known offset
|
||||
diff_press_pa_raw -= _diff_pres_offset;
|
||||
|
||||
/*
|
||||
With the above calculation the MS4525 sensor will produce a
|
||||
positive number when the top port is used as a dynamic port
|
||||
and bottom port is used as the static port
|
||||
|
||||
Also note that the _diff_pres_offset is applied before the
|
||||
fabsf() not afterwards. It needs to be done this way to
|
||||
prevent a bias at low speeds, but this also means that when
|
||||
setting a offset you must set it based on the raw value, not
|
||||
the offset value
|
||||
*/
|
||||
|
||||
|
||||
struct differential_pressure_s report;
|
||||
|
||||
/* track maximum differential pressure measured (so we can work out top speed). */
|
||||
if (diff_press_pa > _max_differential_pressure_pa) {
|
||||
_max_differential_pressure_pa = diff_press_pa;
|
||||
if (diff_press_pa_raw > _max_differential_pressure_pa) {
|
||||
_max_differential_pressure_pa = diff_press_pa_raw;
|
||||
}
|
||||
|
||||
report.timestamp = hrt_absolute_time();
|
||||
report.error_count = perf_event_count(_comms_errors);
|
||||
report.temperature = temperature;
|
||||
report.differential_pressure_pa = diff_press_pa;
|
||||
report.differential_pressure_filtered_pa = _filter.apply(diff_press_pa);
|
||||
|
||||
/* the dynamics of the filter can make it overshoot into the negative range */
|
||||
if (report.differential_pressure_filtered_pa < 0.0f) {
|
||||
report.differential_pressure_filtered_pa = _filter.reset(diff_press_pa);
|
||||
}
|
||||
report.differential_pressure_filtered_pa = _filter.apply(diff_press_pa_raw);
|
||||
|
||||
report.differential_pressure_raw_pa = diff_press_pa_raw;
|
||||
report.voltage = 0;
|
||||
report.max_differential_pressure_pa = _max_differential_pressure_pa;
|
||||
|
||||
if (_airspeed_pub > 0 && !(_pub_blocked)) {
|
||||
@@ -343,7 +324,7 @@ MEASAirspeed::cycle()
|
||||
/**
|
||||
correct for 5V rail voltage if the system_power ORB topic is
|
||||
available
|
||||
|
||||
|
||||
See http://uav.tridgell.net/MS4525/MS4525-offset.png for a graph of
|
||||
offset versus voltage for 3 sensors
|
||||
*/
|
||||
@@ -392,7 +373,7 @@ MEASAirspeed::voltage_correction(float &diff_press_pa, float &temperature)
|
||||
if (voltage_diff < -1.0f) {
|
||||
voltage_diff = -1.0f;
|
||||
}
|
||||
temperature -= voltage_diff * temp_slope;
|
||||
temperature -= voltage_diff * temp_slope;
|
||||
#endif // CONFIG_ARCH_BOARD_PX4FMU_V2
|
||||
}
|
||||
|
||||
@@ -418,6 +399,9 @@ void info();
|
||||
|
||||
/**
|
||||
* Start the driver.
|
||||
*
|
||||
* This function call only returns once the driver is up and running
|
||||
* or failed to detect the sensor.
|
||||
*/
|
||||
void
|
||||
start(int i2c_bus)
|
||||
@@ -518,7 +502,7 @@ test()
|
||||
}
|
||||
|
||||
warnx("single read");
|
||||
warnx("diff pressure: %d pa", (int)report.differential_pressure_pa);
|
||||
warnx("diff pressure: %d pa", (int)report.differential_pressure_filtered_pa);
|
||||
|
||||
/* start the sensor polling at 2Hz */
|
||||
if (OK != ioctl(fd, SENSORIOCSPOLLRATE, 2)) {
|
||||
@@ -546,7 +530,7 @@ test()
|
||||
}
|
||||
|
||||
warnx("periodic read %u", i);
|
||||
warnx("diff pressure: %d pa", (int)report.differential_pressure_pa);
|
||||
warnx("diff pressure: %d pa", (int)report.differential_pressure_filtered_pa);
|
||||
warnx("temperature: %d C (0x%02x)", (int)report.temperature, (unsigned) report.temperature);
|
||||
}
|
||||
|
||||
|
||||
@@ -36,6 +36,11 @@
|
||||
#
|
||||
|
||||
MODULE_COMMAND = meas_airspeed
|
||||
MODULE_STACKSIZE = 2048
|
||||
|
||||
SRCS = meas_airspeed.cpp
|
||||
|
||||
MODULE_STACKSIZE = 1200
|
||||
|
||||
EXTRACXXFLAGS = -Weffc++
|
||||
|
||||
MAXOPTIMIZATION = -Os
|
||||
|
||||
@@ -37,6 +37,8 @@
|
||||
|
||||
MODULE_COMMAND = mkblctrl
|
||||
|
||||
SRCS = mkblctrl.cpp
|
||||
SRCS = mkblctrl.cpp
|
||||
|
||||
INCLUDE_DIRS += $(TOPDIR)/arch/arm/src/stm32 $(TOPDIR)/arch/arm/src/common
|
||||
|
||||
MAXOPTIMIZATION = -Os
|
||||
|
||||
@@ -37,7 +37,8 @@
|
||||
|
||||
MODULE_COMMAND = mpu6000
|
||||
|
||||
# XXX seems excessive, check if 2048 is not sufficient
|
||||
MODULE_STACKSIZE = 4096
|
||||
|
||||
SRCS = mpu6000.cpp
|
||||
|
||||
MODULE_STACKSIZE = 1200
|
||||
|
||||
EXTRACXXFLAGS = -Weffc++
|
||||
|
||||
+176
-70
@@ -55,6 +55,7 @@
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <unistd.h>
|
||||
#include <getopt.h>
|
||||
|
||||
#include <systemlib/perf_counter.h>
|
||||
#include <systemlib/err.h>
|
||||
@@ -71,12 +72,15 @@
|
||||
#include <drivers/drv_accel.h>
|
||||
#include <drivers/drv_gyro.h>
|
||||
#include <mathlib/math/filter/LowPassFilter2p.hpp>
|
||||
#include <lib/conversion/rotation.h>
|
||||
|
||||
#define DIR_READ 0x80
|
||||
#define DIR_WRITE 0x00
|
||||
|
||||
#define MPU_DEVICE_PATH_ACCEL "/dev/mpu6000_accel"
|
||||
#define MPU_DEVICE_PATH_GYRO "/dev/mpu6000_gyro"
|
||||
#define MPU_DEVICE_PATH_ACCEL_EXT "/dev/mpu6000_accel_ext"
|
||||
#define MPU_DEVICE_PATH_GYRO_EXT "/dev/mpu6000_gyro_ext"
|
||||
|
||||
// MPU 6000 registers
|
||||
#define MPUREG_WHOAMI 0x75
|
||||
@@ -177,7 +181,7 @@ class MPU6000_gyro;
|
||||
class MPU6000 : public device::SPI
|
||||
{
|
||||
public:
|
||||
MPU6000(int bus, spi_dev_e device);
|
||||
MPU6000(int bus, const char *path_accel, const char *path_gyro, spi_dev_e device, enum Rotation rotation);
|
||||
virtual ~MPU6000();
|
||||
|
||||
virtual int init();
|
||||
@@ -211,6 +215,7 @@ private:
|
||||
float _accel_range_scale;
|
||||
float _accel_range_m_s2;
|
||||
orb_advert_t _accel_topic;
|
||||
orb_id_t _accel_orb_id;
|
||||
int _accel_class_instance;
|
||||
|
||||
RingBuffer *_gyro_reports;
|
||||
@@ -232,6 +237,8 @@ private:
|
||||
math::LowPassFilter2p _gyro_filter_y;
|
||||
math::LowPassFilter2p _gyro_filter_z;
|
||||
|
||||
enum Rotation _rotation;
|
||||
|
||||
/**
|
||||
* Start automatic measurement.
|
||||
*/
|
||||
@@ -337,6 +344,9 @@ private:
|
||||
*/
|
||||
void _set_sample_rate(uint16_t desired_sample_rate_hz);
|
||||
|
||||
/* do not allow to copy this class due to pointer data members */
|
||||
MPU6000(const MPU6000&);
|
||||
MPU6000 operator=(const MPU6000&);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -345,7 +355,7 @@ private:
|
||||
class MPU6000_gyro : public device::CDev
|
||||
{
|
||||
public:
|
||||
MPU6000_gyro(MPU6000 *parent);
|
||||
MPU6000_gyro(MPU6000 *parent, const char *path);
|
||||
~MPU6000_gyro();
|
||||
|
||||
virtual ssize_t read(struct file *filp, char *buffer, size_t buflen);
|
||||
@@ -361,24 +371,32 @@ protected:
|
||||
private:
|
||||
MPU6000 *_parent;
|
||||
orb_advert_t _gyro_topic;
|
||||
orb_id_t _gyro_orb_id;
|
||||
int _gyro_class_instance;
|
||||
|
||||
/* do not allow to copy this class due to pointer data members */
|
||||
MPU6000_gyro(const MPU6000_gyro&);
|
||||
MPU6000_gyro operator=(const MPU6000_gyro&);
|
||||
};
|
||||
|
||||
/** driver 'main' command */
|
||||
extern "C" { __EXPORT int mpu6000_main(int argc, char *argv[]); }
|
||||
|
||||
MPU6000::MPU6000(int bus, spi_dev_e device) :
|
||||
SPI("MPU6000", MPU_DEVICE_PATH_ACCEL, bus, device, SPIDEV_MODE3, MPU6000_LOW_BUS_SPEED),
|
||||
_gyro(new MPU6000_gyro(this)),
|
||||
MPU6000::MPU6000(int bus, const char *path_accel, const char *path_gyro, spi_dev_e device, enum Rotation rotation) :
|
||||
SPI("MPU6000", path_accel, bus, device, SPIDEV_MODE3, MPU6000_LOW_BUS_SPEED),
|
||||
_gyro(new MPU6000_gyro(this, path_gyro)),
|
||||
_product(0),
|
||||
_call{},
|
||||
_call_interval(0),
|
||||
_accel_reports(nullptr),
|
||||
_accel_scale{},
|
||||
_accel_range_scale(0.0f),
|
||||
_accel_range_m_s2(0.0f),
|
||||
_accel_topic(-1),
|
||||
_accel_orb_id(nullptr),
|
||||
_accel_class_instance(-1),
|
||||
_gyro_reports(nullptr),
|
||||
_gyro_scale{},
|
||||
_gyro_range_scale(0.0f),
|
||||
_gyro_range_rad_s(0.0f),
|
||||
_sample_rate(1000),
|
||||
@@ -391,7 +409,8 @@ MPU6000::MPU6000(int bus, spi_dev_e device) :
|
||||
_accel_filter_z(MPU6000_ACCEL_DEFAULT_RATE, MPU6000_ACCEL_DEFAULT_DRIVER_FILTER_FREQ),
|
||||
_gyro_filter_x(MPU6000_GYRO_DEFAULT_RATE, MPU6000_GYRO_DEFAULT_DRIVER_FILTER_FREQ),
|
||||
_gyro_filter_y(MPU6000_GYRO_DEFAULT_RATE, MPU6000_GYRO_DEFAULT_DRIVER_FILTER_FREQ),
|
||||
_gyro_filter_z(MPU6000_GYRO_DEFAULT_RATE, MPU6000_GYRO_DEFAULT_DRIVER_FILTER_FREQ)
|
||||
_gyro_filter_z(MPU6000_GYRO_DEFAULT_RATE, MPU6000_GYRO_DEFAULT_DRIVER_FILTER_FREQ),
|
||||
_rotation(rotation)
|
||||
{
|
||||
// disable debug() calls
|
||||
_debug_enabled = false;
|
||||
@@ -491,31 +510,56 @@ MPU6000::init()
|
||||
|
||||
measure();
|
||||
|
||||
if (_accel_class_instance == CLASS_DEVICE_PRIMARY) {
|
||||
/* advertise sensor topic, measure manually to initialize valid report */
|
||||
struct accel_report arp;
|
||||
_accel_reports->get(&arp);
|
||||
|
||||
/* advertise sensor topic, measure manually to initialize valid report */
|
||||
struct accel_report arp;
|
||||
_accel_reports->get(&arp);
|
||||
/* measurement will have generated a report, publish */
|
||||
switch (_accel_class_instance) {
|
||||
case CLASS_DEVICE_PRIMARY:
|
||||
_accel_orb_id = ORB_ID(sensor_accel0);
|
||||
break;
|
||||
|
||||
case CLASS_DEVICE_SECONDARY:
|
||||
_accel_orb_id = ORB_ID(sensor_accel1);
|
||||
break;
|
||||
|
||||
/* measurement will have generated a report, publish */
|
||||
_accel_topic = orb_advertise(ORB_ID(sensor_accel), &arp);
|
||||
|
||||
if (_accel_topic < 0)
|
||||
debug("failed to create sensor_accel publication");
|
||||
case CLASS_DEVICE_TERTIARY:
|
||||
_accel_orb_id = ORB_ID(sensor_accel2);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if (_gyro->_gyro_class_instance == CLASS_DEVICE_PRIMARY) {
|
||||
_accel_topic = orb_advertise(_accel_orb_id, &arp);
|
||||
|
||||
/* advertise sensor topic, measure manually to initialize valid report */
|
||||
struct gyro_report grp;
|
||||
_gyro_reports->get(&grp);
|
||||
if (_accel_topic < 0) {
|
||||
warnx("ADVERT FAIL");
|
||||
}
|
||||
|
||||
_gyro->_gyro_topic = orb_advertise(ORB_ID(sensor_gyro), &grp);
|
||||
|
||||
if (_gyro->_gyro_topic < 0)
|
||||
debug("failed to create sensor_gyro publication");
|
||||
/* advertise sensor topic, measure manually to initialize valid report */
|
||||
struct gyro_report grp;
|
||||
_gyro_reports->get(&grp);
|
||||
|
||||
switch (_gyro->_gyro_class_instance) {
|
||||
case CLASS_DEVICE_PRIMARY:
|
||||
_gyro->_gyro_orb_id = ORB_ID(sensor_gyro0);
|
||||
break;
|
||||
|
||||
case CLASS_DEVICE_SECONDARY:
|
||||
_gyro->_gyro_orb_id = ORB_ID(sensor_gyro1);
|
||||
break;
|
||||
|
||||
case CLASS_DEVICE_TERTIARY:
|
||||
_gyro->_gyro_orb_id = ORB_ID(sensor_gyro2);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
_gyro->_gyro_topic = orb_advertise(_gyro->_gyro_orb_id, &grp);
|
||||
|
||||
if (_gyro->_gyro_topic < 0) {
|
||||
warnx("ADVERT FAIL");
|
||||
}
|
||||
|
||||
out:
|
||||
@@ -666,7 +710,9 @@ MPU6000::_set_dlpf_filter(uint16_t frequency_hz)
|
||||
/*
|
||||
choose next highest filter frequency available
|
||||
*/
|
||||
if (frequency_hz <= 5) {
|
||||
if (frequency_hz == 0) {
|
||||
filter = BITS_DLPF_CFG_2100HZ_NOLPF;
|
||||
} else if (frequency_hz <= 5) {
|
||||
filter = BITS_DLPF_CFG_5HZ;
|
||||
} else if (frequency_hz <= 10) {
|
||||
filter = BITS_DLPF_CFG_10HZ;
|
||||
@@ -922,10 +968,11 @@ MPU6000::ioctl(struct file *filp, int cmd, unsigned long arg)
|
||||
return _accel_filter_x.get_cutoff_freq();
|
||||
|
||||
case ACCELIOCSLOWPASS:
|
||||
|
||||
// XXX decide on relationship of both filters
|
||||
// i.e. disable the on-chip filter
|
||||
//_set_dlpf_filter((uint16_t)arg);
|
||||
if (arg == 0) {
|
||||
// allow disabling of on-chip filter using
|
||||
// zero as desired filter frequency
|
||||
_set_dlpf_filter(0);
|
||||
}
|
||||
_accel_filter_x.set_cutoff_frequency(1.0e6f / _call_interval, arg);
|
||||
_accel_filter_y.set_cutoff_frequency(1.0e6f / _call_interval, arg);
|
||||
_accel_filter_z.set_cutoff_frequency(1.0e6f / _call_interval, arg);
|
||||
@@ -1009,8 +1056,11 @@ MPU6000::gyro_ioctl(struct file *filp, int cmd, unsigned long arg)
|
||||
_gyro_filter_x.set_cutoff_frequency(1.0e6f / _call_interval, arg);
|
||||
_gyro_filter_y.set_cutoff_frequency(1.0e6f / _call_interval, arg);
|
||||
_gyro_filter_z.set_cutoff_frequency(1.0e6f / _call_interval, arg);
|
||||
// XXX check relation to the internal lowpass
|
||||
//_set_dlpf_filter((uint16_t)arg);
|
||||
if (arg == 0) {
|
||||
// allow disabling of on-chip filter using 0
|
||||
// as desired frequency
|
||||
_set_dlpf_filter(0);
|
||||
}
|
||||
return OK;
|
||||
|
||||
case GYROIOCSSCALE:
|
||||
@@ -1295,6 +1345,9 @@ MPU6000::measure()
|
||||
arb.y = _accel_filter_y.apply(y_in_new);
|
||||
arb.z = _accel_filter_z.apply(z_in_new);
|
||||
|
||||
// apply user specified rotation
|
||||
rotate_3f(_rotation, arb.x, arb.y, arb.z);
|
||||
|
||||
arb.scaling = _accel_range_scale;
|
||||
arb.range_m_s2 = _accel_range_m_s2;
|
||||
|
||||
@@ -1313,6 +1366,9 @@ MPU6000::measure()
|
||||
grb.y = _gyro_filter_y.apply(y_gyro_in_new);
|
||||
grb.z = _gyro_filter_z.apply(z_gyro_in_new);
|
||||
|
||||
// apply user specified rotation
|
||||
rotate_3f(_rotation, grb.x, grb.y, grb.z);
|
||||
|
||||
grb.scaling = _gyro_range_scale;
|
||||
grb.range_rad_s = _gyro_range_rad_s;
|
||||
|
||||
@@ -1326,14 +1382,14 @@ MPU6000::measure()
|
||||
poll_notify(POLLIN);
|
||||
_gyro->parent_poll_notify();
|
||||
|
||||
if (_accel_topic > 0 && !(_pub_blocked)) {
|
||||
if (!(_pub_blocked)) {
|
||||
/* publish it */
|
||||
orb_publish(ORB_ID(sensor_accel), _accel_topic, &arb);
|
||||
orb_publish(_accel_orb_id, _accel_topic, &arb);
|
||||
}
|
||||
|
||||
if (_gyro->_gyro_topic > 0 && !(_pub_blocked)) {
|
||||
if (!(_pub_blocked)) {
|
||||
/* publish it */
|
||||
orb_publish(ORB_ID(sensor_gyro), _gyro->_gyro_topic, &grb);
|
||||
orb_publish(_gyro->_gyro_orb_id, _gyro->_gyro_topic, &grb);
|
||||
}
|
||||
|
||||
/* stop measuring */
|
||||
@@ -1350,10 +1406,11 @@ MPU6000::print_info()
|
||||
_gyro_reports->print_info("gyro queue");
|
||||
}
|
||||
|
||||
MPU6000_gyro::MPU6000_gyro(MPU6000 *parent) :
|
||||
CDev("MPU6000_gyro", MPU_DEVICE_PATH_GYRO),
|
||||
MPU6000_gyro::MPU6000_gyro(MPU6000 *parent, const char *path) :
|
||||
CDev("MPU6000_gyro", path),
|
||||
_parent(parent),
|
||||
_gyro_topic(-1),
|
||||
_gyro_orb_id(nullptr),
|
||||
_gyro_class_instance(-1)
|
||||
{
|
||||
}
|
||||
@@ -1407,36 +1464,52 @@ MPU6000_gyro::ioctl(struct file *filp, int cmd, unsigned long arg)
|
||||
namespace mpu6000
|
||||
{
|
||||
|
||||
MPU6000 *g_dev;
|
||||
MPU6000 *g_dev_int; // on internal bus
|
||||
MPU6000 *g_dev_ext; // on external bus
|
||||
|
||||
void start();
|
||||
void test();
|
||||
void reset();
|
||||
void info();
|
||||
void start(bool, enum Rotation);
|
||||
void test(bool);
|
||||
void reset(bool);
|
||||
void info(bool);
|
||||
void usage();
|
||||
|
||||
/**
|
||||
* Start the driver.
|
||||
*
|
||||
* This function only returns if the driver is up and running
|
||||
* or failed to detect the sensor.
|
||||
*/
|
||||
void
|
||||
start()
|
||||
start(bool external_bus, enum Rotation rotation)
|
||||
{
|
||||
int fd;
|
||||
MPU6000 **g_dev_ptr = external_bus?&g_dev_ext:&g_dev_int;
|
||||
const char *path_accel = external_bus?MPU_DEVICE_PATH_ACCEL_EXT:MPU_DEVICE_PATH_ACCEL;
|
||||
const char *path_gyro = external_bus?MPU_DEVICE_PATH_GYRO_EXT:MPU_DEVICE_PATH_GYRO;
|
||||
|
||||
if (g_dev != nullptr)
|
||||
if (*g_dev_ptr != nullptr)
|
||||
/* if already started, the still command succeeded */
|
||||
errx(0, "already started");
|
||||
|
||||
/* create the driver */
|
||||
g_dev = new MPU6000(1 /* XXX magic number */, (spi_dev_e)PX4_SPIDEV_MPU);
|
||||
if (external_bus) {
|
||||
#ifdef PX4_SPI_BUS_EXT
|
||||
*g_dev_ptr = new MPU6000(PX4_SPI_BUS_EXT, path_accel, path_gyro, (spi_dev_e)PX4_SPIDEV_EXT_MPU, rotation);
|
||||
#else
|
||||
errx(0, "External SPI not available");
|
||||
#endif
|
||||
} else {
|
||||
*g_dev_ptr = new MPU6000(PX4_SPI_BUS_SENSORS, path_accel, path_gyro, (spi_dev_e)PX4_SPIDEV_MPU, rotation);
|
||||
}
|
||||
|
||||
if (g_dev == nullptr)
|
||||
if (*g_dev_ptr == nullptr)
|
||||
goto fail;
|
||||
|
||||
if (OK != g_dev->init())
|
||||
if (OK != (*g_dev_ptr)->init())
|
||||
goto fail;
|
||||
|
||||
/* set the poll rate to default, starts automatic data collection */
|
||||
fd = open(MPU_DEVICE_PATH_ACCEL, O_RDONLY);
|
||||
fd = open(path_accel, O_RDONLY);
|
||||
|
||||
if (fd < 0)
|
||||
goto fail;
|
||||
@@ -1449,9 +1522,9 @@ start()
|
||||
exit(0);
|
||||
fail:
|
||||
|
||||
if (g_dev != nullptr) {
|
||||
delete g_dev;
|
||||
g_dev = nullptr;
|
||||
if (*g_dev_ptr != nullptr) {
|
||||
delete (*g_dev_ptr);
|
||||
*g_dev_ptr = nullptr;
|
||||
}
|
||||
|
||||
errx(1, "driver start failed");
|
||||
@@ -1463,24 +1536,26 @@ fail:
|
||||
* and automatic modes.
|
||||
*/
|
||||
void
|
||||
test()
|
||||
test(bool external_bus)
|
||||
{
|
||||
const char *path_accel = external_bus?MPU_DEVICE_PATH_ACCEL_EXT:MPU_DEVICE_PATH_ACCEL;
|
||||
const char *path_gyro = external_bus?MPU_DEVICE_PATH_GYRO_EXT:MPU_DEVICE_PATH_GYRO;
|
||||
accel_report a_report;
|
||||
gyro_report g_report;
|
||||
ssize_t sz;
|
||||
|
||||
/* get the driver */
|
||||
int fd = open(MPU_DEVICE_PATH_ACCEL, O_RDONLY);
|
||||
int fd = open(path_accel, O_RDONLY);
|
||||
|
||||
if (fd < 0)
|
||||
err(1, "%s open failed (try 'mpu6000 start' if the driver is not running)",
|
||||
MPU_DEVICE_PATH_ACCEL);
|
||||
err(1, "%s open failed (try 'mpu6000 start')",
|
||||
path_accel);
|
||||
|
||||
/* get the driver */
|
||||
int fd_gyro = open(MPU_DEVICE_PATH_GYRO, O_RDONLY);
|
||||
int fd_gyro = open(path_gyro, O_RDONLY);
|
||||
|
||||
if (fd_gyro < 0)
|
||||
err(1, "%s open failed", MPU_DEVICE_PATH_GYRO);
|
||||
err(1, "%s open failed", path_gyro);
|
||||
|
||||
/* reset to manual polling */
|
||||
if (ioctl(fd, SENSORIOCSPOLLRATE, SENSOR_POLLRATE_MANUAL) < 0)
|
||||
@@ -1528,7 +1603,7 @@ test()
|
||||
|
||||
/* XXX add poll-rate tests here too */
|
||||
|
||||
reset();
|
||||
reset(external_bus);
|
||||
errx(0, "PASS");
|
||||
}
|
||||
|
||||
@@ -1536,9 +1611,10 @@ test()
|
||||
* Reset the driver.
|
||||
*/
|
||||
void
|
||||
reset()
|
||||
reset(bool external_bus)
|
||||
{
|
||||
int fd = open(MPU_DEVICE_PATH_ACCEL, O_RDONLY);
|
||||
const char *path_accel = external_bus?MPU_DEVICE_PATH_ACCEL_EXT:MPU_DEVICE_PATH_ACCEL;
|
||||
int fd = open(path_accel, O_RDONLY);
|
||||
|
||||
if (fd < 0)
|
||||
err(1, "failed ");
|
||||
@@ -1558,47 +1634,77 @@ reset()
|
||||
* Print a little info about the driver.
|
||||
*/
|
||||
void
|
||||
info()
|
||||
info(bool external_bus)
|
||||
{
|
||||
if (g_dev == nullptr)
|
||||
MPU6000 **g_dev_ptr = external_bus?&g_dev_ext:&g_dev_int;
|
||||
if (*g_dev_ptr == nullptr)
|
||||
errx(1, "driver not running");
|
||||
|
||||
printf("state @ %p\n", g_dev);
|
||||
g_dev->print_info();
|
||||
printf("state @ %p\n", *g_dev_ptr);
|
||||
(*g_dev_ptr)->print_info();
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void
|
||||
usage()
|
||||
{
|
||||
warnx("missing command: try 'start', 'info', 'test', 'reset'");
|
||||
warnx("options:");
|
||||
warnx(" -X (external bus)");
|
||||
warnx(" -R rotation");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int
|
||||
mpu6000_main(int argc, char *argv[])
|
||||
{
|
||||
bool external_bus = false;
|
||||
int ch;
|
||||
enum Rotation rotation = ROTATION_NONE;
|
||||
|
||||
/* jump over start/off/etc and look at options first */
|
||||
while ((ch = getopt(argc, argv, "XR:")) != EOF) {
|
||||
switch (ch) {
|
||||
case 'X':
|
||||
external_bus = true;
|
||||
break;
|
||||
case 'R':
|
||||
rotation = (enum Rotation)atoi(optarg);
|
||||
break;
|
||||
default:
|
||||
mpu6000::usage();
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
const char *verb = argv[optind];
|
||||
|
||||
/*
|
||||
* Start/load the driver.
|
||||
|
||||
*/
|
||||
if (!strcmp(argv[1], "start"))
|
||||
mpu6000::start();
|
||||
if (!strcmp(verb, "start"))
|
||||
mpu6000::start(external_bus, rotation);
|
||||
|
||||
/*
|
||||
* Test the driver/device.
|
||||
*/
|
||||
if (!strcmp(argv[1], "test"))
|
||||
mpu6000::test();
|
||||
if (!strcmp(verb, "test"))
|
||||
mpu6000::test(external_bus);
|
||||
|
||||
/*
|
||||
* Reset the driver.
|
||||
*/
|
||||
if (!strcmp(argv[1], "reset"))
|
||||
mpu6000::reset();
|
||||
if (!strcmp(verb, "reset"))
|
||||
mpu6000::reset(external_bus);
|
||||
|
||||
/*
|
||||
* Print driver information.
|
||||
*/
|
||||
if (!strcmp(argv[1], "info"))
|
||||
mpu6000::info();
|
||||
if (!strcmp(verb, "info"))
|
||||
mpu6000::info(external_bus);
|
||||
|
||||
errx(1, "unrecognized command, try 'start', 'test', 'reset' or 'info'");
|
||||
}
|
||||
|
||||
@@ -38,3 +38,5 @@
|
||||
MODULE_COMMAND = ms5611
|
||||
|
||||
SRCS = ms5611.cpp ms5611_spi.cpp ms5611_i2c.cpp
|
||||
|
||||
MAXOPTIMIZATION = -Os
|
||||
|
||||
@@ -50,6 +50,7 @@
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <unistd.h>
|
||||
#include <getopt.h>
|
||||
|
||||
#include <nuttx/arch.h>
|
||||
#include <nuttx/wqueue.h>
|
||||
@@ -129,7 +130,7 @@ protected:
|
||||
float _T;
|
||||
|
||||
/* altitude conversion calibration */
|
||||
unsigned _msl_pressure; /* in kPa */
|
||||
unsigned _msl_pressure; /* in Pa */
|
||||
|
||||
orb_advert_t _baro_topic;
|
||||
|
||||
@@ -299,12 +300,17 @@ MS5611::init()
|
||||
|
||||
ret = OK;
|
||||
|
||||
if (_class_instance == CLASS_DEVICE_PRIMARY) {
|
||||
switch (_class_instance) {
|
||||
case CLASS_DEVICE_PRIMARY:
|
||||
_baro_topic = orb_advertise(ORB_ID(sensor_baro0), &brp);
|
||||
break;
|
||||
case CLASS_DEVICE_SECONDARY:
|
||||
_baro_topic = orb_advertise(ORB_ID(sensor_baro1), &brp);
|
||||
break;
|
||||
}
|
||||
|
||||
_baro_topic = orb_advertise(ORB_ID(sensor_baro), &brp);
|
||||
|
||||
if (_baro_topic < 0)
|
||||
debug("failed to create sensor_baro publication");
|
||||
if (_baro_topic < 0) {
|
||||
warnx("failed to create sensor_baro publication");
|
||||
}
|
||||
|
||||
} while (0);
|
||||
@@ -460,7 +466,7 @@ MS5611::ioctl(struct file *filp, int cmd, unsigned long arg)
|
||||
irqrestore(flags);
|
||||
return -ENOMEM;
|
||||
}
|
||||
irqrestore(flags);
|
||||
irqrestore(flags);
|
||||
return OK;
|
||||
}
|
||||
|
||||
@@ -721,9 +727,17 @@ MS5611::collect()
|
||||
report.altitude = (((pow((p / p1), (-(a * R) / g))) * T1) - T1) / a;
|
||||
|
||||
/* publish it */
|
||||
if (_baro_topic > 0 && !(_pub_blocked)) {
|
||||
if (!(_pub_blocked)) {
|
||||
/* publish it */
|
||||
orb_publish(ORB_ID(sensor_baro), _baro_topic, &report);
|
||||
switch (_class_instance) {
|
||||
case CLASS_DEVICE_PRIMARY:
|
||||
orb_publish(ORB_ID(sensor_baro0), _baro_topic, &report);
|
||||
break;
|
||||
|
||||
case CLASS_DEVICE_SECONDARY:
|
||||
orb_publish(ORB_ID(sensor_baro1), _baro_topic, &report);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (_reports->force(&report)) {
|
||||
@@ -775,11 +789,12 @@ namespace ms5611
|
||||
|
||||
MS5611 *g_dev;
|
||||
|
||||
void start();
|
||||
void start(bool external_bus);
|
||||
void test();
|
||||
void reset();
|
||||
void info();
|
||||
void calibrate(unsigned altitude);
|
||||
void usage();
|
||||
|
||||
/**
|
||||
* MS5611 crc4 cribbed from the datasheet
|
||||
@@ -832,7 +847,7 @@ crc4(uint16_t *n_prom)
|
||||
* Start the driver.
|
||||
*/
|
||||
void
|
||||
start()
|
||||
start(bool external_bus)
|
||||
{
|
||||
int fd;
|
||||
prom_u prom_buf;
|
||||
@@ -845,7 +860,7 @@ start()
|
||||
|
||||
/* create the driver, try SPI first, fall back to I2C if unsuccessful */
|
||||
if (MS5611_spi_interface != nullptr)
|
||||
interface = MS5611_spi_interface(prom_buf);
|
||||
interface = MS5611_spi_interface(prom_buf, external_bus);
|
||||
if (interface == nullptr && (MS5611_i2c_interface != nullptr))
|
||||
interface = MS5611_i2c_interface(prom_buf);
|
||||
|
||||
@@ -1056,43 +1071,68 @@ calibrate(unsigned altitude)
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void
|
||||
usage()
|
||||
{
|
||||
warnx("missing command: try 'start', 'info', 'test', 'test2', 'reset', 'calibrate'");
|
||||
warnx("options:");
|
||||
warnx(" -X (external bus)");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int
|
||||
ms5611_main(int argc, char *argv[])
|
||||
{
|
||||
bool external_bus = false;
|
||||
int ch;
|
||||
|
||||
/* jump over start/off/etc and look at options first */
|
||||
while ((ch = getopt(argc, argv, "X")) != EOF) {
|
||||
switch (ch) {
|
||||
case 'X':
|
||||
external_bus = true;
|
||||
break;
|
||||
default:
|
||||
ms5611::usage();
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
const char *verb = argv[optind];
|
||||
|
||||
/*
|
||||
* Start/load the driver.
|
||||
*/
|
||||
if (!strcmp(argv[1], "start"))
|
||||
ms5611::start();
|
||||
if (!strcmp(verb, "start"))
|
||||
ms5611::start(external_bus);
|
||||
|
||||
/*
|
||||
* Test the driver/device.
|
||||
*/
|
||||
if (!strcmp(argv[1], "test"))
|
||||
if (!strcmp(verb, "test"))
|
||||
ms5611::test();
|
||||
|
||||
/*
|
||||
* Reset the driver.
|
||||
*/
|
||||
if (!strcmp(argv[1], "reset"))
|
||||
if (!strcmp(verb, "reset"))
|
||||
ms5611::reset();
|
||||
|
||||
/*
|
||||
* Print driver information.
|
||||
*/
|
||||
if (!strcmp(argv[1], "info"))
|
||||
if (!strcmp(verb, "info"))
|
||||
ms5611::info();
|
||||
|
||||
/*
|
||||
* Perform MSL pressure calibration given an altitude in metres
|
||||
*/
|
||||
if (!strcmp(argv[1], "calibrate")) {
|
||||
if (!strcmp(verb, "calibrate")) {
|
||||
if (argc < 2)
|
||||
errx(1, "missing altitude");
|
||||
|
||||
long altitude = strtol(argv[2], nullptr, 10);
|
||||
long altitude = strtol(argv[optind+1], nullptr, 10);
|
||||
|
||||
ms5611::calibrate(altitude);
|
||||
}
|
||||
|
||||
@@ -80,6 +80,6 @@ extern bool crc4(uint16_t *n_prom);
|
||||
} /* namespace */
|
||||
|
||||
/* interface factories */
|
||||
extern device::Device *MS5611_spi_interface(ms5611::prom_u &prom_buf) weak_function;
|
||||
extern device::Device *MS5611_spi_interface(ms5611::prom_u &prom_buf, bool external_bus) weak_function;
|
||||
extern device::Device *MS5611_i2c_interface(ms5611::prom_u &prom_buf) weak_function;
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user