Compare commits

..

No commits in common. "v1.7.2" and "v1.7.0" have entirely different histories.

46 changed files with 25545 additions and 1007 deletions

View File

@ -413,27 +413,6 @@ if (all_posix_cmake_targets)
)
endif()
#=============================================================================
# uORB graph generation: add a custom target 'uorb_graph'
#
set(uorb_graph_config ${BOARD})
set(graph_module_list "")
foreach(module ${config_module_list})
set(graph_module_list "${graph_module_list}" "--src-path" "src/${module}")
endforeach()
add_custom_command(OUTPUT ${uorb_graph_config}
COMMAND ${PYTHON_EXECUTABLE} ${PX4_SOURCE_DIR}/Tools/uorb_graph/create.py
${module_list}
--exclude-path src/examples
--file ${PX4_SOURCE_DIR}/Tools/uorb_graph/graph_${uorb_graph_config}
WORKING_DIRECTORY ${PX4_SOURCE_DIR}
COMMENT "Generating uORB graph"
)
add_custom_target(uorb_graph DEPENDS ${uorb_graph_config})
#=============================================================================
# packaging
#

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

BIN
Documentation/dsm_bind.odt Normal file

Binary file not shown.

BIN
Documentation/dsm_bind.pdf Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

View File

@ -0,0 +1,98 @@
[TOC]
# Introduction
The HIL architecture allows you to test the flight stack replacing the real physical vehicle and sensors with a simulator of vehicle dynamics and sensor outputs. The flight stack "is not aware" that it is not on a real vehicle. This is a powerful tool for develping and testing code rapidly in a benchtop environment.
The flight stack can be run anywhere that supports a network connection to the simulator (with sufficient bandwidth and latency to transport the sensor and actuator messages). This can be on a standard linux workstation, an on-target linux image, or the on-target DSP image. These modes can be selected based on the goals of the testing. Workstation is useful for rapid testing in a tool-rich environment. DSP image testing is the closest to the final implementation, so is useful for testing actual HW operation, other than the physical sensing and actuation.
## Px4 High-level HIL Architecture
A diagram of the setup described is shown here. Note that UDP port numbers are only displayed on the socket server and are left blank on the socket client.
(???NOTES: This diagram needs to be updated to use control inputs over UDP, either from QGC or from other)
![SITL Diagram](./SITL_Diagram_QGC.png "SITL Diagram")
## Requirements
The simulator that is currently supported is jMAVSim. The setup described here requires PX4 and jMAVSim installed and running. qGroundControl (QGC) is also required because it is the supported method of providing manual control commands.
## Assumptions
# Compiling Code
## JMAVSim
### Platform Requirements
Linux with java-1.7.x or greater
### Build Instructions
In a clean directory
```
> git clone https://github.com/PX4/jMAVSim.git
> cd jMAVSim
> git submodule init
> git submodule update
> ant
```
## qGroundControl
### Platform Requirements
Windows 7
Logitech Gamepad F310 joystick controller
### Download/Install Instructions
Download QGC from http://qgroundcontrol.org/downloads and install using the windows executable.
## PX4
### Platform Requirements
Linux or Eagle with a working IP interface (?? does this need further instructions?)
### Build Host Requirements
(???Notes: Windows?)
### Download & Build Instructions
### Installing binaries on the Qualcomm Target
# Running PX4 in HIL Mode
## Starting PX4 on Qualcomm Eagle
```
> adb shell
# bash
root@linaro-developer:/# cd ???
root@linaro-developer:/# ./px4
App name: px4
Enter a command and its args:
uorb start
muorb start
mavlink start -u 14556
simulator start -p
```
## Starting jMAVSim
In the directory where jMAVSim is installed
```
java -cp lib/*:out/production/jmavsim.jar me.drton.jmavsim.Simulator -udp <IPADDR>:14560 -n 100
```
replacing <IPADDR> with the IP address of the machine running PX4 (Eagle). This can be found by running "ifconfig" on that machine.
## Starting qGroundControl
Launch the qGroundControl application
1. Set up the communication to the flight stack. In the menu File:Settings:CommLinks, select Add. Enter a Link Name of your choice. Select Link Type: UDP. Set the listening port to an unused port (example: 14561). Select Add. Enter the IP address and port of the PX4 Mavlink app, which is <IPADDR>:14556 with <IPADDR> being the IP address of the Eagle board. Select OK.
1. Set up the joystick. Plug in the joystick to your Windows machine. In the menu File:Settings:CommLinks, check Enable Controllers. Select "Gamepad F310". Select "Manual". Set the axes/channel mapping to 0:Yaw, 1:Throttle, 2:unset, 3:Pitch, 4:Roll. Seletct "Inverted" for the throttle axis. Click "Calibrate range". Move the right joystick through its full range of motion. Move the left joystick full left then full right. Move the left joystick full forward (but not full backward). Click "end calibration."
1. Connect to the flight stack. Click Analyze. Click the "Connect" button in the upper right, and select the connection that you created in the first step.
You should now be connected to the flight stack. You can see incoming Mavlink packets using the MAVLink Instpector (from Advanced:Tool Widgets)
## Controlling PX4 flight in HIL Mode
The joystick can now be used to fly the simulated vehicle. The jMAVSim world visualization gives a FPV view, and QGC can be used to display instruments such as artificial horizon and maps (if GPS simulation is enabled).
# Debugging/FAQ

View File

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

2
Documentation/versionfilter.sh Executable file
View File

@ -0,0 +1,2 @@
#!/bin/sh
git log --pretty=format:"Last change: commit %h - %aN, %ar : %s" -1 $1 || echo no git

145
Jenkinsfile vendored
View File

@ -1,6 +1,17 @@
pipeline {
agent none
stages {
stage('Quality Checks') {
agent {
docker {
image 'px4io/px4-dev-base:2017-10-23'
args '-e CI=true'
}
}
steps {
sh 'make check_format'
}
}
stage('Build') {
steps {
@ -44,7 +55,7 @@ pipeline {
sh "make clean"
sh "ccache -z"
sh "git fetch --tags"
sh "make px4io-v2_default"
sh "make nuttx_px4io-v2_default"
sh "make nuttx_px4fmu-v2_default"
sh "make nuttx_px4fmu-v2_lpe"
sh "make nuttx_px4fmu-v3_default"
@ -107,28 +118,6 @@ pipeline {
}
// posix_sitl
for (def option in ["sitl_default", "sitl_rtps"]) {
def node_name = "${option}"
builds["${node_name}"] = {
node {
stage("Build Test ${node_name}") {
docker.image('px4io/px4-dev-base:2017-10-23').inside('-e CI=true -e CCACHE_BASEDIR=$WORKSPACE -e CCACHE_DIR=/tmp/ccache -v /tmp/ccache:/tmp/ccache:rw') {
stage("${node_name}") {
checkout scm
sh "make clean"
sh "ccache -z"
sh "make posix_${node_name}"
sh "ccache -s"
}
}
}
}
}
}
// raspberry pi and bebop (armhf)
for (def option in ["rpi_cross", "bebop_default"]) {
def node_name = "${option}"
@ -197,8 +186,8 @@ pipeline {
}
// GCC7 posix
for (def option in ["sitl_default"]) {
// GCC7 tests
for (def option in ["posix_sitl_default", "nuttx_px4fmu-v5_default"]) {
def node_name = "${option}"
builds["${node_name} (GCC7)"] = {
@ -209,28 +198,7 @@ pipeline {
checkout scm
sh "make clean"
sh "ccache -z"
sh "make posix_${node_name}"
sh "ccache -s"
}
}
}
}
}
}
// GCC7 nuttx
for (def option in ["px4fmu-v5_default"]) {
def node_name = "${option}"
builds["${node_name} (GCC7)"] = {
node {
stage("Build Test ${node_name} (GCC7)") {
docker.image('px4io/px4-dev-base-archlinux:2017-12-08').inside('-e CI=true -e CCACHE_BASEDIR=$WORKSPACE -e CCACHE_DIR=/tmp/ccache -v /tmp/ccache:/tmp/ccache:rw') {
stage("${node_name}") {
checkout scm
sh "make clean"
sh "ccache -z"
sh "make nuttx_${node_name}"
sh "make ${node_name}"
sh "ccache -s"
}
}
@ -247,76 +215,19 @@ pipeline {
stage('Test') {
parallel {
stage('check style') {
agent {
docker {
image 'px4io/px4-dev-base:2017-10-23'
args '-e CI=true'
}
}
steps {
sh 'make check_format'
}
}
stage('clang analyzer') {
agent {
docker {
image 'px4io/px4-dev-clang:2017-10-23'
args '-e CI=true -e CCACHE_BASEDIR=$WORKSPACE -e CCACHE_DIR=/tmp/ccache -v /tmp/ccache:/tmp/ccache:rw'
}
}
steps {
sh 'make clean'
sh 'make scan-build'
// publish html
publishHTML target: [
reportTitles: 'clang static analyzer',
allowMissing: false,
alwaysLinkToLastBuild: true,
keepAll: true,
reportDir: 'build/scan-build/report_latest',
reportFiles: '*',
reportName: 'Clang Static Analyzer'
]
}
}
stage('clang tidy') {
agent {
docker {
image 'px4io/px4-dev-clang:2017-10-23'
args '-e CI=true -e CCACHE_BASEDIR=$WORKSPACE -e CCACHE_DIR=/tmp/ccache -v /tmp/ccache:/tmp/ccache:rw'
}
}
steps {
sh 'make clean'
sh 'make clang-tidy-quiet'
}
}
stage('cppcheck') {
agent {
docker {
image 'px4io/px4-dev-base:ubuntu17.10'
args '-e CI=true -e CCACHE_BASEDIR=$WORKSPACE -e CCACHE_DIR=/tmp/ccache -v /tmp/ccache:/tmp/ccache:rw'
}
}
steps {
sh 'make clean'
sh 'make cppcheck'
// publish html
publishHTML target: [
reportTitles: 'Cppcheck',
allowMissing: false,
alwaysLinkToLastBuild: true,
keepAll: true,
reportDir: 'build/cppcheck/',
reportFiles: '*',
reportName: 'Cppcheck'
]
}
}
// temporarily disabled until build resources are available
//stage('clang-tidy') {
// agent {
// docker {
// image 'px4io/px4-dev-clang:2017-10-23'
// args '-e CI=true -e CCACHE_BASEDIR=$WORKSPACE -e CCACHE_DIR=/tmp/ccache -v /tmp/ccache:/tmp/ccache:rw'
// }
// }
// steps {
// sh 'make clean'
// sh 'make clang-tidy-quiet'
// }
//}
stage('tests') {
agent {

View File

@ -218,7 +218,7 @@ check_rtps: \
check_posix_sitl_rtps \
sizes
.PHONY: sizes check quick_check check_rtps uorb_graphs
.PHONY: sizes check quick_check check_rtps
sizes:
@-find build -name *.elf -type f | xargs size 2> /dev/null || :
@ -235,14 +235,6 @@ check_%:
@$(MAKE) --no-print-directory $(subst check_,,$@)
@echo
uorb_graphs:
@./Tools/uorb_graph/create_from_startupscript.sh
@./Tools/uorb_graph/create.py --src-path src --exclude-path src/examples --file Tools/uorb_graph/graph_full
@$(MAKE) --no-print-directory px4fmu-v2_default uorb_graph
@$(MAKE) --no-print-directory px4fmu-v4_default uorb_graph
@$(MAKE) --no-print-directory posix_sitl_default uorb_graph
.PHONY: coverity_scan
coverity_scan: posix_sitl_default
@ -264,6 +256,37 @@ module_documentation:
px4_metadata: parameters_metadata airframe_metadata module_documentation
# S3 upload helpers
# --------------------------------------------------------------------
# s3cmd uses these ENV variables
# AWS_ACCESS_KEY_ID
# AWS_SECRET_ACCESS_KEY
# AWS_S3_BUCKET
.PHONY: s3put_firmware s3put_qgc_firmware s3put_px4fmu_firmware s3put_misc_qgc_extra_firmware s3put_metadata s3put_scan-build s3put_cppcheck s3put_coverage
s3put_qgc_firmware: s3put_px4fmu_firmware s3put_misc_qgc_extra_firmware
s3put_px4fmu_firmware: px4fmu_firmware
@find $(SRC_DIR)/build -name "*.px4" -exec $(SRC_DIR)/Tools/s3put.sh "{}" \;
s3put_misc_qgc_extra_firmware: misc_qgc_extra_firmware
@find $(SRC_DIR)/build -name "*.px4" -exec $(SRC_DIR)/Tools/s3put.sh "{}" \;
s3put_metadata: px4_metadata
@$(SRC_DIR)/Tools/s3put.sh airframes.md
@$(SRC_DIR)/Tools/s3put.sh airframes.xml
@$(SRC_DIR)/Tools/s3put.sh parameters.xml
@$(SRC_DIR)/Tools/s3put.sh parameters.md
s3put_scan-build: scan-build
@$(SRC_DIR)/Tools/s3put.sh `find $(SRC_DIR)/build/scan-build -mindepth 1 -maxdepth 1 -type d`/
s3put_cppcheck: cppcheck
@$(SRC_DIR)/Tools/s3put.sh $(SRC_DIR)/build/cppcheck/
s3put_coverage: tests_coverage
@$(SRC_DIR)/Tools/s3put.sh $(SRC_DIR)/build/posix_sitl_default/coverage-html/
# Astyle
# --------------------------------------------------------------------
.PHONY: check_format format
@ -297,12 +320,9 @@ tests_coverage:
scan-build:
@export CCC_CC=clang
@export CCC_CXX=clang++
@rm -rf $(SRC_DIR)/build/posix_sitl_default-scan-build
@rm -rf $(SRC_DIR)/build/scan-build/report_latest
@mkdir -p $(SRC_DIR)/build/posix_sitl_default-scan-build
@cd $(SRC_DIR)/build/posix_sitl_default-scan-build && scan-build cmake $(SRC_DIR) -GNinja -DCONFIG=posix_sitl_default
@scan-build -o $(SRC_DIR)/build/scan-build cmake --build $(SRC_DIR)/build/posix_sitl_default-scan-build
@find $(SRC_DIR)/build/scan-build -maxdepth 1 -mindepth 1 -type d -exec cp -r "{}" $(SRC_DIR)/build/scan-build/report_latest \;
posix_sitl_default-clang:
@mkdir -p $(SRC_DIR)/build/posix_sitl_default-clang

View File

@ -1,42 +1,34 @@
# PX4 Pro Drone Autopilot
## PX4 Pro Drone Autopilot ##
[![Releases](https://img.shields.io/github/release/PX4/Firmware.svg)](https://github.com/PX4/Firmware/releases) [![DOI](https://zenodo.org/badge/22634/PX4/Firmware.svg)](https://zenodo.org/badge/latestdoi/22634/PX4/Firmware)
[![Build Status](http://ci.px4.io:8080/buildStatus/icon?job=Firmware/master)](http://ci.px4.io:8080/blue/organizations/jenkins/Firmware/activity) [![Coverity Scan](https://scan.coverity.com/projects/3966/badge.svg?flat=1)](https://scan.coverity.com/projects/3966?tab=overview)
[![Releases](https://img.shields.io/github/release/PX4/Firmware.svg)](https://github.com/PX4/Firmware/releases) [![DOI](https://zenodo.org/badge/22634/PX4/Firmware.svg)](https://zenodo.org/badge/latestdoi/22634/PX4/Firmware) [![Build Status](https://travis-ci.org/PX4/Firmware.svg?branch=master)](https://travis-ci.org/PX4/Firmware) [![Coverity Scan](https://scan.coverity.com/projects/3966/badge.svg?flat=1)](https://scan.coverity.com/projects/3966?tab=overview)
[![Slack](https://px4-slack.herokuapp.com/badge.svg)](http://slack.px4.io)
This repository holds the [PX4 Pro](http://px4.io) flight control solution for drones, with the main applications located in the [src/modules](https://github.com/PX4/Firmware/tree/master/src/modules) directory. It also contains the PX4 Drone Middleware Platform, which provides drivers and middleware to run drones.
* Official Website: http://px4.io (License: BSD 3-clause, [LICENSE](https://github.com/PX4/Firmware/blob/master/LICENSE))
* [Supported airframes](https://docs.px4.io/en/airframes/airframe_reference.html) ([portfolio](http://px4.io/#airframes)):
* [Multicopters](https://docs.px4.io/en/airframes/airframe_reference.html#copter)
* [Fixed wing](https://docs.px4.io/en/airframes/airframe_reference.html#plane)
* [VTOL](https://docs.px4.io/en/airframes/airframe_reference.html#vtol)
* many more experimental types (Rovers, Blimps, Boats, Submarines, etc)
* Releases: [Downloads](https://github.com/PX4/Firmware/releases)
## PX4 Users
The [PX4 User Guide](https://docs.px4.io/en/) explains how to assemble [supported vehicles](https://docs.px4.io/en/airframes/airframe_reference.html) and fly drones with PX4.
See the [forum and chat](https://docs.px4.io/en/#support) if you need help!
## PX4 Developers
This [Developer Guide](https://dev.px4.io/) is for software developers who want to modify the flight stack and middleware (e.g. to add new flight modes), hardware integrators who want to support new flight controller boards and peripherals, any anyone who wants to get PX4 working on a new (unsupported) airframe/vehicle.
Developers should read the [Guide for Contributions](https://dev.px4.io/en/contribute/).
See the [forum and chat](https://dev.px4.io/en/#support) if you need help!
* Official Website: http://px4.io (License: BSD 3-clause, [LICENSE.md](https://github.com/PX4/Firmware/blob/master/LICENSE.md))
* Supported airframes:
* [Multicopters](http://px4.io/portfolio_category/multicopter/)
* [Fixed wing](http://px4.io/portfolio_category/plane/)
* [VTOL](http://px4.io/portfolio_category/vtol/)
* many more experimental types (Rovers, Blimps, Boats, Submarines, etc)
* Releases: [Downloads](https://github.com/PX4/Firmware/releases)
Please refer to the [user documentation](https://docs.px4.io/en/) and [user forum](http://discuss.px4.io) for flying drones with the PX4 flight stack.
### Weekly Dev Call
The PX4 Dev Team syncs up on a [weekly dev call](https://dev.px4.io/en/contribute/#dev_call).
The PX4 Dev Team syncs up on a [weekly dev call](https://dev.px4.io/en/contribute/).
> **Note** The dev call is open to all interested developers (not just the core dev team). This is a great opportunity to meet the team and contribute to the ongoing development of the platform.
* [Wednesday 17:00 Central European Time, 11:00 Eastern Time, 08:00 Pacific Standard Time](https://www.google.com/calendar/embed?src=bGludXhmb3VuZGF0aW9uLm9yZ19nMjF0dmFtMjRtN3BtN2poZXYwMWJ2bHFoOEBncm91cC5jYWxlbmRhci5nb29nbGUuY29t)
* [Uber conference (dial-in or web client)](https://www.uberconference.com/lf-dronecode)
* The agenda is announced in advance on the [PX4 Discuss](http://discuss.px4.io/c/weekly-dev-call)
* Issues and PRs may be labelled [devcall](https://github.com/PX4/Firmware/issues?q=is%3Aopen+is%3Aissue+label%3Adevcall) to flag them for discussion
### Developers ###
* [Developer Guide](https://dev.px4.io/)
* [Build instructions](https://dev.px4.io/en/setup/building_px4.html)
* [Guide for Contributions](https://dev.px4.io/en/contribute/)
## Maintenance Team
@ -79,32 +71,28 @@ The PX4 Dev Team syncs up on a [weekly dev call](https://dev.px4.io/en/contribut
* [Airmind MindPX / MindRacer](https://github.com/PX4/Firmware/labels/mindpx) - [Henry Zhang](https://github.com/iZhangHui)
* RTPS/ROS2 Interface - [Vicente Monge](https://github.com/vicenteeprosima)
See also [About Us](http://px4.io/about-us/#development_team) (px4.io) and the [contributors list](https://github.com/PX4/Firmware/graphs/contributors) (Github).
## Supported Hardware
This repository contains code supporting these boards:
* [Snapdragon Flight](https://docs.px4.io/en/flight_controller/snapdragon_flight.html)
* [Intel Aero](https://docs.px4.io/en/flight_controller/intel_aero.html)
* [Raspberry PI with Navio 2](https://docs.px4.io/en/flight_controller/raspberry_pi_navio2.html)
* [Snapdragon Flight](https://dev.px4.io/en/flight_controller/snapdragon_flight.html)
* [Intel Aero](https://dev.px4.io/en/flight_controller/intel_aero.html)
* [Raspberry PI with Navio 2](https://dev.px4.io/en/flight_controller/raspberry_pi.html)
* [Parrot Bebop 2](https://dev.px4.io/en/advanced/parrot_bebop.html)
* FMUv2.x
* [Pixhawk](https://docs.px4.io/en/flight_controller/pixhawk.html)
* [Pixhawk Mini](https://docs.px4.io/en/flight_controller/pixhawk_mini.html)
* [Pixfalcon](https://docs.px4.io/en/flight_controller/pixfalcon.html)
* [Pixhawk](https://dev.px4.io/en/flight_controller/pixhawk.html)
* Pixhawk Mini
* [Pixfalcon](https://dev.px4.io/en/flight_controller/pixfalcon.html)
* FMUv3.x [Pixhawk 2](https://pixhawk.org/modules/pixhawk2)
* FMUv4.x
* [Pixracer](https://docs.px4.io/en/flight_controller/pixracer.html)
* [Pixhawk 3 Pro](https://docs.px4.io/en/flight_controller/pixhawk3_pro.html)
* [Pixracer](https://dev.px4.io/en/flight_controller/pixracer.html)
* Pixhawk 3 Pro
* FMUv5.x (ARM Cortex M7, future Pixhawk)
* [STM32F4Discovery](http://www.st.com/en/evaluation-tools/stm32f4discovery.html) (basic support) [Tutorial](https://pixhawk.org/modules/stm32f4discovery)
* [Gumstix AeroCore](https://www.gumstix.com/aerocore-2/) (only v2)
* STM32F4Discovery (basic support) [Tutorial](https://pixhawk.org/modules/stm32f4discovery)
* Gumstix AeroCore (v1 and v2)
* [Airmind MindPX V2.8](http://www.mindpx.net/assets/accessories/UserGuide_MindPX.pdf)
* [Airmind MindRacer V1.2](http://mindpx.net/assets/accessories/mindracer_user_guide_v1.2.pdf)
* [Bitcraze Crazyflie 2.0](https://docs.px4.io/en/flight_controller/crazyflie2.html)
* [Bitcraze Crazyflie 2.0](https://dev.px4.io/en/flight_controller/crazyflie2.html)
Additional information about supported hardware can be found in [PX4 user Guide > Autopilot Hardware](https://docs.px4.io/en/flight_controller/).
## Project Milestones
## Project Roadmap
A high level project roadmap is available [here](https://www.dronecode.org/roadmap/).
The PX4 software and Pixhawk hardware (which has been designed for it) has been created in 2011 by [Lorenz Meier](https://github.com/LorenzMeier).

View File

@ -4,17 +4,20 @@ set VEHICLE_TYPE vtol
if [ $AUTOCNF == yes ]
then
param set MIS_TAKEOFF_ALT 20
param set MIS_YAW_TMT 10
param set MPC_ACC_HOR_MAX 2.0
param set MPC_LAND_SPEED 0.7
param set MPC_TKO_SPEED 1.0
param set MPC_XY_VEL_MAX 4.0
param set MPC_Z_VEL_MAX_DN 1.5
param set MC_ROLL_P 6.0
param set MC_PITCH_P 6.0
param set MC_YAW_P 4
#
# Default parameters for mission and position handling
#
param set NAV_ACC_RAD 3
param set MPC_TKO_SPEED 1.0
param set MPC_LAND_SPEED 0.7
param set MPC_Z_VEL_MAX_DN 1.5
param set MPC_XY_VEL_MAX 4.0
param set MIS_YAW_TMT 10
param set MPC_ACC_HOR_MAX 2.0
param set RTL_LAND_DELAY 0
fi

View File

@ -3,17 +3,8 @@
function check_git_submodule {
# The .git exists in a submodule if init and update have been done.
if [[ -f $1"/.git" || -d $1"/.git" ]];
if [ "$CI" != "true" ] && [[ -f $1"/.git" || -d $1"/.git" ]];
then
if [ "$CI" == "true" ];
then
git submodule sync --recursive -- $1
git submodule update --init --recursive --force -- $1 || true
git submodule update --init --recursive --force -- $1
exit 0
fi
SUBMODULE_STATUS=$(git submodule summary "$1")
STATUSRETVAL=$(echo $SUBMODULE_STATUS | grep -A20 -i "$1")
if ! [[ -z "$STATUSRETVAL" ]];
@ -44,8 +35,8 @@ then
elif [ "$user_cmd" == "u" ]
then
git submodule sync --recursive -- $1
git submodule update --init --recursive -- $1 || true
git submodule update --init --recursive --force -- $1
git submodule update --init --recursive --force --quiet -- $1 || true
git submodule update --init --recursive -- $1
echo "Submodule fixed, continuing build.."
else
echo "Build aborted."
@ -53,9 +44,9 @@ then
fi
fi
else
git submodule sync --recursive --quiet -- $1
git submodule update --init --recursive -- $1 || true
git submodule update --init --recursive -- $1
git submodule sync --recursive -- $1
git submodule update --init --recursive --force -- $1 || true
git submodule update --init --recursive --force -- $1
fi
}

23
Tools/s3put.sh Executable file
View File

@ -0,0 +1,23 @@
#!/bin/bash
filename=${1}
# Requires these ENV variables
# AWS_ACCESS_KEY_ID
# AWS_SECRET_ACCESS_KEY
# AWS_S3_BUCKET
[ -z "$AWS_ACCESS_KEY_ID" ] && { echo "ERROR: Need to set AWS_ACCESS_KEY_ID"; exit 1; }
[ -z "$AWS_SECRET_ACCESS_KEY" ] && { echo "ERROR: Need to set AWS_SECRET_ACCESS_KEY"; exit 1; }
[ -z "$AWS_S3_BUCKET" ] && { echo "ERROR: Need to set AWS_S3_BUCKET"; exit 1; }
if [ -f ${filename} ]; then
base_file_name=`basename $filename`
s3cmd --access_key=${AWS_ACCESS_KEY_ID} --secret_key=${AWS_SECRET_ACCESS_KEY} put ${filename} s3://${AWS_S3_BUCKET}/${base_file_name}
elif [ -d ${filename} ]; then
dir_name=$filename
s3cmd --access_key=${AWS_ACCESS_KEY_ID} --secret_key=${AWS_SECRET_ACCESS_KEY} put -r ${dir_name} s3://${AWS_S3_BUCKET}/
else
echo "ERROR: ${file} doesn't exist"
exit 1
fi

View File

@ -1,2 +0,0 @@
*.json

View File

@ -1,641 +0,0 @@
#! /usr/bin/env python
from __future__ import print_function
import argparse
import os
import codecs
import re
import colorsys
import json
parser = argparse.ArgumentParser(
description='Generate uORB pub/sub dependency graph from source code')
parser.add_argument('-s', '--src-path', action='append',
help='Source path(s) (default=src, can be specified multiple times)',
default=[])
parser.add_argument('-e', '--exclude-path', action='append',
help='Excluded path(s), can be specified multiple times',
default=[])
parser.add_argument('-f', '--file', metavar='file', action='store',
help='output file name prefix',
default='graph')
parser.add_argument('-o', '--output', metavar='output', action='store',
help='output format (json or graphviz)',
default='json')
parser.add_argument('--use-topic-union', action='store_true',
help='''
Use the union of all publication and subscription topics (useful for complete
graphs or only few/single module(s)). The default is to use the intersection
(remove topics that have no subscriber or no publisher)''')
parser.add_argument('-m', '--modules', action='store',
help='Comma-separated whitelist of modules (the module\'s '+
'MAIN, e.g. from a startup script)',
default='')
args = parser.parse_args()
g_debug = False
def dbg_print(string):
if g_debug:
print(string)
def get_N_colors(N, s=0.8, v=0.9):
""" get N distinct colors as a list of hex strings """
HSV_tuples = [(x*1.0/N, s, v) for x in range(N)]
hex_out = []
for rgb in HSV_tuples:
rgb = map(lambda x: int(x*255), colorsys.hsv_to_rgb(*rgb))
hex_out.append("#"+"".join(map(lambda x: format(x, '02x'), rgb)))
return hex_out
class PubSub:
""" Collects either publication or subscription information for nodes
(modules and topics) & edges """
def __init__(self, is_publication, topic_blacklist, orb_pub_sub_regexes, special_cases):
"""
:param is_publication: if True, publications, False for
subscriptions
:param topic_blacklist: list of topics to blacklist
:param orb_pub_sub_regexes: list of regexes to extract orb calls
(e.g. orb_subscribe). They need to have 2 captures, the second
one is the one capturing ORB_ID(<topic>
"""
self._module_pubsubs = {} # key = module name, value = set of topic names
self._special_cases = special_cases
self._special_cases_matched = None
self._topic_blacklist = topic_blacklist
self._orb_pub_sub_regexes = orb_pub_sub_regexes
if is_publication:
self._method = 'Publication'
else:
self._method = 'Subscription'
def reset(self):
self._special_cases_matched = [False]*len(self._special_cases)
def filter_modules(self, module_whitelist):
remove = [k for k in self._module_pubsubs if k not in module_whitelist]
for k in remove: del self._module_pubsubs[k]
def check_if_match_found(self, modules):
""" check if all special cases got a match (if not, it means the source
code got changed)
"""
for i, (module_match, file_match_re, src_match_re, _) in enumerate(self._special_cases):
if module_match in modules and src_match_re is not None:
if not self._special_cases_matched[i]:
raise Exception('Module '+module_match+
': no match for '+self._method+' special case'+
src_match_re.pattern+'. The case needs to be updated')
def extract(self, file_name, src_str, module, orb_id_vehicle_attitude_controls_topic):
""" Extract subscribed/published topics from a source string
:param src_str: string of C/C++ code with comments and whitespace removed
"""
orb_pubsub_matches = []
for regex in self._orb_pub_sub_regexes:
orb_pubsub_matches += re.findall(regex, src_str)
orb_id = 'ORB_ID('
for _, match in orb_pubsub_matches:
if match == 'ORB_ID_VEHICLE_ATTITUDE_CONTROLS': # special case
match = orb_id+orb_id_vehicle_attitude_controls_topic
# match has the form: '[ORB_ID(]<topic_name>'
if match.startswith(orb_id):
topic_name = match[len(orb_id):]
self._add_topic(topic_name, file_name, module)
else:
ignore_found = False
for module_match, file_match_re, _, ignore_re in self._special_cases:
if module == module_match:
if file_match_re.search(file_name):
if ignore_re.search(match):
ignore_found = True
if not ignore_found:
# If we land here, we need to add another special case
raise Exception(self._method+' w/o ORB_ID(): '+match+' in '
+file_name+' ('+module+'). You need to add another special case.')
# handle special cases
for i, (module_match, file_match_re, src_match_re, _) in enumerate(self._special_cases):
if src_match_re is None:
continue
if module == module_match:
if file_match_re.search(file_name):
matches = src_match_re.findall(src_str)
for match in matches:
# match has the form: '[ORB_ID(]<topic_name>'
if match.startswith(orb_id):
topic_name = match[len(orb_id):]
dbg_print('Found '+self._method+' for special case in '
+module+': '+topic_name)
self._add_topic(topic_name, file_name, module)
self._special_cases_matched[i] = True
else:
# this is not fatal, as it could be a method delaration/definition
dbg_print('Special case '+self._method+' w/o ORB_ID(): '
+match+' in '+file_name+' ('+module+')')
def _add_topic(self, topic_name, file_name, module):
""" add a subscription/publication for a module
"""
if topic_name in self._topic_blacklist:
dbg_print('ignoring blacklisted topic '+topic_name)
return
if module is None:
if not file_name.endswith('hott/messages.cpp'): # hott has a special module structure. just ignore it
print('Warning: found '+self._method+' without associated module: '
+topic_name+' in '+file_name)
return
if not module in self._module_pubsubs:
self._module_pubsubs[module] = set()
self._module_pubsubs[module].add(topic_name)
def get_topics(self, modules):
""" get the set of topics
:param modules: list of modules to take into account
"""
topics = set()
for module in modules:
if module in self._module_pubsubs:
topics |= self._module_pubsubs[module]
return topics
@property
def pubsubs(self):
""" get dict of all publication/subscriptions (key=modules, value=set of
topic names"""
return self._module_pubsubs
class Graph:
""" Collects Node and Edge information by parsing the source tree """
def __init__(self, module_whitelist=[], topic_blacklist=[]):
self._current_module = [] # stack with current module (they can be nested)
self._all_modules = set() # set of all found modules
self._comment_remove_pattern = re.compile(
r'//.*?$|/\*.*?\*/|\'(?:\\.|[^\\\'])*\'|"(?:\\.|[^\\"])*"',
re.DOTALL | re.MULTILINE)
self._whitespace_pattern = re.compile(r'\s+')
self._module_whitelist = module_whitelist
self._excluded_paths = []
self._orb_id_vehicle_attitude_controls_topic = 'actuator_controls_0'
self._orb_id_vehicle_attitude_controls_re = \
re.compile(r'\#define\s+ORB_ID_VEHICLE_ATTITUDE_CONTROLS\s+([^,)]+)')
self._module_subscriptions = {} # key = module name, value = set of topic names
self._module_publications = {} # key = module name, value = set of topic names
self._modules = set() # all modules
self._topics = set() # all topics
self._topic_colors = {} # key = topic, value = color (html string)
# handle special cases
# format: list of tuples with 4 entries:
# - module name to match (module MAIN)
# - regex for file name(s) to match within the module (matched against the full path)
# - regex to extract the topic name: the match must be ORB_ID(<topic_name>
# Note: whitespace is removed from source code, so it does not need to be
# accounted for in the regex.
# If this is None, it will just be ignored
# - regex to ignore matches in the form orb_[subscribe|advertise](<match>
# (the expectation is that the previous matching ORB_ID() will be passed
# to this, so that we can ignore it)
special_cases_sub = [
('sensors', r'voted_sensors_update\.cpp$', r'\binit_sensor_class\b\(([^,)]+)', r'^meta$'),
('mavlink', r'.*', r'\badd_orb_subscription\b\(([^,)]+)', r'^_topic$'),
('sdlog2', r'.*', None, r'^topic$'),
('logger', r'.*', None, r'^(topic|sub\.metadata|_polling_topic_meta)$'),
('uavcan', r'uavcan_main\.cpp$', r'\b_control_topics\[[0-9]\]=([^,)]+)', r'^_control_topics\[i\]$'),
('tap_esc', r'.*', r'\b_control_topics\[[0-9]\]=([^,)]+)', r'^_control_topics\[i\]$'),
('pwm_out_sim', r'.*', r'\b_control_topics\[[0-9]\]=([^,)]+)', r'^_control_topics\[i\]$'),
('snapdragon_pwm_out', r'.*', r'\b_controls_topics\[[0-9]\]=([^,)]+)', r'^_controls_topics\[i\]$'),
('fmu', r'.*', r'\b_control_topics\[[0-9]\]=([^,)]+)', r'^_control_topics\[i\]$'),
('linux_pwm_out', r'.*', r'\b_controls_topics\[[0-9]\]=([^,)]+)', r'^_controls_topics\[i\]$'),
]
special_cases_sub = [(a, re.compile(b), re.compile(c) if c is not None else None, re.compile(d))
for a,b,c,d in special_cases_sub]
self._subscriptions = PubSub(False, topic_blacklist,
[r"\borb_subscribe(_multi|)\b\(([^,)]+)"],
special_cases_sub)
special_cases_pub = [
('replay', r'replay_main\.cpp$', None, r'^sub\.orb_meta$'),
('fw_pos_control_l1', r'FixedwingPositionControl\.cpp$', r'\b_attitude_setpoint_id=([^,)]+)', r'^_attitude_setpoint_id$'),
('mc_pos_control', r'mc_pos_control_main\.cpp$', r'\b_attitude_setpoint_id=([^,)]+)', r'^_attitude_setpoint_id$'),
('mc_att_control', r'mc_att_control_main\.cpp$', r'\b_rates_sp_id=([^,)]+)', r'^_rates_sp_id$'),
('mc_att_control', r'mc_att_control_main\.cpp$', r'\b_actuators_id=([^,)]+)', r'^_actuators_id$'),
('fw_att_control', r'fw_att_control_main\.cpp$', r'\b_rates_sp_id=([^,)]+)', r'^_rates_sp_id$'),
('fw_att_control', r'fw_att_control_main\.cpp$', r'\b_actuators_id=([^,)]+)', r'^_actuators_id$'),
('fw_att_control', r'fw_att_control_main\.cpp$', r'\b_attitude_setpoint_id=([^,)]+)', r'^_attitude_setpoint_id$'),
('uavcan', r'sensors/.*\.cpp$', r'\bUavcanCDevSensorBridgeBase\([^{]*DEVICE_PATH,([^,)]+)', r'^_orb_topic$'),
('batt_smbus', r'batt_smbus\.cpp$', r'\b_batt_orb_id=([^,)]+)', r'^_batt_orb_id$'),
]
special_cases_pub = [(a, re.compile(b), re.compile(c) if c is not None else None, re.compile(d))
for a,b,c,d in special_cases_pub]
self._publications = PubSub(True, topic_blacklist,
[r"\borb_advertise(_multi|_queue|_multi_queue|)\b\(([^,)]+)",
r"\borb_publish_auto()\b\(([^,)]+)"],
special_cases_pub)
def _get_current_module(self):
if len(self._current_module) == 0:
return None
return self._current_module[-1]
def build(self, src_path_list, excluded_paths=[], use_topic_pubsub_union=True):
""" parse the source tree & extract pub/sub information.
:param use_topic_pubsub_union: if true, use all topics that have a
publisher or subscriber. If false, use only topics with at least one
publisher and subscriber.
fill in self._module_subsciptions & self._module_publications
"""
self._subscriptions.reset()
self._publications.reset()
self._excluded_paths = [os.path.normpath(p) for p in excluded_paths]
for path in src_path_list:
self._build_recursive(path)
# filter by whitelist
if len(self._module_whitelist) > 0:
self._subscriptions.filter_modules(self._module_whitelist)
self._publications.filter_modules(self._module_whitelist)
# modules & topics sets
self._modules = set(self._publications.pubsubs.keys() +
self._subscriptions.pubsubs.keys())
print('number of modules: '+str(len(self._modules)))
self._topics = self._get_topics(use_topic_pubsub_union=use_topic_pubsub_union)
print('number of topics: '+str(len(self._topics)))
# initialize colors
color_list = get_N_colors(len(self._topics), 0.7, 0.85)
self._topic_colors = {}
for i, topic in enumerate(self._topics):
self._topic_colors[topic] = color_list[i]
# validate that all special rules got used
self._subscriptions.check_if_match_found(self._all_modules)
self._publications.check_if_match_found(self._all_modules)
def _get_topics(self, use_topic_pubsub_union=True):
""" get the set of topics
"""
subscribed_topics = self._subscriptions.get_topics(self._modules)
published_topics = self._publications.get_topics(self._modules)
if use_topic_pubsub_union:
return subscribed_topics | published_topics
return subscribed_topics & published_topics
def _build_recursive(self, path):
if os.path.normpath(path) in self._excluded_paths:
dbg_print('ignoring excluded path '+path)
return
entries = os.listdir(path)
# check if entering a new module
cmake_file = 'CMakeLists.txt'
new_module = False
if cmake_file in entries:
new_module = self._extract_module_name(os.path.join(path, cmake_file))
# iterate directories recursively
for entry in entries:
file_name = os.path.join(path, entry)
if os.path.isdir(file_name):
self._build_recursive(file_name)
# iterate source files
# Note: we could skip the entries if we're not in a module, but we don't
# so that we get appropriate error messages to know where we miss subs
# or pubs
for entry in entries:
file_name = os.path.join(path, entry)
if os.path.isfile(file_name):
_, ext = os.path.splitext(file_name)
if ext in ['.cpp', '.c', '.h', '.hpp']:
self._process_source_file(file_name)
if new_module:
self._current_module.pop()
def _extract_module_name(self, file_name):
""" extract the module name from a CMakeLists.txt file and store
in self._current_module if there is any """
datafile = file(file_name)
found_module_def = False
for line in datafile:
if 'px4_add_module' in line: # must contain 'px4_add_module'
found_module_def = True
words = line.split()
# get the definition of MAIN
if found_module_def and 'MAIN' in words and len(words) >= 2:
self._current_module.append(words[1])
self._all_modules.add(words[1])
dbg_print('Found module name: '+words[1])
return True
return False
def _process_source_file(self, file_name):
""" extract information from a single source file """
with codecs.open(file_name, 'r', 'utf-8') as f:
try:
content = f.read()
except:
print('Failed reading file: %s, skipping content.' % path)
return
current_module = self._get_current_module()
if current_module == 'uorb_tests': # skip this
return
if current_module == 'uorb':
# search and validate the ORB_ID_VEHICLE_ATTITUDE_CONTROLS define
matches = self._orb_id_vehicle_attitude_controls_re.findall(content)
for match in matches:
if match != 'ORB_ID('+self._orb_id_vehicle_attitude_controls_topic:
# if we land here, you need to change _orb_id_vehicle_attitude_controls_topic
raise Exception(
'The extracted define for ORB_ID_VEHICLE_ATTITUDE_CONTROLS '
'is '+match+' but expected ORB_ID('+
self._orb_id_vehicle_attitude_controls_topic)
return # skip uorb module for the rest
if content.lower().find('orb_') != -1: # approximative filter to quickly
# discard files we're not interested in
# (speedup the parsing)
src = self._comment_remover(content)
src = re.sub(self._whitespace_pattern, '', src) # remove all whitespace
# subscriptions
self._subscriptions.extract(file_name, src, current_module,
self._orb_id_vehicle_attitude_controls_topic)
# publications
self._publications.extract(file_name, src, current_module,
self._orb_id_vehicle_attitude_controls_topic)
# TODO: handle Publication & Subscription template classes
def _comment_remover(self, text):
""" remove C++ & C style comments.
Source: https://stackoverflow.com/a/241506 """
def replacer(match):
s = match.group(0)
if s.startswith('/'):
return " " # note: a space and not an empty string
else:
return s
return re.sub(self._comment_remove_pattern, replacer, text)
@property
def modules(self):
""" get the set of all modules """
return self._modules
@property
def topics(self):
""" get set set of all topics """
return self._topics
@property
def topic_colors(self):
""" get a dict of all topic colors with key=topic, value=color """
return self._topic_colors
@property
def module_subscriptions(self):
""" get a dict of all subscriptions with key=module name, value=set(topic names) """
return self._subscriptions.pubsubs
@property
def module_publications(self):
""" get a dict of all publications with key=module name, value=set(topic names) """
return self._publications.pubsubs
class OutputGraphviz:
""" write graph using Graphviz """
def __init__(self, graph):
self._graph = graph
def write(self, file_name, engine='fdp',
show_publications=True, show_subscriptions=True):
""" write the graph to a file
:param engine: graphviz engine
- fdp works for large graphs
- neato works better for smaller graphs
- circo works for single modules
CLI: fdp graph.fv -Tpdf -o test.pdf
"""
print('Writing to '+file_name)
ratio = 1 # aspect ratio
modules = self._graph.modules
topics = self._graph.topics
topic_colors = self._graph.topic_colors
module_publications = self._graph.module_publications
module_subscriptions = self._graph.module_subscriptions
graph_attr={'splines': 'true', 'ratio': str(ratio), 'overlap': 'false'}
graph_attr['sep'] = '"+15,15"' # increase spacing between nodes
graph = Digraph(comment='autogenerated graph with graphviz using uorb_graph.py',
engine=engine, graph_attr=graph_attr)
# nodes
for module in modules:
graph.node('m_'+module, module, shape='box', fontcolor='#ffffff',
style='filled', color='#666666', fontsize='16')
for topic in topics:
graph.node('t_'+topic, topic, shape='ellipse', fontcolor='#ffffff',
style='filled', color=topic_colors[topic])
# edges
if show_publications:
for module in modules:
if module in module_publications:
for topic in module_publications[module]:
if topic in topics:
graph.edge('m_'+module, 't_'+topic,
color=topic_colors[topic], style='dashed')
if show_subscriptions:
for module in modules:
if module in module_subscriptions:
for topic in module_subscriptions[module]:
if topic in topics:
graph.edge('t_'+topic, 'm_'+module,
color=topic_colors[topic])
graph.render(file_name, view=False)
class OutputJSON:
""" write graph to a JSON file (that can be used with D3.js) """
def __init__(self, graph):
self._graph = graph
def write(self, file_name):
print('Writing to '+file_name)
modules = self._graph.modules
topics = self._graph.topics
topic_colors = self._graph.topic_colors
module_publications = self._graph.module_publications
module_subscriptions = self._graph.module_subscriptions
data = {}
nodes = []
# nodes
# (sort by length, such that short names are last. The rendering order
# will be the same, so that in case of an overlap, the shorter label
# will be on top)
for module in sorted(modules, key=len, reverse=True):
node = {}
node['id'] = 'm_'+module
node['name'] = module
node['type'] = 'module'
node['color'] = '#666666'
# TODO: add url to open module documentation?
nodes.append(node)
for topic in sorted(topics, key=len, reverse=True):
node = {}
node['id'] = 't_'+topic
node['name'] = topic
node['type'] = 'topic'
node['color'] = topic_colors[topic]
# url is opened when double-clicking on the node
# TODO: does not work for multi-topics
node['url'] = 'https://github.com/PX4/Firmware/blob/master/msg/'+topic+'.msg'
nodes.append(node)
data['nodes'] = nodes
edges = []
# edges
for module in modules:
if module in module_publications:
for topic in module_publications[module]:
if topic in topics:
edge = {}
edge['source'] = 'm_'+module
edge['target'] = 't_'+topic
edge['color'] = topic_colors[topic]
edge['style'] = 'dashed'
edges.append(edge)
for module in modules:
if module in module_subscriptions:
for topic in module_subscriptions[module]:
if topic in topics:
edge = {}
edge['source'] = 't_'+topic
edge['target'] = 'm_'+module
edge['color'] = topic_colors[topic]
edge['style'] = 'normal'
edges.append(edge)
data['links'] = edges
with open(file_name, 'w') as outfile:
json.dump(data, outfile) # add indent=2 for readable formatting
# ignore topics that are subscribed/published by many topics, but are not really
# useful to show in the graph
topic_blacklist = [ 'parameter_update', 'mavlink_log', 'log_message' ]
print('Excluded topics: '+str(topic_blacklist))
if len(args.modules) == 0:
module_whitelist = []
else:
module_whitelist = [ m.strip() for m in args.modules.split(',')]
graph = Graph(module_whitelist=module_whitelist, topic_blacklist=topic_blacklist)
if len(args.src_path) == 0:
args.src_path = ['src']
graph.build(args.src_path, args.exclude_path, use_topic_pubsub_union=args.use_topic_union)
if args.output == 'json':
output_json = OutputJSON(graph)
output_json.write(args.file+'.json')
elif args.output == 'graphviz':
try:
from graphviz import Digraph
except:
print("Failed to import graphviz.")
print("You may need to install it with 'pip install graphviz'")
print("")
raise
output_graphviz = OutputGraphviz(graph)
engine='fdp' # use neato or fdp
output_graphviz.write(args.file+'.fv', engine=engine)
output_graphviz.write(args.file+'_subs.fv', show_publications=False, engine=engine)
output_graphviz.write(args.file+'_pubs.fv', show_subscriptions=False, engine=engine)
else:
print('Error: unknown output format '+args.output)

View File

@ -1,13 +0,0 @@
#! /bin/bash
# create the graph from a posix (e.g. SITL) startup script
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
startup_file="$SCRIPT_DIR"/../../posix-configs/SITL/init/ekf2/typhoon_h480
[ -n "$1" ] && startup_file=$1
# get the modules as comma-separated list
modules=$(cat "$startup_file"|cut -f1 -d' '|sort|uniq|tr '\n' ,)
cd "$SCRIPT_DIR/../.."
"$SCRIPT_DIR"/create.py --src-path src -m "$modules" -f "$SCRIPT_DIR/graph_runtime_sitl"

View File

@ -9,8 +9,9 @@ float32 y # Y coordinate in meters
float32 z # Z coordinate in meters
float32 yaw # Yaw angle in radians
float32 direction_x # Takeoff direction in NED X
float32 direction_y # Takeoff direction in NED Y
float32 direction_z # Takeoff direction in NED Z
bool valid_alt # true when the altitude has been set
bool valid_hpos # true when the latitude and longitude have been set
bool manual_home # true when home position was set manually

View File

@ -331,7 +331,7 @@ transition_result_t arm_disarm(bool arm, orb_advert_t *mavlink_log_pub, const ch
* @brief This function initializes the home position of the vehicle. This happens first time we get a good GPS fix and each
* time the vehicle is armed with a good GPS fix.
**/
static bool commander_set_home_position(orb_advert_t &homePub, home_position_s &home,
static void commander_set_home_position(orb_advert_t &homePub, home_position_s &home,
const vehicle_local_position_s &localPosition, const vehicle_global_position_s &globalPosition,
const vehicle_attitude_s &attitude,
bool set_alt_only_to_lpos_ref);
@ -971,8 +971,7 @@ bool handle_command(struct vehicle_status_s *status_local, const struct safety_s
/* update home position on arming if at least 500 ms from commander start spent to avoid setting home on in-air restart */
if (cmd_arms && (arming_res == TRANSITION_CHANGED) &&
(hrt_absolute_time() > (commander_boot_timestamp + INAIR_RESTART_HOLDOFF_INTERVAL)) &&
!home->manual_home) {
(hrt_absolute_time() > (commander_boot_timestamp + INAIR_RESTART_HOLDOFF_INTERVAL))) {
commander_set_home_position(*home_pub, *home, *local_pos, *global_pos, *attitude, false);
}
@ -1043,7 +1042,13 @@ bool handle_command(struct vehicle_status_s *status_local, const struct safety_s
if (use_current) {
/* use current position */
if (commander_set_home_position(*home_pub, *home, *local_pos, *global_pos, *attitude, false)) {
if (status_flags.condition_global_position_valid) {
home->lat = global_pos->lat;
home->lon = global_pos->lon;
home->alt = global_pos->alt;
home->timestamp = hrt_absolute_time();
cmd_result = vehicle_command_s::VEHICLE_CMD_RESULT_ACCEPTED;
} else {
@ -1051,50 +1056,29 @@ bool handle_command(struct vehicle_status_s *status_local, const struct safety_s
}
} else {
const double lat = cmd->param5;
const double lon = cmd->param6;
const float alt = cmd->param7;
/* use specified position */
home->lat = cmd->param5;
home->lon = cmd->param6;
home->alt = cmd->param7;
if (PX4_ISFINITE(lat) && PX4_ISFINITE(lon) && PX4_ISFINITE(alt)) {
home->timestamp = hrt_absolute_time();
if (local_pos->xy_global && local_pos->z_global) {
/* use specified position */
home->timestamp = hrt_absolute_time();
cmd_result = vehicle_command_s::VEHICLE_CMD_RESULT_ACCEPTED;
}
home->lat = lat;
home->lon = lon;
home->alt = alt;
if (cmd_result == vehicle_command_s::VEHICLE_CMD_RESULT_ACCEPTED) {
mavlink_and_console_log_info(&mavlink_log_pub, "Home position: %.7f, %.7f, %.2f", home->lat, home->lon, (double)home->alt);
home->manual_home = true;
home->valid_alt = true;
home->valid_hpos = true;
// update local projection reference including altitude
struct map_projection_reference_s ref_pos;
map_projection_init(&ref_pos, local_pos->ref_lat, local_pos->ref_lon);
map_projection_project(&ref_pos, lat, lon, &home->x, &home->y);
home->z = -(alt - local_pos->ref_alt);
/* announce new home position */
if (*home_pub != nullptr) {
orb_publish(ORB_ID(home_position), *home_pub, home);
} else {
*home_pub = orb_advertise(ORB_ID(home_position), home);
}
/* mark home position as set */
status_flags.condition_home_position_valid = true;
cmd_result = vehicle_command_s::VEHICLE_CMD_RESULT_ACCEPTED;
} else {
cmd_result = vehicle_command_s::VEHICLE_CMD_RESULT_TEMPORARILY_REJECTED;
}
/* announce new home position */
if (*home_pub != nullptr) {
orb_publish(ORB_ID(home_position), *home_pub, home);
} else {
cmd_result = vehicle_command_s::VEHICLE_CMD_RESULT_DENIED;
*home_pub = orb_advertise(ORB_ID(home_position), home);
}
/* mark home position as set */
status_flags.condition_home_position_valid = true;
}
}
break;
@ -1250,7 +1234,7 @@ bool handle_command(struct vehicle_status_s *status_local, const struct safety_s
* @brief This function initializes the home position an altitude of the vehicle. This happens first time we get a good GPS fix and each
* time the vehicle is armed with a good GPS fix.
**/
static bool commander_set_home_position(orb_advert_t &homePub, home_position_s &home,
static void commander_set_home_position(orb_advert_t &homePub, home_position_s &home,
const vehicle_local_position_s &localPosition, const vehicle_global_position_s &globalPosition,
const vehicle_attitude_s &attitude,
bool set_alt_only_to_lpos_ref)
@ -1258,15 +1242,16 @@ static bool commander_set_home_position(orb_advert_t &homePub, home_position_s &
if (!set_alt_only_to_lpos_ref) {
//Need global and local position fix to be able to set home
if (!status_flags.condition_global_position_valid || !status_flags.condition_local_position_valid) {
return false;
return;
}
//Ensure that the GPS accuracy is good enough for intializing home
if (globalPosition.eph > eph_threshold || globalPosition.epv > epv_threshold) {
return false;
return;
}
// Set home position
//Set home position
home.timestamp = hrt_absolute_time();
home.lat = globalPosition.lat;
home.lon = globalPosition.lon;
home.valid_hpos = true;
@ -1281,6 +1266,9 @@ static bool commander_set_home_position(orb_advert_t &homePub, home_position_s &
matrix::Eulerf euler = matrix::Quatf(attitude.q);
home.yaw = euler.psi();
PX4_INFO("home: %.7f, %.7f, %.2f", home.lat, home.lon, (double)home.alt);
//Play tune first time we initialize HOME
if (!status_flags.condition_home_position_valid) {
tune_home_set(true);
@ -1291,16 +1279,15 @@ static bool commander_set_home_position(orb_advert_t &homePub, home_position_s &
} else if (!home.valid_alt && localPosition.z_global) {
// handle special case where we are setting only altitude using local position reference
home.timestamp = hrt_absolute_time();
home.alt = localPosition.ref_alt;
home.valid_alt = true;
PX4_INFO("home alt: %.2f", (double)home.alt);
} else {
return false;
return;
}
home.timestamp = hrt_absolute_time();
home.manual_home = false;
/* announce new home position */
if (homePub != nullptr) {
orb_publish(ORB_ID(home_position), homePub, &home);
@ -1308,8 +1295,6 @@ static bool commander_set_home_position(orb_advert_t &homePub, home_position_s &
} else {
homePub = orb_advertise(ORB_ID(home_position), &home);
}
return true;
}
int commander_thread_main(int argc, char *argv[])
@ -2047,9 +2032,7 @@ int commander_thread_main(int argc, char *argv[])
}
// Provide feedback on mission state
if ((_mission_result.timestamp > commander_boot_timestamp) && hotplug_timeout &&
(_mission_result.instance_count > 0) && !_mission_result.valid) {
if (!_mission_result.valid && hotplug_timeout && _home.timestamp > 0) {
mavlink_log_critical(&mavlink_log_pub, "Planned mission fails check. Please upload again.");
}
}
@ -3137,43 +3120,24 @@ int commander_thread_main(int argc, char *argv[])
/* Get current timestamp */
const hrt_abstime now = hrt_absolute_time();
// automaticcally set or update home position
if (!_home.manual_home) {
if (armed.armed) {
if ((!was_armed || (was_landed && !land_detector.landed)) &&
(now > commander_boot_timestamp + INAIR_RESTART_HOLDOFF_INTERVAL)) {
/* First time home position update - but only if disarmed */
if (!status_flags.condition_home_position_valid && !armed.armed) {
commander_set_home_position(home_pub, _home, local_position, global_position, attitude, false);
}
/* update home position on arming if at least 500 ms from commander start spent to avoid setting home on in-air restart */
commander_set_home_position(home_pub, _home, local_position, global_position, attitude, false);
}
} else {
if (status_flags.condition_home_position_valid) {
if (land_detector.landed && local_position.xy_valid && local_position.z_valid) {
/* distance from home */
float home_dist_xy = -1.0f;
float home_dist_z = -1.0f;
mavlink_wpm_distance_to_point_local(_home.x, _home.y, _home.z, local_position.x, local_position.y,
local_position.z, &home_dist_xy, &home_dist_z);
/* update home position on arming if at least 500 ms from commander start spent to avoid setting home on in-air restart */
else if (((!was_armed && armed.armed) || (was_landed && !land_detector.landed)) &&
(now > commander_boot_timestamp + INAIR_RESTART_HOLDOFF_INTERVAL)) {
commander_set_home_position(home_pub, _home, local_position, global_position, attitude, false);
if (home_dist_xy > local_position.epv * 2 || home_dist_z > local_position.eph * 2) {
}
/* update when disarmed, landed and moved away from current home position */
commander_set_home_position(home_pub, _home, local_position, global_position, attitude, false);
}
}
} else {
/* First time home position update - but only if disarmed */
commander_set_home_position(home_pub, _home, local_position, global_position, attitude, false);
}
}
/* Set home position altitude to EKF origin height if home is not set and the EKF has a global origin.
* This allows home atitude to be used in the calculation of height above takeoff location when GPS
* use has commenced after takeoff. */
if (!_home.valid_alt && local_position.z_global) {
commander_set_home_position(home_pub, _home, local_position, global_position, attitude, true);
/* Set home position altitude to EKF origin height if home is not set and the EKF has a global origin.
* This allows home atitude to be used in the calculation of height above takeoff location when GPS
* use has commenced after takeoff. */
if (!_home.valid_alt && local_position.z_global) {
commander_set_home_position(home_pub, _home, local_position, global_position, attitude, true);
}
}
// check for arming state change

View File

@ -217,7 +217,6 @@ private:
BlockParamExtFloat _mag_heading_noise; ///< measurement noise used for simple heading fusion (rad)
BlockParamExtFloat _mag_noise; ///< measurement noise used for 3-axis magnetoemeter fusion (Gauss)
BlockParamExtFloat _eas_noise; ///< measurement noise used for airspeed fusion (m/sec)
BlockParamExtFloat _beta_innov_gate; ///< synthetic sideslip innovation consistency gate size (STD)
BlockParamExtFloat _beta_noise; ///< synthetic sideslip noise (rad)
BlockParamExtFloat _mag_declination_deg;///< magnetic declination (degrees)
BlockParamExtFloat _heading_innov_gate;///< heading fusion innovation consistency gate size (STD)
@ -362,7 +361,6 @@ Ekf2::Ekf2():
_mag_heading_noise(this, "HEAD_NOISE", true, _params->mag_heading_noise),
_mag_noise(this, "MAG_NOISE", true, _params->mag_noise),
_eas_noise(this, "EAS_NOISE", true, _params->eas_noise),
_beta_innov_gate(this, "BETA_GATE", true, _params->beta_innov_gate),
_beta_noise(this, "BETA_NOISE", true, _params->beta_noise),
_mag_declination_deg(this, "MAG_DECL", true, _params->mag_declination_deg),
_heading_innov_gate(this, "HDG_GATE", true, _params->heading_innov_gate),

View File

@ -393,18 +393,6 @@ PARAM_DEFINE_FLOAT(EKF2_MAG_NOISE, 5.0e-2f);
*/
PARAM_DEFINE_FLOAT(EKF2_EAS_NOISE, 1.4f);
/**
* Gate size for synthetic sideslip fusion
*
* Sets the number of standard deviations used by the innovation consistency test.
*
* @group EKF2
* @min 1.0
* @unit SD
* @decimal 1
*/
PARAM_DEFINE_FLOAT(EKF2_BETA_GATE, 5.0f);
/**
* Noise for synthetic sideslip fusion.
*
@ -564,18 +552,16 @@ PARAM_DEFINE_FLOAT(EKF2_TAS_GATE, 3.0f);
* 3 : Set to true to enable vision position fusion
* 4 : Set to true to enable vision yaw fusion
* 5 : Set to true to enable multi-rotor drag specific force fusion
* 6 : set to true if the EV observations are in a non NED reference frame and need to be rotated before being used
*
* @group EKF2
* @min 0
* @max 127
* @max 63
* @bit 0 use GPS
* @bit 1 use optical flow
* @bit 2 inhibit IMU bias estimation
* @bit 3 vision position fusion
* @bit 4 vision yaw fusion
* @bit 5 multi-rotor drag fusion
* @bit 6 rotate external vision
* @reboot_required true
*/
PARAM_DEFINE_INT32(EKF2_AID_MASK, 1);

View File

@ -591,7 +591,6 @@ void Logger::add_default_topics()
add_topic("ekf2_innovations", 200);
add_topic("esc_status", 250);
add_topic("estimator_status", 200);
add_topic("home_position");
add_topic("input_rc", 200);
add_topic("manual_control_setpoint", 200);
add_topic("mission_result");

View File

@ -1406,7 +1406,6 @@ MavlinkMissionManager::parse_mavlink_mission_item(const mavlink_mission_item_t *
break;
case MAV_CMD_DO_CHANGE_SPEED:
case MAV_CMD_DO_SET_HOME:
case MAV_CMD_DO_SET_SERVO:
case MAV_CMD_DO_LAND_START:
case MAV_CMD_DO_TRIGGER_CONTROL:
@ -1480,7 +1479,6 @@ MavlinkMissionManager::format_mavlink_mission_item(const struct mission_item_s *
break;
case NAV_CMD_DO_CHANGE_SPEED:
case NAV_CMD_DO_SET_HOME:
case NAV_CMD_DO_SET_SERVO:
case NAV_CMD_DO_LAND_START:
case NAV_CMD_DO_TRIGGER_CONTROL:

View File

@ -870,11 +870,11 @@ Mission::do_need_vertical_takeoff()
/* force takeoff if landed (additional protection) */
_need_takeoff = true;
} else if (_navigator->get_global_position()->alt > takeoff_alt - _navigator->get_altitude_acceptance_radius()) {
} else if (_navigator->get_global_position()->alt > takeoff_alt - _navigator->get_acceptance_radius()) {
/* if in-air and already above takeoff height, don't do takeoff */
_need_takeoff = false;
} else if (_navigator->get_global_position()->alt <= takeoff_alt - _navigator->get_altitude_acceptance_radius()
} else if (_navigator->get_global_position()->alt <= takeoff_alt - _navigator->get_acceptance_radius()
&& (_mission_item.nav_cmd == NAV_CMD_TAKEOFF
|| _mission_item.nav_cmd == NAV_CMD_VTOL_TAKEOFF)) {
/* if in-air but below takeoff height and we have a takeoff item */

View File

@ -113,7 +113,6 @@ MissionBlock::is_mission_item_reached()
}
case NAV_CMD_DO_CHANGE_SPEED:
case NAV_CMD_DO_SET_HOME:
return true;
default:

View File

@ -64,7 +64,6 @@ MissionFeasibilityChecker::checkMissionFeasible(const mission_s &mission,
fw_pos_ctrl_status_s *fw_pos_ctrl_status = _navigator->get_fw_pos_ctrl_status();
const float home_alt = _navigator->get_home_position()->alt;
const bool home_valid = _navigator->home_position_valid();
const bool home_alt_valid = _navigator->home_alt_valid();
bool &warning_issued = _navigator->get_mission_result()->warning;
const float default_acceptance_rad = _navigator->get_default_acceptance_radius();
@ -75,7 +74,7 @@ MissionFeasibilityChecker::checkMissionFeasible(const mission_s &mission,
bool warned = false;
// first check if we have a valid position
if (!home_alt_valid) {
if (!home_valid) {
failed = true;
warned = true;
mavlink_log_info(_navigator->get_mavlink_log_pub(), "Not yet ready for mission, no position lock.");
@ -90,15 +89,15 @@ MissionFeasibilityChecker::checkMissionFeasible(const mission_s &mission,
failed = failed
|| !checkDistancesBetweenWaypoints(dm_current, nMissionItems, max_distance_between_waypoints, warning_issued);
failed = failed || !checkGeofence(dm_current, nMissionItems, geofence, home_alt, home_valid);
failed = failed || !checkHomePositionAltitude(dm_current, nMissionItems, home_alt, home_alt_valid, warned);
failed = failed || !checkHomePositionAltitude(dm_current, nMissionItems, home_alt, home_valid, warned);
if (isRotarywing) {
failed = failed
|| !checkRotarywing(dm_current, nMissionItems, home_alt, home_alt_valid, default_altitude_acceptance_rad);
|| !checkRotarywing(dm_current, nMissionItems, home_alt, home_valid, default_altitude_acceptance_rad);
} else {
failed = failed
|| !checkFixedwing(dm_current, nMissionItems, fw_pos_ctrl_status, home_alt, home_alt_valid,
|| !checkFixedwing(dm_current, nMissionItems, fw_pos_ctrl_status, home_alt, home_valid,
default_acceptance_rad, land_start_req);
}
@ -107,7 +106,7 @@ MissionFeasibilityChecker::checkMissionFeasible(const mission_s &mission,
bool
MissionFeasibilityChecker::checkRotarywing(dm_item_t dm_current, size_t nMissionItems,
float home_alt, bool home_alt_valid, float default_altitude_acceptance_rad)
float home_alt, bool home_valid, float default_altitude_acceptance_rad)
{
for (size_t i = 0; i < nMissionItems; i++) {
struct mission_item_s missionitem = {};
@ -145,11 +144,11 @@ MissionFeasibilityChecker::checkRotarywing(dm_item_t dm_current, size_t nMission
bool
MissionFeasibilityChecker::checkFixedwing(dm_item_t dm_current, size_t nMissionItems,
fw_pos_ctrl_status_s *fw_pos_ctrl_status, float home_alt, bool home_alt_valid,
fw_pos_ctrl_status_s *fw_pos_ctrl_status, float home_alt, bool home_valid,
float default_acceptance_rad, bool land_start_req)
{
/* Perform checks and issue feedback to the user for all checks */
bool resTakeoff = checkFixedWingTakeoff(dm_current, nMissionItems, home_alt, home_alt_valid, land_start_req);
bool resTakeoff = checkFixedWingTakeoff(dm_current, nMissionItems, home_alt, home_valid, land_start_req);
bool resLanding = checkFixedWingLanding(dm_current, nMissionItems, fw_pos_ctrl_status, land_start_req);
/* Mission is only marked as feasible if all checks return true */
@ -199,7 +198,7 @@ MissionFeasibilityChecker::checkGeofence(dm_item_t dm_current, size_t nMissionIt
bool
MissionFeasibilityChecker::checkHomePositionAltitude(dm_item_t dm_current, size_t nMissionItems,
float home_alt, bool home_alt_valid, bool &warning_issued, bool throw_error)
float home_alt, bool home_valid, bool &warning_issued, bool throw_error)
{
/* Check if all waypoints are above the home altitude */
for (size_t i = 0; i < nMissionItems; i++) {
@ -213,7 +212,7 @@ MissionFeasibilityChecker::checkHomePositionAltitude(dm_item_t dm_current, size_
}
/* reject relative alt without home set */
if (missionitem.altitude_is_relative && !home_alt_valid && MissionBlock::item_contains_position(missionitem)) {
if (missionitem.altitude_is_relative && !home_valid && MissionBlock::item_contains_position(missionitem)) {
warning_issued = true;
@ -276,7 +275,6 @@ MissionFeasibilityChecker::checkMissionItemValidity(dm_item_t dm_current, size_t
missionitem.nav_cmd != NAV_CMD_DELAY &&
missionitem.nav_cmd != NAV_CMD_DO_JUMP &&
missionitem.nav_cmd != NAV_CMD_DO_CHANGE_SPEED &&
missionitem.nav_cmd != NAV_CMD_DO_SET_HOME &&
missionitem.nav_cmd != NAV_CMD_DO_SET_SERVO &&
missionitem.nav_cmd != NAV_CMD_DO_LAND_START &&
missionitem.nav_cmd != NAV_CMD_DO_TRIGGER_CONTROL &&
@ -329,7 +327,7 @@ MissionFeasibilityChecker::checkMissionItemValidity(dm_item_t dm_current, size_t
bool
MissionFeasibilityChecker::checkFixedWingTakeoff(dm_item_t dm_current, size_t nMissionItems,
float home_alt, bool home_alt_valid, float default_acceptance_rad)
float home_alt, bool home_valid, float default_acceptance_rad)
{
for (size_t i = 0; i < nMissionItems; i++) {
struct mission_item_s missionitem = {};

View File

@ -57,7 +57,7 @@ private:
/* Checks for all airframes */
bool checkGeofence(dm_item_t dm_current, size_t nMissionItems, Geofence &geofence, float home_alt, bool home_valid);
bool checkHomePositionAltitude(dm_item_t dm_current, size_t nMissionItems, float home_alt, bool home_alt_valid,
bool checkHomePositionAltitude(dm_item_t dm_current, size_t nMissionItems, float home_alt, bool home_valid,
bool &warning_issued, bool throw_error = false);
bool checkMissionItemValidity(dm_item_t dm_current, size_t nMissionItems, bool condition_landed);
@ -68,16 +68,16 @@ private:
/* Checks specific to fixedwing airframes */
bool checkFixedwing(dm_item_t dm_current, size_t nMissionItems, fw_pos_ctrl_status_s *fw_pos_ctrl_status,
float home_alt, bool home_alt_valid, float default_acceptance_rad, bool land_start_req);
float home_alt, bool home_valid, float default_acceptance_rad, bool land_start_req);
bool checkFixedWingTakeoff(dm_item_t dm_current, size_t nMissionItems, float home_alt, bool home_alt_valid,
bool checkFixedWingTakeoff(dm_item_t dm_current, size_t nMissionItems, float home_alt, bool home_valid,
float default_acceptance_rad);
bool checkFixedWingLanding(dm_item_t dm_current, size_t nMissionItems, fw_pos_ctrl_status_s *fw_pos_ctrl_status,
bool land_start_req);
/* Checks specific to rotarywing airframes */
bool checkRotarywing(dm_item_t dm_current, size_t nMissionItems,
float home_alt, bool home_alt_valid, float default_altitude_acceptance_rad);
float home_alt, bool home_valid, float default_altitude_acceptance_rad);
public:
MissionFeasibilityChecker(Navigator *navigator) : _navigator(navigator) {}

View File

@ -71,7 +71,6 @@ enum NAV_CMD {
NAV_CMD_DELAY = 93,
NAV_CMD_DO_JUMP = 177,
NAV_CMD_DO_CHANGE_SPEED = 178,
NAV_CMD_DO_SET_HOME = 179,
NAV_CMD_DO_SET_SERVO = 183,
NAV_CMD_DO_LAND_START = 189,
NAV_CMD_DO_SET_ROI = 201,

View File

@ -150,8 +150,7 @@ public:
const vehicle_roi_s &get_vroi() { return _vroi; }
bool home_alt_valid() { return (_home_pos.timestamp > 0 && _home_pos.valid_alt); }
bool home_position_valid() { return (_home_pos.timestamp > 0 && _home_pos.valid_alt && _home_pos.valid_hpos); }
bool home_position_valid() { return (_home_pos.timestamp > 0 && _home_pos.valid_hpos && _home_pos.valid_alt); }
int get_onboard_mission_sub() { return _onboard_mission_sub; }
int get_offboard_mission_sub() { return _offboard_mission_sub; }
@ -234,7 +233,7 @@ public:
orb_advert_t *get_mavlink_log_pub() { return &_mavlink_log_pub; }
void increment_mission_instance_count() { _mission_result.instance_count++; }
void increment_mission_instance_count() { _mission_instance_count++; }
void set_mission_failure(const char *reason);
@ -291,6 +290,8 @@ private:
position_setpoint_triplet_s _takeoff_triplet{}; /**< triplet for non-mission direct takeoff command */
vehicle_roi_s _vroi{}; /**< vehicle ROI */
int _mission_instance_count{-1}; /**< instance count for the current mission */
perf_counter_t _loop_perf; /**< loop performance counter */
Geofence _geofence; /**< class that handles the geofence */

View File

@ -497,7 +497,7 @@ Navigator::task_main()
publish_vehicle_command_ack(cmd, vehicle_command_s::VEHICLE_CMD_RESULT_ACCEPTED);
} else if (cmd.command == vehicle_command_s::VEHICLE_CMD_MISSION_START) {
if (_mission_result.valid &&
if (get_mission_result()->valid &&
PX4_ISFINITE(cmd.param1) && (cmd.param1 >= 0) && (cmd.param1 < _mission_result.seq_total)) {
_mission.set_current_offboard_mission_index(cmd.param1);
@ -1114,6 +1114,7 @@ void
Navigator::publish_mission_result()
{
_mission_result.timestamp = hrt_absolute_time();
_mission_result.instance_count = _mission_instance_count;
/* lazily publish the mission result only once available */
if (_mission_result_pub != nullptr) {