diff --git a/.circleci/config.yml b/.circleci/config.yml
new file mode 100644
index 000000000..825f26624
--- /dev/null
+++ b/.circleci/config.yml
@@ -0,0 +1,83 @@
+# CircleCI 2.0 configuration file for dronekit-python
+
+# Steps common to both Python 2 and Python 3
+common: &commonsteps
+ steps:
+ - checkout
+
+ - run:
+ name: Install dronekit with dependencies
+ command: |
+ virtualenv venv
+ source venv/bin/activate
+ pip install -UI future
+ pip install -r requirements.txt -UI
+ pip install . -UI
+
+ - run:
+ name: Run dronekit tests
+ environment:
+ SITL_SPEEDUP: 10
+ SITL_RATE: 200
+ command: |
+ source venv/bin/activate
+ nosetests -svx dronekit.test.unit
+ nosetests -svx dronekit.test.sitl
+
+ - run:
+ name: Build documentation
+ command: |
+ source venv/bin/activate
+ cd docs; make clean; make html
+
+ - store_artifacts:
+ path: test-reports
+ destination: test-reports
+
+# Jobs definition
+version: 2
+jobs:
+ python2:
+ docker:
+ - image: circleci/python:2.7-stretch
+ working_directory: ~/dronekit-python2
+ <<: *commonsteps
+
+ python3:
+ docker:
+ - image: circleci/python:3.6-stretch
+ working_directory: ~/dronekit-python3
+ <<: *commonsteps
+
+ deploy:
+ name: Deploy to dronekit.io
+ working_directory: ~/deploy
+ machine: true
+ steps:
+ - checkout
+ - run:
+ name: update docs
+ command: ./scripts/update-docs.sh
+
+# Send a notification on Gitter
+notify:
+ webhooks:
+ - url: https://webhooks.gitter.im/e/27b0e1a9fede99dbbe6c
+
+# Workflow definition
+# Run Python 2 and Python 3 testing in parallel
+# and deploy if the Python 2 build succeeds
+workflows:
+ version: 2
+ build_test_deploy:
+ jobs:
+ - python2
+ - python3
+# disabling until we find a new docs server
+# - deploy:
+# requires:
+# - python2
+# filters:
+# branches:
+# only:
+# - master
diff --git a/.editorconfig b/.editorconfig
index 08c10f020..2470cbc7e 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -20,6 +20,8 @@ trim_trailing_whitespace = true
[*.py]
indent_style = space
indent_size = 4
+trim_trailing_whitespace = true
+end_of_line = LF
[*.mk]
indent_style = tab
diff --git a/.gitignore b/.gitignore
index eb6b83785..dec06d5da 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,6 @@
.project
.pydevproject
+.python-version
dronekit.egg-info
dist
build
@@ -8,3 +9,4 @@ build
.idea
*.pyc
env
+vs/.vs/dronekit-python/v14/*.suo
diff --git a/.style.yapf b/.style.yapf
new file mode 100644
index 000000000..728e3f0e0
--- /dev/null
+++ b/.style.yapf
@@ -0,0 +1,3 @@
+[style]
+based_on_style = pep8
+column_limit = 100
diff --git a/.travis.yml b/.travis.yml
index a061c5378..16dfd6d8b 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,36 +1,47 @@
+language: python
+
env:
global:
- SITL_SPEEDUP=10
- SITL_RATE=200
python:
- - "2.7"
+ - 2.7
+ - 3.6
+
+before_install:
+ - pip install --upgrade pip
install:
- - 'sudo pip install . -UI'
- - 'sudo pip install -r requirements.txt -UI'
+ - pip install -r requirements.txt
+ - pip install flake8
+
+before_script:
+ # stop the build if there are Python syntax errors or undefined names
+ - flake8 . --count --select=E901,E999,F821,F822,F823 --show-source --statistics
+ # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
+ - flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
script:
- - '[ "${TRAVIS_PULL_REQUEST}" != "false" ] || nosetests tests/web'
- - 'nosetests tests/unit'
- - 'nosetests tests/sitl'
+ - nosetests --debug=nose,nose.importer --debug-log=nose_debug -svx dronekit.test.unit
+ - nosetests --debug=nose,nose.importer --debug-log=nose_debug -svx dronekit.test.sitl
git:
depth: 10
-language: objective-c
-
notifications:
email: false
- slack:
- secure: IYgZ83X065I/LljGrPEACZms+KDwrojiQbboFHhvNxL2Zkc5jHqwBK6PD1BsJh2JVun9fCZ1v2R8KuDsf+Qz2dCximdOZcHI81L9JUOZYuSJ2TVlbKiC00WdXpcQ6g7pDTLm/mGBoPxC+MuC5l8zZdbpPBpEa0F/YCe/n7tbT+g=
+ webhooks:
+ urls:
+ - https://webhooks.gitter.im/e/f3f81b74f930dac9583a
+ on_success: change
+ on_failure: always
+ on_start: never
-matrix:
- fast_finish: true
+#matrix:
+ #allow_failures:
+ #- python: 3.6
branches:
only:
- master
- - patch
- - major
- - minor
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 000000000..ca542f26a
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,201 @@
+# Changelog
+
+
+## Version 2.9.2 (2019-03-18)
+
+### Improvements
+* CI integration improvements
+* Python3 compatability
+* use logging module
+* log statustexts
+* documentation improvements
+* convenience functions added: wait_for, wait_for_armable, arm, disarm, wait_for_mode, wait_for_alt, wait_simple_takeoff
+* play_tune method added
+* reboot method added
+* send_calibrate_gyro, send_calibrate_magnetometer, send_calibrate_magnetometer, send_calibrate_vehicle_level, send_calibrate_barometer all added
+* update gimbal orientation from MOUNT_ORIENTATION
+* add a still-waiting callback for connect() to provide debug on where the connection is up to
+* several new tests added (including, play_tune, reboot and set_attitude_target)
+
+### Cleanup
+* flake8 compliance improvements
+* test includes pruned
+* examples cleaned up
+
+### Bug Fixes
+* ignore GCS heartbeats for the purposes of link up
+* many!
+
+## Version 2.9.1 (2017-04-21)
+
+### Improvements
+* home locatin notifications
+* notify ci status to gitter
+* basic python 3 support
+* isolated logger function so implementers can override
+* rename windows installer
+
+### Cleanup
+* removed legacy cloud integrations
+
+### Bug Fixes
+* fix missing ** operator for pymavlink compatibility
+
+## Version 2.9.0 (2016-08-29)
+
+### Bug Fixes
+* MAVConnection stops threads on exit and close
+* PX4 Pro flight modes are now properly supported
+* go to test now uses correct `global_relative_frame` alt
+
+### Improvements
+* Updated pymavlink dependency to v2 from v1 hoping we don't fall behind
+ again.
+
+## Version 2.8.0 (2016-07-15)
+
+### Bug Fixes
+* Makes sure we are listening to `HOME_LOCATION` message, befor we
+ would only set home location if received by waypoints.
+
+## Version 2.7.0 (2016-06-21)
+
+### Improvements
+* Adds udpin-multi support
+
+## Version 2.6.0 (2016-06-17)
+
+### Bug Fixes
+* Fixes patched mavutil sendfn
+
+## Version 2.5.0 (2016-05-04)
+
+### Improvements
+* Catch and display message and attribute errors, then continue
+* Improved takeoff example docs
+* Deploy docs on successful merge into master (from CircleCI)
+* Drone delivery example, explain port to connect
+* MicroCGS example now uses SITL
+* Make running examples possible on Vagrant
+
+### Bug Fixes
+* Mav type for rover was incorrect
+* `_is_mode_available` can now handle unrecognized mode codes
+* Fix broken links on companion computer page
+* Fix infinite loop on channel test
+
+
+
+## Version 2.4.0 (2016-02-29)
+
+### Bug Fixes
+
+* Use monotonic clock for all of the internal timeouts and time
+ measurements
+* Docs fixes
+
+
+## Version 2.3.0 (2016-02-26)
+
+### New Features
+
+* PX4 compatibility improvements
+
+### Updated Features
+
+* Documentation fixes
+* PIP repository improvements
+* Mode-setting API improvements
+* ardupilot-solo compatibility fixes
+
+
+
+## Version 2.2.0 (2016-02-19)
+
+### Bug Fixes
+
+* Splits outbound messages into its own thread.
+* Remove of capabilities request on HEARTBEAT listener
+* Check if mode_mapping has items before iteration
+
+
+
+## Version 2.1.0 (2016-02-16)
+
+
+### New Features
+
+
+* Gimbal control attribute
+* Autopilot version attribute
+* Autopilot capabilities attribute
+* Best Practice guide documentation.
+* Performance test example (restructured and docs added)
+
+### Updated Features:
+
+Many documentation fixes:
+
+* Restructured documentation with Develop (Concepts) and Guide (HowTo) sections
+* Docs separated out "Connection Strings" section.
+* Improved test and contribution sections.
+* Updated examples and documentation to use DroneKit-Sitl for simulation ("zero setup examples")
+* Debugging docs updated with additional libraries.
+* Flight Replay example fetches data from TLOG rather than droneshare
+* Drone Delivery example now uses strart location for home address.
+* Disabled web tests (not currently supported/used)
+* Updated copyright range to include changes in 2016
+
+### Bug Fixes
+
+* Numerous minor docs fixes.
+* Harmonise nosetest options across each of the integration platforms
+* Fix incorrect property marker for airspeed attribute
+
+
+
+## Version 2.0.2 (2015-11-30)
+
+### Bug Fixes:
+
+* Updates `requests` dependency to work >=2.5.0
+
+
+## Version 2.0.0 (2015-11-23)
+
+### New Features:
+
+* Renamed library and package from DroneAPI to DroneKit on pip
+* DroneKit Python is now a standalone library and no longer requires use of MAVProxy
+* Connect multiple vehicles in one script by creating separate vehicle instances
+* Removed NumPy, ProtoBuf as dependencies
+* Add MAVLink message listeners using `add_message_listener` methods
+* Added `on_attribute` and `on_message` function decorator shorthands
+* Added `mount_status`, `system_status`, `ekf_ok`, `is_armable`, `heading`
+* Made settable `groundspeed`, `airspeed`
+* Moved `dronekit.lib` entries to root package `dronekit`
+* Added `parameters.set` and `parameters.get` for fine-tuned parameter access
+* `parameters` now observable and iterable (#442)
+* Added `last_heartbeat` attribute, updated every event loop with time since last heartbeat (#451)
+* Await attributes through `wait_ready` method and `connect` method parameter
+* Adds subclassable Vehicle class, used by `vehicle_class` parameter in `connect`
+
+### Updated Features:
+
+* local_connect renamed to connect(), accepting a connection path, link configuration, and timeout settings
+* Removed `.set_mavrx_callback`. Use `vehicle.on_message('*', obj)` methods
+* Renamed `add_attribute_observer` methods to `add_attribute_listener`, etc. (#420)
+* Renamed `wait_init` and `wait_valid` to `wait_ready`
+* Split `home_location` is a separate attribute from `commands` waypoint array
+* Moved RC channels into `.channels` object (#427)
+* Split location information into `local_frame`, `global_frame`, and `global_relative_frame` (and removed `is_relative`) (#445)
+* Renamed `flush` to `commands.upload`, as it only impacts waypoints (#276)
+* `commands.goto` and `commands.takeoff` renamed to `simple_goto` and `simple_takeoff`
+
+### Bug Fixes:
+
+* `armed` and `mode` attributes updated constantly (#60, #446)
+* Parameter setting times out (#12)
+* `battery` access can throw exception (#298)
+* Vehicle.location reports incorrect is_relative value for Copter (#130)
+* Excess arming message when already armed
diff --git a/README.md b/README.md
index 2bb29e500..f024a0b6f 100644
--- a/README.md
+++ b/README.md
@@ -1,35 +1,74 @@
# DroneKit Python
+
+
+[](https://pypi.org/project/dronekit/)
[](https://ci.appveyor.com/project/3drobotics/dronekit-python/branch/master)
[](https://travis-ci.org/dronekit/dronekit-python)
-[](https://circleci.com/gh/dronekit/dronekit-python)
+[](https://circleci.com/gh/dronekit/dronekit-python)
+
+DroneKit-Python helps you create powerful apps for UAVs.
+
+# ⚠️ ATTENTION: MAINTAINERS NEEDED ⚠️
+
+Hey it's true this project is not very active, but it could be with your help. We are looking for maintainers interested in keeping the project alive by keep up with CI and PRs. If you are interested in helping please apply by [creating an issue]([url](https://github.com/dronekit/dronekit-python/issues/new)) and listing the reasons why you would like to help, in return we will be granting committer access to folks who are truly interested in helping.
+
+
+## Overview
+
+DroneKit-Python (formerly DroneAPI-Python) contains the python language implementation of DroneKit.
+
+The API allows developers to create Python apps that communicate with vehicles over MAVLink. It provides programmatic access to a connected vehicle's telemetry, state and parameter information, and enables both mission management and direct control over vehicle movement and operations.
+
+The API is primarily intended for use in onboard companion computers (to support advanced use cases including computer vision, path planning, 3D modelling etc). It can also be used for ground station apps, communicating with vehicles over a higher latency RF-link.
+
+## Getting Started
+
+The [Quick Start](https://dronekit-python.readthedocs.io/en/latest/guide/quick_start.html) guide explains how to set up DroneKit on each of the supported platforms (Linux, Mac OSX, Windows) and how to write a script to connect to a vehicle (real or simulated).
+
+A basic script looks like this:
+
+```python
+from dronekit import connect
+
+# Connect to UDP endpoint.
+vehicle = connect('127.0.0.1:14550', wait_ready=True)
+# Use returned Vehicle object to query device state - e.g. to get the mode:
+print("Mode: %s" % vehicle.mode.name)
+```
+
+Once you've got DroneKit set up, the [guide](https://dronekit-python.readthedocs.io/en/latest/guide/index.html) explains how to perform operations like taking off and flying the vehicle. You can also try out most of the tasks by running the [examples](https://dronekit-python.readthedocs.io/en/latest/examples/index.html).
+
+## Resources
+
+The project documentation is available at [https://readthedocs.org/projects/dronekit-python/](https://readthedocs.org/projects/dronekit-python/). This includes [guide](https://dronekit-python.readthedocs.io/en/latest/guide/index.html), [example](https://dronekit-python.readthedocs.io/en/latest/examples/index.html) and [API Reference](https://dronekit-python.readthedocs.io/en/latest/automodule.html) material.
+
+The example source code is hosted here on Github as sub-folders of [/dronekit-python/examples](https://github.com/dronekit/dronekit-python/tree/master/examples).
+
+The [DroneKit Forums](http://discuss.dronekit.io) are the best place to ask for technical support on how to use the library. You can also check out our [Gitter channel](https://gitter.im/dronekit/dronekit-python?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) though we prefer posts on the forums where possible.
+
+* **Documentation:** [https://dronekit-python.readthedocs.io/en/latest/about/index.html](https://dronekit-python.readthedocs.io/en/latest/about/index.html)
+* **Guides:** [https://dronekit-python.readthedocs.io/en/latest/guide/index.html)
+* **API Reference:** [https://dronekit-python.readthedocs.io/en/latest/automodule.html)
+* **Examples:** [/dronekit-python/examples](https://github.com/dronekit/dronekit-python/tree/master/examples)
+* **Forums:** [http://discuss.dronekit.io/](http://discuss.dronekit.io)
+* **Gitter:** [https://gitter.im/dronekit/dronekit-python](https://gitter.im/dronekit/dronekit-python?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) though we prefer posts on the forums where possible.
+
+
+## Users and contributors wanted!
-[](https://gitter.im/dronekit/dronekit-python?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
+We'd love your [feedback and suggestions](https://github.com/dronekit/dronekit-python/issues) about this API and are eager to evolve it to meet your needs, please feel free to create an issue to report bugs or feature requests.
-*(Formerly DroneAPI-python.)*
+If you've created some awesome software that uses this project, [let us know on the forums here](https://discuss.dronekit.io/t/notable-projects-using-dronekit/230)!
-This package contains the python language implementation of DroneKit.
+If you want to contribute, see our [Contributing](https://dronekit-python.readthedocs.io/en/latest/contributing/index.html) guidelines, we welcome all types of contributions but mostly contributions that would help us shrink our [issues list](https://github.com/dronekit/dronekit-python/issues).
-## Users wanted!
-We'd love your [feedback and suggestions](https://github.com/dronekit/dronekit-python/issues) about this API and are eager to evolve it to meet your needs.
+## Licence
-For documentation on how to use this API please see:
+DroneKit-Python is made available under the permissive open source [Apache 2.0 License](http://python.dronekit.io/about/license.html).
-* The new DroneKit-python [website](http://python.dronekit.io/)
-* Our [tutorial](http://dev.ardupilot.com/wiki/droneapi-tutorial/) on the ardupilot wiki
-* The [overview document](https://docs.google.com/document/d/1ihKneLwA4hXmKS1W2pbG9lty_EAwbmy0giusUwQ8dto)
-* The [python autodocs](http://python.dronekit.io/automodule.html)
-* The [python code](droneapi/lib/__init__.py) itself
-* Answers to [technical support queries](http://stackoverflow.com/questions/tagged/dronekit-python) on Stack Overflow.
-* Example code can be found here: ['examples/'](examples/)
- * Beginner ['vehicle_state'](examples/vehicle_state/vehicle_state.py)
- * Beginner ['simple_goto'](examples/simple_goto/simple_goto.py)
- * Beginner ['flight_replay'](examples/flight_replay/flight_replay.py)
- * Beginner ['gcs'](examples/gcs/microgcs.py)
- * Advanced ['drone_delivery'](examples/drone_delivery/)
- * Advanced ['follow-me'](examples/follow_me/)
-The [DroneKit Forums](http://discuss.dronekit.io) is the best place to ask for technical support on how to use the library.
+***
-Copyright 2015 3D Robotics, Inc. Licensed under the Apache 2.0 License.
+Copyright 2015 3D Robotics, Inc.
diff --git a/Vagrantfile b/Vagrantfile
index 77610a6fa..d916140aa 100644
--- a/Vagrantfile
+++ b/Vagrantfile
@@ -3,6 +3,7 @@
Vagrant.configure(2) do |config|
config.vm.box = "ubuntu/trusty64"
+ config.vm.network "private_network", type: "dhcp"
config.vm.provision "shell", inline: <<-SHELL
apt-get -y update
@@ -13,6 +14,12 @@ Vagrant.configure(2) do |config|
echo "[DroneKit]: Installing pip ..."
apt-get -y install python-pip
easy_install -U pip
+ echo "[DroneKit]: Installing python-cherrypy3 ..."
+ apt-get -y install python-cherrypy3
+ echo "[DroneKit]: Installing python-matplotlib ..."
+ apt-get -y install python-matplotlib
+ echo "[DroneKit]: Installing python-gps ..."
+ apt-get -y install python-gps
echo "[DroneKit]: Installing Sphinx ... "
pip install sphinx
cd /vagrant
diff --git a/appveyor.yml b/appveyor.yml
index 3aadf0baa..b1996b573 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -1,11 +1,20 @@
environment:
- global:
- SITL_SPEEDUP: 10
- SITL_RATE: 200
+ SITL_SPEEDUP: 10
+ SITL_RATE: 200
+ PYTHONUNBUFFERED: 1
+
+ matrix:
+ - PYTHON: "C:\\Python27"
+ PYTHON_VERSION: "2.7"
+ - PYTHON: "C:\\Python37"
+ PYTHON_VERSION: "3.7"
cache:
- "c:\\Users\\appveyor\\.pip-wheelhouse"
+init:
+ - cmd: "SET PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH%"
+
install:
- ps: |
New-Item -ItemType Directory -Force -Path c:\Users\appveyor\pip\
@@ -16,25 +25,14 @@ install:
[wheel]
wheel-dir = c:/Users/appveyor/.pip-wheelhouse
'@ | out-file -Encoding ascii -FilePath c:\Users\appveyor\pip\pip.ini
-
- - cmd: 'SET PATH=%PYTHON%;c:\\Python27\\Scripts;%PATH%'
- - cmd: 'SET PYTHONUNBUFFERED=1'
-
- cmd: 'python -m pip install pip wheel -U'
- cmd: 'pip install . -UI'
- cmd: 'pip install -r requirements.txt -UI'
-build_script:
- - cmd: 'nosetests tests\\web'
- - cmd: 'nosetests -s -v tests\\sitl'
- - cmd: 'nosetests tests\\unit'
+build: off
+
+test_script:
+ - cmd: 'nosetests -svx dronekit.test.unit'
+ - cmd: 'nosetests -svx dronekit.test.sitl'
clone_depth: 10
-test: 'off'
-branches:
- only:
- - master
- - major
- - minor
- - patch
- - /^v\d+\.\d+\.\d+$/
diff --git a/circle.yml b/circle.yml
deleted file mode 100644
index 62b0bb8c7..000000000
--- a/circle.yml
+++ /dev/null
@@ -1,18 +0,0 @@
-machine:
- environment:
- SITL_SPEEDUP: 10
- SITL_RATE: 200
-
-dependencies:
- override:
- - 'pip install . -UI'
- - 'pip install -r requirements.txt -UI'
-
-test:
- override:
- - 'nosetests tests/web'
- - 'nosetests tests/unit'
- - 'nosetests tests/sitl'
-
-general:
- build_dir: .
diff --git a/docs/about/github_latest_release.txt b/docs/about/github_latest_release.txt
index 719294867..9a67880ee 100644
--- a/docs/about/github_latest_release.txt
+++ b/docs/about/github_latest_release.txt
@@ -1,30 +1,227 @@
.. This document was auto-generated by the get_release_notes.py script using latest-release information from github
-Release 1.5.0 (August 12, 2015)
-===============================
-
-
-**Features:**
-
-* Added methods to unset `mavlink_callback`. (#115, #240)
-* Publishing scripts now live in `scripts/` (#259)
-
-**Documentation:**
-
-* Documented clearing of `mavlink_callback`. (#245)
-
-Source Code
------------
-
-
-Source code is available at .
-
-* View `**commits** included in this release `_
-* View `**bugs** closed by this release `_
-* View `**pull requests** merged into this release `_
-
-Notes
------
-
-
-Thanks to @hamishwillee, @mrpollo, @tcr3dr
\ No newline at end of file
+Changelog
+=========
+
+Version 2.9.1 (2017-04-21)
+--------------------------
+
+Improvements
+~~~~~~~~~~~~
+
+- home locatin notifications
+- notify ci status to gitter
+- basic python 3 support
+- isolated logger function so implementers can override
+- rename windows installer
+
+Cleanup
+~~~~~~~
+
+- removed legacy cloud integrations
+
+Bug Fixes
+~~~~~~~~~
+
+- fix missing \*\* operator for pymavlink compatibility
+
+Version 2.9.0 (2016-08-29)
+--------------------------
+
+Bug Fixes
+~~~~~~~~~
+
+- MAVConnection stops threads on exit and close
+- PX4 Pro flight modes are now properly supported
+- go to test now uses correct ``global_relative_frame`` alt
+
+Improvements
+~~~~~~~~~~~~
+
+- Updated pymavlink dependency to v2 from v1 hoping we don't fall
+ behind again.
+
+Version 2.8.0 (2016-07-15)
+--------------------------
+
+Bug Fixes
+~~~~~~~~~
+
+- Makes sure we are listening to ``HOME_LOCATION`` message, befor we
+ would only set home location if received by waypoints.
+
+Version 2.7.0 (2016-06-21)
+--------------------------
+
+Improvements
+~~~~~~~~~~~~
+
+- Adds udpin-multi support
+
+Version 2.6.0 (2016-06-17)
+--------------------------
+
+Bug Fixes
+~~~~~~~~~
+
+- Fixes patched mavutil sendfn
+
+Version 2.5.0 (2016-05-04)
+--------------------------
+
+Improvements
+~~~~~~~~~~~~
+
+- Catch and display message and attribute errors, then continue
+- Improved takeoff example docs
+- Deploy docs on successful merge into master (from CircleCI)
+- Drone delivery example, explain port to connect
+- MicroCGS example now uses SITL
+- Make running examples possible on Vagrant
+
+Bug Fixes
+~~~~~~~~~
+
+- Mav type for rover was incorrect
+- ``_is_mode_available`` can now handle unrecognized mode codes
+- Fix broken links on companion computer page
+- Fix infinite loop on channel test
+
+Version 2.4.0 (2016-02-29)
+--------------------------
+
+Bug Fixes
+~~~~~~~~~
+
+- Use monotonic clock for all of the internal timeouts and time
+ measurements
+- Docs fixes
+
+Version 2.3.0 (2016-02-26)
+--------------------------
+
+New Features
+~~~~~~~~~~~~
+
+- PX4 compatibility improvements
+
+Updated Features
+~~~~~~~~~~~~~~~~
+
+- Documentation fixes
+- PIP repository improvements
+- Mode-setting API improvements
+- ardupilot-solo compatibility fixes
+
+Version 2.2.0 (2016-02-19)
+--------------------------
+
+Bug Fixes
+~~~~~~~~~
+
+- Splits outbound messages into its own thread.
+- Remove of capabilities request on HEARTBEAT listener
+- Check if mode\_mapping has items before iteration
+
+Version 2.1.0 (2016-02-16)
+--------------------------
+
+New Features
+~~~~~~~~~~~~
+
+- Gimbal control attribute
+- Autopilot version attribute
+- Autopilot capabilities attribute
+- Best Practice guide documentation.
+- Performance test example (restructured and docs added)
+
+Updated Features:
+~~~~~~~~~~~~~~~~~
+
+Many documentation fixes:
+
+- Restructured documentation with Develop (Concepts) and Guide (HowTo)
+ sections
+- Docs separated out "Connection Strings" section.
+- Improved test and contribution sections.
+- Updated examples and documentation to use DroneKit-Sitl for
+ simulation ("zero setup examples")
+- Debugging docs updated with additional libraries.
+- Flight Replay example fetches data from TLOG rather than droneshare
+- Drone Delivery example now uses strart location for home address.
+- Disabled web tests (not currently supported/used)
+- Updated copyright range to include changes in 2016
+
+Bug Fixes
+~~~~~~~~~
+
+- Numerous minor docs fixes.
+- Harmonise nosetest options across each of the integration platforms
+- Fix incorrect property marker for airspeed attribute
+
+Version 2.0.2 (2015-11-30)
+--------------------------
+
+Bug Fixes:
+~~~~~~~~~~
+
+- Updates ``requests`` dependency to work >=2.5.0
+
+Version 2.0.0 (2015-11-23)
+--------------------------
+
+New Features:
+~~~~~~~~~~~~~
+
+- Renamed library and package from DroneAPI to DroneKit on pip
+- DroneKit Python is now a standalone library and no longer requires
+ use of MAVProxy
+- Connect multiple vehicles in one script by creating separate vehicle
+ instances
+- Removed NumPy, ProtoBuf as dependencies
+- Add MAVLink message listeners using ``add_message_listener`` methods
+- Added ``on_attribute`` and ``on_message`` function decorator
+ shorthands
+- Added ``mount_status``, ``system_status``, ``ekf_ok``,
+ ``is_armable``, ``heading``
+- Made settable ``groundspeed``, ``airspeed``
+- Moved ``dronekit.lib`` entries to root package ``dronekit``
+- Added ``parameters.set`` and ``parameters.get`` for fine-tuned
+ parameter access
+- ``parameters`` now observable and iterable (`#442 `_)
+- Added ``last_heartbeat`` attribute, updated every event loop with
+ time since last heartbeat (`#451 `_)
+- Await attributes through ``wait_ready`` method and ``connect`` method
+ parameter
+- Adds subclassable Vehicle class, used by ``vehicle_class`` parameter
+ in ``connect``
+
+Updated Features:
+~~~~~~~~~~~~~~~~~
+
+- local\_connect renamed to connect(), accepting a connection path,
+ link configuration, and timeout settings
+- Removed ``.set_mavrx_callback``. Use ``vehicle.on_message('*', obj)``
+ methods
+- Renamed ``add_attribute_observer`` methods to
+ ``add_attribute_listener``, etc. (`#420 `_)
+- Renamed ``wait_init`` and ``wait_valid`` to ``wait_ready``
+- Split ``home_location`` is a separate attribute from ``commands``
+ waypoint array
+- Moved RC channels into ``.channels`` object (`#427 `_)
+- Split location information into ``local_frame``, ``global_frame``,
+ and ``global_relative_frame`` (and removed ``is_relative``) (`#445 `_)
+- Renamed ``flush`` to ``commands.upload``, as it only impacts
+ waypoints (`#276 `_)
+- ``commands.goto`` and ``commands.takeoff`` renamed to ``simple_goto``
+ and ``simple_takeoff``
+
+Bug Fixes:
+~~~~~~~~~~
+
+- ``armed`` and ``mode`` attributes updated constantly (`#60 `_, `#446 `_)
+- Parameter setting times out (`#12 `_)
+- ``battery`` access can throw exception (`#298 `_)
+- Vehicle.location reports incorrect is\_relative value for Copter
+ (`#130 `_)
+- Excess arming message when already armed
diff --git a/docs/about/index.rst b/docs/about/index.rst
index cee9c6eb6..1d5866a3e 100644
--- a/docs/about/index.rst
+++ b/docs/about/index.rst
@@ -12,6 +12,7 @@ After reading, you will understand what the kit offers and the opportunities it
overview
release_notes
+ migrating
license
diff --git a/docs/about/license.rst b/docs/about/license.rst
index a7b95cc12..1fe406e2d 100644
--- a/docs/about/license.rst
+++ b/docs/about/license.rst
@@ -2,7 +2,7 @@
Open Source Licence
=======================
-DroneKit-Python is licensed under the *Apache License Version 2.0, January 2004 (http://www.apache.org/licenses/). This is present in the `LICENSE `_ file in the source tree, and reproduced below:
+DroneKit-Python is licensed under the *Apache License Version 2.0, January 2004* (http://www.apache.org/licenses/). This is present in the `LICENSE `_ file in the source tree, and reproduced below:
.. include:: ../../LICENSE
:literal:
\ No newline at end of file
diff --git a/docs/about/migrating.rst b/docs/about/migrating.rst
new file mode 100644
index 000000000..9654f9ce1
--- /dev/null
+++ b/docs/about/migrating.rst
@@ -0,0 +1,359 @@
+.. _migrating_dkpy2_0:
+
+=====================
+Migrating to DKPY 2.0
+=====================
+
+DroneKit-Python 2.0 has undergone a significant *architectural* evolution when compared to version 1.x (the library changed from a MAVProxy extension
+to a standalone Python module). The API itself remains similar, with the most important difference being that you
+now need to specify the vehicle target address inside the script.
+
+The sections below outline the main migration areas.
+
+.. note::
+
+ *DroneKit-Python version 1.5* has now been superseded (see these links for legacy `documentation `_
+ and `examples `_).
+
+
+Installation
+============
+
+DKPY 2.0 is now installed from `pip` on all platforms - see :ref:`installing_dronekit` for more information.
+
+Installation is generally simpler than on DK 1.x because there are far fewer dependencies (both MAVProxy and numpy
+are no longer needed).
+
+.. note::
+
+ * The DroneKit-Python Windows installer cannot be used for DKPY2.x (and is no longer needed).
+ * One implication of the reduced dependencies is that it should now be easier to use other Python distributions
+ (like ActivePython - although this has not been verified!)
+
+
+Launching scripts
+=================
+
+DroneKit-Python 2.0 apps are run from an ordinary Python command prompt. For example:
+
+.. code:: bash
+
+ some_python_script.py # or `python some_python_script.py`
+
+.. note::
+
+ This contrasts with DKPY 1.x scripts, which were run from within MAVProxy using the command:
+
+ .. code:: bash
+
+ api start some_python_script.py
+
+
+Code changes
+============
+
+This section outlines the changes you will need to make to your DroneKit-Python scripts.
+
+Connecting to a vehicle
+-----------------------
+
+You must specify the target vehicle address in your script (in DKPY 1.x this was done when you launched MAVProxy).
+
+The code fragment below shows how you import the :py:func:`connect() ` method and use it to return a
+connected :py:class:`Vehicle ` object. The address string passed to ``connect()`` takes the same
+values as were passed to *MAVProxy* when setting up a connection in DKPY 1.x (in this case, a SITL instance running on the same computer).
+
+.. code:: python
+
+ from dronekit import connect
+
+ # Connect to the Vehicle (in this case a UDP endpoint)
+ vehicle = connect('127.0.0.1:14550', wait_ready=True)
+
+.. note::
+
+ The ``wait_ready=True`` parameter ensures that ``connect()`` won't return until
+ :py:attr:`Vehicle.parameters ` and most other default attributes have been
+ populated with values from the vehicle. Check out :py:func:`Vehicle.wait_ready() ` for more
+ information (this method is used by the ``connect()`` implementation).
+
+ :py:func:`connect() ` also has arguments for setting the baud rate,
+ returning your own :ref:`custom vehicle classes ` and setting the length of the connection timeout.
+
+
+After connecting, the returned ``vehicle`` can be used in exactly the same way as in DKPY 1.x.
+
+.. note::
+
+ The above code replaces DKPY 1.x code to get the Vehicle (similar to the example below):
+
+ .. code:: python
+
+ # Get an instance of the API endpoint
+ api = local_connect()
+ # Get the connected vehicle (currently only one vehicle can be returned).
+ vehicle = api.get_vehicles()[0]
+
+
+
+.. todo:: Above link to the connect method in API ref - make sure connect() is documented.
+
+
+Connection status checks
+------------------------
+
+DroneKit no longer runs in *MAVProxy* so scripts don't need to monitor and act on external thread shutdown commands.
+
+Remove code that checks the ``api.exit`` status (note that the ``api.exit`` call below is commented out).
+
+.. code:: python
+
+ while not vehicle.armed # and not api.exit:
+ print " Waiting for arming..."
+ time.sleep(1)
+
+.. note::
+
+ In fact you should delete all references to ``APIConnection`` class and its methods (``get_vehicles()``, ``exit()`` and ``stop()``).
+
+
+
+
+Script completion checks
+------------------------
+
+Examples that might possibly have outstanding messages should call :py:func:`Vehicle.close() `
+before exiting to ensure that all messages have flushed before the script completes:
+
+.. code:: python
+
+ # About to exit script
+ vehicle.close()
+
+
+Command line arguments
+----------------------
+
+Remove any code that uses the ``local_arguments`` array to get script-local command line arguments (via MAVProxy).
+
+From DKPY 2.0 command line arguments are passed to ``sys.argv`` as with any other script. The examples use the
+`argparse `_ module for argument parsing, but you can
+use whatever method you like.
+
+.. note::
+
+ In DKPY 1.x the script's ``sys.argv`` values were the values passed to MAVProxy when it was
+ started. To access arguments passed to the script from *MAVProxy* you used the ``local_arguments`` array.
+ For example if you started a script as shown below:
+
+ .. code:: bash
+
+ api start my_script.py 101
+
+ Then you would read the integer in your code using
+
+ .. code:: python
+
+ my_argument = int(local_arguments[0])
+
+
+.. todo:: This addition closes https://github.com/dronekit/dronekit-python/issues/13
+
+
+Current script directory
+------------------------
+
+DroneKit-Python v1.x passed a global property ``load_path`` to any executed file containing the
+directory in which the script was running. This is no longer needed in version 2 and has been removed.
+
+Instead, use normal Python methods for getting file system information:
+
+.. code:: python
+
+ import os.path
+ full_directory_path_of_current_script = os.path.dirname(os.path.abspath(__file__))
+
+
+Vehicle.location
+----------------
+
+DroneKit-Python v1.x had a ``Vehicle.location`` attribute which provided latitude and longitude information in the
+global frame, and altitude either relative to sea-level or the home location (depending on the value of its ``is_relative`` member).
+
+DKPY2.0 uses and attribute with the same name to provide location in
+global, global-relative and local (NED) frames:
+
+.. code-block:: python
+
+ print "Global Location: %s" % vehicle.location.global_frame
+ print "Global Location (relative altitude): %s" % vehicle.location.global_relative_frame
+ print "Local Location: %s" % vehicle.location.local_frame
+
+For more information see: :py:attr:`Vehicle.location `,
+:py:attr:`Vehicle.location.global_frame `,
+:py:attr:`Vehicle.location.global_relative_frame `,
+:py:attr:`Vehicle.location.local_frame `, and :ref:`vehicle-information`.
+
+
+Takeoff and movement commands
+-----------------------------
+
+DroneKit-Python v1.x provided guided mode takeoff and movement methods ``Vehicle.commands.takeoff()``
+and ``Vehicle.commands.goto()``.
+
+DKPY2.0 instead provides :py:func:`Vehicle.simple_takeoff ` and
+:py:func:`Vehicle.simple_goto `. These are the same as the old methods
+except that ``simple_goto`` allows you to optionally set the default target groundspeed and airspeed.
+
+
+:py:attr:`Vehicle.airspeed ` and
+:py:attr:`Vehicle.groundspeed ` are now settable values. Call these to
+set the default target speed used when moving with :py:func:`Vehicle.simple_goto `
+(or other position-based movement commands).
+
+
+.. _migrating_dkpy2_0_home_location:
+
+Home location
+-------------
+
+DroneKit-Python 1.x code retrieved the home location from the first element in :py:attr:`Vehicle.commands `.
+This code must be replaced with the DroneKit-Python 2.x :py:attr:`Vehicle.home_location ` attribute.
+
+.. tip::
+
+ Even though the home location is no longer returned as the first waypoint in :py:attr:`Vehicle.commands `,
+ you will still need to download the commands in order to populate the value of
+ :py:attr:`Vehicle.home_location `.
+
+
+Missions and Waypoints
+----------------------
+
+The API for working with missions has been improved and made significantly more robust.
+
+One of the major changes is that the :py:attr:`Vehicle.commands ` list no
+longer includes the :ref:`home location ` waypoint in the 0th
+index. Another change is that we now wait for command download to complete using
+:py:attr:`Vehicle.commands.wait_ready() `.
+
+All the known bugs have been fixed. It is now much easier to download, clear, and add items to the mission
+because there is no need to work around race conditions and other issues with the API.
+
+For more information see :ref:`auto_mode_vehicle_control`.
+
+
+Observing attribute changes
+---------------------------
+
+The DroneKit-Python 1.x observer function ``vehicle.add_attribute_observer`` has been replaced by
+:py:func:`Vehicle.add_attribute_listener() ` or
+:py:func:`Vehicle.on_attribute() ` in DKYP2.x, and ``Vehicle.remove_attribute_observer``
+has been repaced by :py:func:`remove_attribute_listener() `.
+
+The main difference is that the callback function now takes three arguments (the vehicle object, attribute name, attribute value)
+rather than just the attribute name. This allows you to more easily write callbacks that support attribute-specific and
+vehicle-specific handling and means that you can get the new value from the callback attribute rather than by re-querying
+the vehicle.
+
+.. note::
+
+ The difference between :py:func:`Vehicle.add_attribute_listener() ` and
+ :py:func:`Vehicle.on_attribute() ` is that attribute listeners added using
+ :py:func:`Vehicle.on_attribute() ` cannot be removed (while ``on_attribute()``
+ has a more elegant syntax).
+
+A few attributes have been modified so that they only notify when the value changes:
+:py:func:`Vehicle.system_status `,
+:py:attr:`Vehicle.armed `, and
+:py:attr:`Vehicle.mode `. Users no longer need to add caching code
+for these attributes in their listeners.
+Attributes that provide "streams" of information (i.e. sensor output) remain unchanged.
+
+.. note::
+
+ If you're :ref:`creating your own attributes ` this caching is trivially
+ provided using the ``cache=True`` argument to
+ :py:func:`Vehicle.notify_attribute_listeners() `.
+
+See :ref:`vehicle_state_observe_attributes` for more information.
+
+
+Parameter changes
+-----------------
+
+In DKPY2 you can now :ref:`observe ` parameters in order to
+be notified of changes, and also :ref:`iterate `
+:py:attr:`Vehicle.parameters ` to get a list of off the supported
+values in the connected vehicle.
+
+In addition, the code to download parameters and keep information in sync with the vehicle
+is now a lot more robust.
+
+
+
+
+
+Intercepting MAVLink Messages
+-----------------------------
+
+DroneKit-Python 1.x used ``Vehicle.set_mavlink_callback()`` and ``Vehicle.unset_mavlink_callback``
+to set/unset a callback function that was invoked for every single mavlink message.
+
+In DKPY2 this has been replaced by the :py:func:`Vehicle.on_message() `
+decorator, which allows you to specify a callback function that will be invoked for a single message
+(or all messages, by specifying the message name as the wildcard string '``*``').
+
+.. tip::
+
+ :py:func:`Vehicle.on_message() ` is used in core DroneKit code for
+ message capture and to create ``Vehicle`` attributes.
+
+ The API also adds :py:func:`Vehicle.add_message_listener() `
+ and :py:func:`Vehicle.remove_message_listener() `.
+ These can be used instead of :py:func:`Vehicle.on_message() ` when you need to be
+ able to *remove* an added listener. Typically you won't need to!
+
+See :ref:`mavlink_messages` for more information.
+
+
+New attributes
+--------------
+
+In addition to the :ref:`home_location `,
+a few more attributes have been added, including:
+:py:func:`Vehicle.system_status `,
+:py:func:`Vehicle.heading `,
+:py:func:`Vehicle.mount_status `,
+:py:func:`Vehicle.ekf_ok `,
+:py:func:`Vehicle.is_armable `,
+:py:func:`Vehicle.last_heartbeat `.
+
+
+Channel Overrides
+-----------------
+
+.. warning::
+
+ Channel overrides (a.k.a “RC overrides”) are highly discommended (they are primarily implemented for
+ simulating user input and when implementing certain types of joystick control).
+
+DKPY v2 replaces the ``vehicle.channel_readback`` attribute with
+:py:attr:`Vehicle.channels ` (and the :py:class:`Channels `
+class) and the ``vehicle.channel_override`` attribute with
+:py:attr:`Vehicle.channels.overrides `
+(and the :py:class:`ChannelsOverrides ` class).
+
+Documentation and example code for how to use the new API are provided in :ref:`example_channel_overrides`.
+
+
+
+
+Debugging
+=========
+
+DroneKit-Python 1.x scripts were run in the context of a MAVProxy. This made them difficult to debug because you had to
+instrument your code in order to launch the debugger, and debug messages were interleaved with MAVProxy output.
+
+Debugging on DroneKit-Python 2.x is much easier. Apps are now just standalone scripts, and can be debugged
+using standard Python methods (including the debugger/IDE of your choice).
diff --git a/docs/about/overview.rst b/docs/about/overview.rst
index f0221b13f..05b814ffb 100644
--- a/docs/about/overview.rst
+++ b/docs/about/overview.rst
@@ -2,9 +2,10 @@
About DroneKit
==============
-DroneKit-Python is DroneKit's main API for *Air Computing* — allowing developers to create apps that run on an onboard :ref:`companion computer ` and communicate with the `ArduPilot `_ flight controller using a low-latency link. *Air apps* can significantly enhance the autopilot, adding greater intelligence to vehicle behaviour, and performing tasks that are computationally intensive or time-sensitive (for example, computer vision, path planning, or 3D modelling).
+DroneKit-Python allows developers to create apps that run on an onboard :ref:`companion computer ` and communicate with the `ArduPilot `_ flight controller using a low-latency link. Onboard apps can significantly enhance the autopilot, adding greater intelligence to vehicle behaviour, and performing tasks that are computationally intensive or time-sensitive (for example, computer vision, path planning, or 3D modelling). DroneKit-Python can also be used for ground station apps, communicating with vehicles over a higher latency RF-link.
+
+The API communicates with vehicles over MAVLink. It provides programmatic access to a connected vehicle's telemetry, state and parameter information, and enables both mission management and direct control over vehicle movement and operations.
-The API communicates with "locally connected" vehicles over MAVLink. It provides programmatic access to a connected vehicle's telemetry, state and parameter information, and enables both mission management and direct control over vehicle movement and operations.
Open source community
@@ -13,14 +14,19 @@ Open source community
DroneKit-Python is an open source and community-driven project.
You can find all the source code on `Github here `_ and check out our permissive :doc:`Apache v2 Licence `.
-If you want to join the community, then see our :doc:`contributing section ` for lots of ideas on how you can help.
+If you want to join the community, then see our :doc:`contributing section <../contributing/index>` for lots of ideas on how you can help.
Compatibility
=============
-DroneKit-Python is compatible with all vehicles using the `MAVLink protocol `_ (including most vehicles made by 3DR and other members of the `DroneCode foundation `_). It runs on Linux, Mac OS X, or Windows.
+DroneKit-Python is compatible with vehicles that communicate using the `MAVLink protocol `_ (including most vehicles made by `3DR `_ and other members of the `DroneCode foundation `_). It runs on Linux, Mac OS X, or Windows.
+
+.. note::
+
+ DroneKit-Python is validated against, and hence *most compatible* with, the `ArduPilot UAV Platform `_.
+ Vehicles running other autopilots may be be less compatible due to differences in adhererence/interpretation of the MAVLink specification.
+ Please report any autopilot-specific issues `on Github here `_.
-In addition to "Air apps", it can be used to create apps that run on a desktop ground station and communicate with ArduPilot over a higher latency RF-link.
API features
@@ -29,12 +35,12 @@ API features
The API provides classes and methods to:
-- Get a list of connected vehicles.
+- Connect to a vehicle (or multiple vehicles) from a script
- Get and set vehicle state/telemetry and parameter information.
- Receive asynchronous notification of state changes.
-- Create and manage waypoint missions (AUTO mode).
- Guide a UAV to specified position (GUIDED mode).
- Send arbitrary custom messages to control UAV movement and other hardware (GUIDED mode).
+- Create and manage waypoint missions (AUTO mode).
- Override RC channel settings.
A complete API reference is available :ref:`here `.
@@ -45,7 +51,7 @@ Technical support
This documentation is a great place to get started with developing DroneKit Python APIs.
-If you run into problems, the `best place to ask questions is Stack Overflow `_.
+If you run into problems, the best place to ask questions is the `DroneKit-Python Forum `_.
If your problem turns out to be a bug, then it should be `posted on Github `_.
diff --git a/docs/about/release_notes.rst b/docs/about/release_notes.rst
index fb4c44d60..c85bc804c 100644
--- a/docs/about/release_notes.rst
+++ b/docs/about/release_notes.rst
@@ -6,7 +6,7 @@ This page contains the release notes for DroneKit-Python ``minor`` and ``major``
.. note::
- DroneKit-Python marks releases using the ``major.minor.patch`` release numbering convention, where ``patch`` is used to denote only bug fixes, ``minor`` is used for releases with new features, and ``major`` indicates the release contains significant API changes. Patch releases are not separately documented here.
+ DroneKit-Python marks releases using the ``major.minor.patch`` release numbering convention, where ``patch`` is used to denote only bug fixes, ``minor`` is used for releases with new features, and ``major`` indicates the release contains significant API changes.
@@ -23,12 +23,14 @@ For information about all past releases, please see `this link on Github `_ for a list of all releases available on PyPI.
diff --git a/docs/automodule.rst b/docs/automodule.rst
index 28b53c593..ef3dd5414 100644
--- a/docs/automodule.rst
+++ b/docs/automodule.rst
@@ -5,10 +5,9 @@ DroneKit-Python API Reference
=============================
-.. automodule:: dronekit.lib
+.. automodule:: dronekit
:members:
:inherited-members:
- :exclude-members: Mission, get_mission, ConnectionInfo, web_connect, AuthInfo, delete
@@ -19,5 +18,4 @@ DroneKit-Python API Reference
-
.. todolist::
\ No newline at end of file
diff --git a/docs/conf.py b/docs/conf.py
index f569024a0..2509fc2de 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -41,17 +41,17 @@
master_doc = 'index'
# General information about the project.
-project = u'DroneKit Air: Python'
-copyright = u'2015, 3D Robotics'
+project = u'DroneKit Python'
+copyright = u'2015-2016, 3D Robotics'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
-version = '0.5'
+version = '2.4'
# The full version, including alpha/beta/rc tags.
-release = '0.5'
+release = '2.4.0'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
diff --git a/docs/contributing/contributions_api.rst b/docs/contributing/contributions_api.rst
index 7e137abc5..9a3c97b7f 100644
--- a/docs/contributing/contributions_api.rst
+++ b/docs/contributing/contributions_api.rst
@@ -6,16 +6,16 @@ Contributing to the API
This article provides a high level overview of how to contribute changes to the DroneKit-Python source code.
-.. tip::
+.. tip::
- We highly recommend that changes and ideas are `discussed with the project team
- `_ before starting work!
+ We highly recommend that changes and ideas are `discussed with the project team
+ `_ before starting work!
Submitting changes
==================
-Contributors should fork the main `dronekit/dronekit-python/ `_
+Contributors should fork the main `dronekit/dronekit-python/ `_
repository and contribute changes back to the project master branch using pull requests
* Changes should be :ref:`tested locally ` before submission.
@@ -30,21 +30,36 @@ repository and contribute changes back to the project master branch using pull r
Test code
=========
-Test code should be used to verify new and changed functionality. There are three test suites in DroneKit-Python:
+There are three test suites in DroneKit-Python:
-* **Unit tests** (:file:`tests/unit`) — verify all code paths of the API.
+* **Unit tests** (:file:`tests/unit`) — verify all code paths of the API.
* **Integration tests** (:file:`tests/sitl`) — verify real-world code, examples, and documentation as they would perform in a real environment.
-* **Web client tests** (:file:`tests/web`) — specifically verify the Python library's capability to talk to `DroneKit Cloud `_.
+
+Test code should be used to verify new and changed functionality. New tests should:
+
+#. Verify all code paths that code can take.
+#. Be concise and straightforward.
+#. Be documented.
+
Setting up local testing
------------------------
-The links below provide information on how to set up a development environment on your development computer. Changes to DroneKit can then be tested locally.
+Follow the links below to set up a development environment on your Linux or Windows computer.
* :ref:`dronekit_development_linux`
* :ref:`dronekit_development_windows`
-Several of the test suites use `nose `_, a Python library for writing test scripts and a command line tool for running these. When setting up your dev environment, all test dependencies will have been installed (via :file:`requirements.txt`).
+The tests require additional pip modules, including `nose `_, a
+Python library and tool for writing and running test scripts. These can be installed separately using either of the commands below:
+
+.. code:: bash
+
+ # Install just the additional requirements for tests
+ pip install requests nose mock
+
+ # (or) Install all requirements for dronekit, tests, and building documentation
+ pip install -r requirements.txt
For several tests, you may be required to set an **environment variable**. In your command line, you can set the name of a variable to equal a value using the following invocation, depending on your OS:
@@ -57,41 +72,53 @@ For several tests, you may be required to set an **environment variable**. In yo
Unit tests
----------
-Unit tests use *nosetests*. On any OS, enter the following command on a terminal/prompt to run the unit tests (and display a summary of the results):
+All new features should be created with accompanying unit tests.
+
+DroneKit-Python unit tests are based on the `nose `_ test framework,
+and use `mock `_ to simulate objects and APIs and
+ensure correct results.
+
+To run the tests and display a summary of the results (on any OS),
+navigate to the **dronekit-python** folder and enter the following
+command on a terminal/prompt:
.. code:: bash
- cd dronekit-python
- nosetests tests/unit
+ nosetests dronekit.test.unit
+
-For unit tests, `mock `_ is used to simulate objects and APIs and ensure correct results.
Writing a new unit test
^^^^^^^^^^^^^^^^^^^^^^^
-Good unit tests should:
+Create any file named :file:`test_XXX.py` in the :file:`tests/unit` folder to add it as a test.
+Feel free to copy from existing tests to get started. When *nosetests* is run, it will add your new test to its summary.
-#. Accompany all new features that are written.
-#. Verify all code paths that code can take.
-#. Be concise and straightforward.
+Tests names should be named based on their associated Github issue (for example,
+``test_12.py`` for `issue #12 `_)
+or describe the functionality covered (for example, ``test_waypoints.py``
+for a unit test for the waypoints API).
-Create any file named :file:`test_XXX.py` in the :file:`tests/unit` folder to add it as a test. Feel free to copy from existing tests to get started. When *nosetests* is run, it will add your new test to its summary.
+Use assertions to test your code is consistent. You can use the built-in Python ``assert`` macro as well as ``assert_equals`` and ``assert_not_equals``
+from the ``notestools`` module:
-Tests names should refer directly to a Github issue (for example, ``test_12.py`` would refer to `issue #12 `_ or describe fully what functionality they encompass (for example, ``test_waypoints.py`` would describe a unit test for the waypoints API).
+.. note::
-Avoiding printing any data from your test. Instead, use assertions to test your code is consistent. You can use the built-in Python ``assert`` macro as well as ``assert_equals`` from the ``nose.tools`` module:
+ Avoiding printing any data from your test!
.. code:: python
- from nose.tools import assert_equals
+ from nose.tools import assert_equals, assert_not_equals
def test_this(the_number_two):
assert the_number_two > 0, '2 should be greater than zero!'
- assert_equals(the_number_two, 2, '2 should equal two!'
+ assert_equals(the_number_two, 2, '2 should equal two!')
+ assert_not_equals(the_number_two, 1, '2 should equal one!')
Please add documentation to each test function describing what behavior it verifies.
+
Integration tests
-----------------
@@ -100,7 +127,18 @@ Integrated tests use a custom test runner that is similar to *nosetests*. On any
.. code:: bash
cd dronekit-python
- python -um tests.sitl
+ nosetests dronekit.test.sitl
+
+You can choose to run a specific tests. The example below shows how to run
+**\dronekit-python\dronekit\test\sitl\test_12.py**.
+
+.. code:: bash
+
+ nosetests dronekit.test.sitl.test_12
+
+
+Configuring the test environment
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Integrated tests use the SITL environment to run DroneKit tests against a simulated Copter. Because these tests emulate Copter in real-time, you can set several environment variables to tweak the environment that code is run in:
@@ -108,11 +146,7 @@ Integrated tests use the SITL environment to run DroneKit tests against a simula
#. ``TEST_RATE`` - Sets framerate. Default is ``TEST_RATE=200`` for copter, 50 for rover, 50 for plane.
#. ``TEST_RETRY`` - Retry failed tests. Default is ``TEST_RETRY=1``. This is useful if your testing environment generates inconsistent success rates because of timing.
-You can choose to test specific files by passing them as arguments:
-.. code:: bash
-
- python -um tests.sitl test_1.py test2_.py ...
Writing a new integration test
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -123,23 +157,40 @@ Integration tests should be written or improved whenever:
#. Example code or documentation has been added.
#. A feature could not be tested by unit tests alone (e.g. timing issues, mode changing, etc.)
-You can write a new integrated test by adding a file with the naming scheme :file:`test_XXX.py` to the :file:`tests/sitl` directory. In this file, functions with the prefix ``test_`` will be called with the ``local_connect`` parameter. For example:
+You can write a new integrated test by adding (or copying) a file with the naming scheme :file:`test_XXX.py` to the :file:`tests/sitl` directory.
+
+Tests names should be named based on their associated Github issue (for example,
+``test_12.py`` for `issue #12 `_)
+or describe the functionality covered (for example, ``test_waypoints.py``
+for an integration test for the waypoints API).
+
+Tests should minimally use the imports shown below and decorate test functions with ``@with_sitl``
+(this sets up the test and passes in a connection string for SITL).
.. code:: python
- from testlib import assert_equals
+ from dronekit import connect
+ from dronekit.test import with_sitl
+ from nose.tools import assert_equals, assert_not_equals
+
+ @with_sitl
+ def test_something(connpath):
+ vehicle = connect(connpath)
+
+ # Test using assert, assert_equals and assert_not_equals
+ ...
+
+ vehicle.close()
- def test_parameters(local_connect):
- v = local_connect().get_vehicles()[0]
- # Simple parameter checks
- assert_equals(type(v.parameters['THR_MIN']), float)
+Use assertions to test your code is consistent. You can use the built-in Python ``assert`` macro as well as ``assert_equals`` and ``assert_not_equals``
+from the ``testlib`` module:
-This checks to see that the parameter object is of type `float`.
+.. note::
+
+ Avoiding printing any data from your test!
-Tests names should refer directly to a Github issue (for example, ``test_12.py`` would refer to `issue #12 `_ or describe fully what functionality they encompass (for example, ``test_waypoints.py`` would describe a unit test for the waypoints API).
-Avoiding printing any data from your test. Instead, use assertions to test your code is consistent. You can use the built-in Python ``assert`` macro as well as ``assert_equals`` from the ``testlib`` module:
.. code:: python
@@ -150,21 +201,3 @@ Avoiding printing any data from your test. Instead, use assertions to test your
assert_equals(the_number_two, 2, '2 should equal two!'
Please add documentation to each test function describing what behavior it verifies.
-
-Web client tests
-----------------
-
-.. warning::
-
- The web client library is being rewritten. Please `discuss with the project team
- `_ if you intend to develop with or for the present version of the web client.
-
-Web client tests use *nosetests*. To run these, you will need to sign up for API keys from `cloud.dronekit.io `_.
-With these, export a variable named ``DRONEAPI_KEY`` with a value in the format ``.`` to your environment.
-
-On any OS, enter the following command on a terminal/prompt to run the web-client tests (and display summary results):
-
-.. code:: bash
-
- cd dronekit-python
- nosetests tests/web
diff --git a/docs/contributing/developer_setup_linux.rst b/docs/contributing/developer_setup_linux.rst
index 00ffeffce..6bf8a965c 100644
--- a/docs/contributing/developer_setup_linux.rst
+++ b/docs/contributing/developer_setup_linux.rst
@@ -5,7 +5,8 @@ Building DroneKit-Python on Linux
===================================
The setup for *developing* DroneKit-Python on Linux is almost the same as for *using*
-DroneKit-Python. We therefore recommend that you start by following the instructions in :ref:`Getting Started `.
+DroneKit-Python. We therefore recommend that you start by following the instructions in
+:ref:`installing_dronekit`.
When you've got DroneKit and a vehicle (simulated or real) communicating, you can
then build and install your own fork of DroneKit, as discussed below.
diff --git a/docs/contributing/developer_setup_windows.rst b/docs/contributing/developer_setup_windows.rst
index 81d7e90b1..b9d65ef25 100644
--- a/docs/contributing/developer_setup_windows.rst
+++ b/docs/contributing/developer_setup_windows.rst
@@ -6,60 +6,12 @@ Building DroneKit-Python on Windows
This article shows how to set up an environment for *developing* DroneKit-Python on Windows.
-.. tip::
-
- If you just want to *use* DroneKit-Python on Windows then easiest way to get started is to use the
- :ref:`Windows Installer <_get_started_install_dk_windows>`. The installer is rebuilt with every patch
- release, so you can always be up to date with the latest features and bug fixes.
-
Install DroneKit using WinPython command line
=============================================
-First set up a command line DroneKit-Python installation using *WinPython*. This Python distribution already includes most of the needed dependencies (though you will need remove *python-dateutil* as the installation comes bundled with a version that does not work with *DroneKit*).
-
-The steps to install this package and the most important add-on modules are:
-
-#. Download and run the correct `WinPython installer `_ (**v2.7**) for your platform (win32 vs win64).
-
- * Run the installer as an administrator (**Right-click** on file, select **Run as Administrator**).
- * When prompted for the destination location, specify **C:\Program Files (x86)**
- (the default location is under the **Downloads** folder).
-
-#. Register the Python that came from *WinPython* as the preferred interpreter for your machine:
- Open the folder where you installed WinPython, run *WinPython Control Panel* and choose **Advanced/Register Distribution**.
-
- .. image:: http://dev.ardupilot.com/wp-content/uploads/sites/6/2014/03/Screenshot-from-2014-09-03-083816.png
-
-#. Install DroneKit-Python and its remaining dependencies (including `MAVProxy `_) from the public PyPi repository:
-
- Open the *WinPython Command Prompt* and run the following two commands:
-
- .. code:: bash
-
- pip uninstall python-dateutil
- pip install dronekit
-
-The dependencies above are all that are required to build DroneKit-Python and the *MAVProxy command line* (i.e. the minimum needed for testing).
-If you also want the *MAVProxy console* and map install:
-
-#. OpenCV
-
- * `Download and install OpenCV version 2.4 for Windows `_ (this can be extracted anywhere)
- * Copy/paste the file :file:`cv2.pyd` from :file:`OpenCV\\build\\python\\2.7\\x64\\` to :file:`site_packages`
- on your Python installation (e.g. :file:`\\python-2.7.6.amd64\\Lib\\site-packages`).
-#. WxPython
-
- * `Download and install WxPython `_. Make sure the target
- path is your WinPython installation.
-#. Console
-
- * Open the WinPython command prompt and enter:
-
- .. code:: bash
-
- pip install console
+First set up a command line DroneKit-Python installation. We recommend *WinPython* or *ActivePython*, as discussed in :ref:`installing_dronekit`.
@@ -78,7 +30,7 @@ Fetch and build DroneKit source
python setup.py install
-
+
Updating DroneKit
=================
diff --git a/docs/guide/MissionPlanner_ConnectPort.png b/docs/develop/MissionPlanner_ConnectPort.png
similarity index 100%
rename from docs/guide/MissionPlanner_ConnectPort.png
rename to docs/develop/MissionPlanner_ConnectPort.png
diff --git a/docs/develop/best_practice.rst b/docs/develop/best_practice.rst
new file mode 100644
index 000000000..dec8c0640
--- /dev/null
+++ b/docs/develop/best_practice.rst
@@ -0,0 +1,246 @@
+.. _best_practices:
+
+==============
+Best Practices
+==============
+
+This guide provides a broad overview of how to use the API, its main programming idioms
+and best practices. More detail information is linked from each section.
+
+
+General considerations
+======================
+
+DroneKit-Python communicates with vehicle autopilots using the MAVLink protocol,
+which defines how commands, telemetry and vehicle settings/parameters
+are sent between vehicles, companion computers, ground stations and other systems on
+a MAVLink network.
+
+Some general considerations from using this protocol are:
+
+* Messages and message acknowledgments are not guaranteed to arrive (the protocol is not "lossless").
+* Commands may be silently ignored by the Autopilot if it is not in a state where it can
+ safely act on them.
+* Command acknowledgment and completion messages are not sent in most cases
+ (and if sent, may not arrive).
+* Commands may be interrupted before completion.
+* Autopilots may choose to interpret the protocol in slightly different ways.
+* Commands can arrive at the autopilot from multiple sources.
+
+Developers should code defensively. Where possible:
+
+* Check that a vehicle is in a state to obey a command (for example,
+ poll on :py:func:`Vehicle.is_armable `
+ before trying to arm the vehicle).
+* Don't assume that a command has succeeded until the changed behaviour is observed.
+ In particular we recommend a launch sequence where you check that the mode and arming
+ have succeeded before attempting to take off.
+* Monitor for state changes and react accordingly.
+ For example, if the user changes the mode from ``GUIDED`` your script should
+ stop sending commands.
+* Verify that your script can run inside the normal latency limits for message passing
+ from the vehicle and tune any monitoring appropriately.
+
+
+Connecting
+==========
+
+In most cases you'll use the normal way to :ref:`connect to a vehicle `,
+setting ``wait_ready=True`` to ensure that the vehicle is already populated with attributes
+when the :py:func:`connect() ` returns:
+
+.. code:: python
+
+ from dronekit import connect
+
+ # Connect to the Vehicle (in this case a UDP endpoint)
+ vehicle = connect('REPLACE_connection_string_for_your_vehicle', wait_ready=True)
+
+The ``connect()`` call will sometimes fail with an exception.
+Additional information about an exception can be obtained by
+running the connect within a ``try-catch`` block as shown:
+
+.. code-block:: python
+
+ import dronekit
+ import socket
+ import exceptions
+
+
+ try:
+ dronekit.connect('REPLACE_connection_string_for_your_vehicle', heartbeat_timeout=15)
+
+ # Bad TCP connection
+ except socket.error:
+ print 'No server exists!'
+
+ # Bad TTY connection
+ except exceptions.OSError as e:
+ print 'No serial exists!'
+
+ # API Error
+ except dronekit.APIException:
+ print 'Timeout!'
+
+ # Other error
+ except:
+ print 'Some other error!'
+
+.. tip::
+
+ The default ``heartbeat_timeout`` on connection is 30 sections. Usually a connection will
+ succeed quite quickly, so you may wish to reduce this in the ``connect()`` method as shown in the
+ code snippet above.
+
+If a connection succeeds from a ground station, but not from DroneKit-Python it may be that your baud
+rate is incorrect for your hardware. This rate can also be set in the ``connect()`` method.
+
+
+Launch sequence
+===============
+
+Generally you should use the standard launch sequence described in :doc:`../guide/taking_off`:
+
+* Poll on :py:func:`Vehicle.is_armable `
+ until the vehicle is ready to arm.
+* Set the :py:attr:`Vehicle.mode ` to ``GUIDED``
+* Set :py:attr:`Vehicle.armed ` to ``True`` and
+ poll on the same attribute until the vehicle is armed.
+* Call :py:func:`Vehicle.simple_takeoff `
+ with a target altitude.
+* Poll on the altitude and allow the code to continue only when it is reached.
+
+The approach ensures that commands are only sent to the vehicle when it is able
+to act on them (e.g. we know :py:func:`Vehicle.is_armable `
+is ``True`` before trying to arm, we know
+:py:attr:`Vehicle.armed ` is ``True`` before we take off).
+It also makes debugging takeoff problems a lot easier.
+
+
+Movement commands
+=================
+
+DroneKit-Python provides :py:func:`Vehicle.simple_goto ` for moving to a specific position (at a defined speed). It is also possible to control movement by sending commands to specify the vehicle's :ref:`velocity components `.
+
+.. note::
+
+ As with :py:func:`Vehicle.simple_takeoff `, movement
+ commands are asynchronous, and will be interrupted if another command arrives
+ before the vehicle reaches its target. Calling code should block and wait (or
+ check that the operation is complete) before preceding to the next command.
+
+For more information see: :ref:`guided_mode_copter`.
+
+
+Vehicle information
+===================
+
+Vehicle state information is exposed through vehicle *attributes* which can be read and observed (and in some cases written)
+and vehicle settings which can be read, written, iterated and observed using *parameters* (a special attribute). All the attributes are documented in :doc:`../guide/vehicle_state_and_parameters`.
+
+Attributes are populated by MAVLink messages from the vehicle.
+Information read from an attribute may not precisely reflect the actual value on the vehicle. Commands sent
+to the vehicle may not arrive, or may be ignored by the autopilot.
+
+If low-latency is critical, we recommend you verify that the update rate is achievable and
+perhaps modify script behaviour if :py:attr:`Vehicle.last_heartbeat ` falls outside
+a useful range.
+
+When setting attributes, poll their values to confirm that they have changed. This applies, in particular,
+to :py:attr:`Vehicle.armed ` and :py:attr:`Vehicle.mode `.
+
+
+
+Missions and waypoints
+======================
+
+DroneKit-Python can also :ref:`create and modify autonomous missions `.
+
+While it is possible to construct DroneKit-Python apps by dynamically constructing missions "on the fly", we recommend you use guided mode for Copter apps. This generally results in a better experience.
+
+.. tip::
+
+ If a mission command is not available in guided mode,
+ it can be useful to switch to a mission and call it, then change
+ back to normal guided mode operation.
+
+
+Monitor and react to state changes
+==================================
+
+Almost all attributes can be observed - see :ref:`vehicle_state_observe_attributes` for more information.
+
+Exactly what state information you observe, and how you react to it, depends on your particular script:
+
+* Most standalone apps should monitor the :py:func:`Vehicle.mode ` and
+ stop sending commands if the mode changes unexpectedly (this usually indicates
+ that the user has taken control of the vehicle).
+* Apps might monitor :py:func:`Vehicle.last_heartbeat `
+ and could attempt to reconnect if the value gets too high.
+* Apps could monitor :py:func:`Vehicle.system_status `
+ for ``CRITICAL`` or ``EMERGENCY`` in order to implement specific emergency handling.
+
+
+Sleep the script when not needed
+================================
+
+Sleeping your script can reduce the CPU overhead.
+
+For example, at low speeds you might only need to check whether you've reached a target every few seconds.
+Using ``time.sleep(2)`` between checks will be more efficient than checking more often.
+
+
+Exiting a script
+================
+
+Scripts should call :py:func:`Vehicle.close() `
+before exiting to ensure that all messages have flushed before the script completes:
+
+.. code:: python
+
+ # About to exit script
+ vehicle.close()
+
+
+Subclass Vehicle
+=====================================
+
+If you need to use functionality that is specific to particular hardware, we
+recommend you subclass :py:class:`Vehicle ` and pass this new class into
+:py:func:`connect() `.
+
+:doc:`../examples/create_attribute` shows how you can do this.
+
+
+
+
+Debugging
+=========
+
+DroneKit-Python apps are ordinary standalone Python scripts, and can be :doc:`debugged using standard Python methods <../guide/debugging>` (including the debugger/IDE of your choice).
+
+
+Launching scripts
+=================
+
+Scripts are run from an ordinary Python command prompt. For example:
+
+.. code:: bash
+
+ python some_python_script.py [arguments]
+
+Command line arguments are passed into the script as ``sys.argv`` variables (the normal)
+and you can use these directly or via an argument parser (e.g.
+`argparse `_).
+
+
+Current script directory
+========================
+
+You can use normal Python methods for getting file system information:
+
+.. code-block:: python
+
+ import os.path
+ full_directory_path_of_current_script = os.path.dirname(os.path.abspath(__file__))
+
diff --git a/docs/develop/coding_standards.rst b/docs/develop/coding_standards.rst
new file mode 100644
index 000000000..36828a5c5
--- /dev/null
+++ b/docs/develop/coding_standards.rst
@@ -0,0 +1,14 @@
+.. _coding_standards:
+
+==========================
+Coding Standards
+==========================
+
+DroneKit-Python does not impose (or recommend) a particular set of coding standards
+for third party code.
+
+Internally we run the `YAPF formatter `_
+on major releases and we expect contributors to copy the patterns used in similar
+code within the existing code base.
+
+
\ No newline at end of file
diff --git a/docs/guide/companion-computers.rst b/docs/develop/companion-computers.rst
similarity index 54%
rename from docs/guide/companion-computers.rst
rename to docs/develop/companion-computers.rst
index 2bc19c4da..f18dcb2b7 100644
--- a/docs/guide/companion-computers.rst
+++ b/docs/develop/companion-computers.rst
@@ -15,21 +15,21 @@ The following computing platforms are known to work with DroneKit, and are suppo
RaspberryPi
-----------
-* `Communicating with Raspberry Pi via MAVLink `_
-* `Making a Mavlink WiFi bridge using the Raspberry Pi `_
+* `Communicating with Raspberry Pi via MAVLink `_
+* `Making a Mavlink WiFi bridge using the Raspberry Pi `_
Intel Edison
------------
-* `Edison for drones `_
+* `Edison for drones `_
BeagleBoneBlack
---------------
-* `BeaglePilot `_
+* `BeaglePilot `_
Odroid
------
-* `Communicating with ODroid via MAVLink `_
-* `ODroid Wifi Access Point for sharing files via Samba `_
+* `Communicating with ODroid via MAVLink `_
+* `ODroid Wifi Access Point for sharing files via Samba `_
diff --git a/docs/develop/index.rst b/docs/develop/index.rst
new file mode 100644
index 000000000..250992942
--- /dev/null
+++ b/docs/develop/index.rst
@@ -0,0 +1,24 @@
+========================
+Developing with DroneKit
+========================
+
+DroneKit-Python is primarily intended for use on Linux-based :doc:`companion-computers` that travel
+on a vehicle and communicate with the autopilot via a serial port. It can also be used
+on ground-based computers running Linux, Windows or Mac OSX (communicating using WiFi or a telemetry radio).
+
+During development you'll generally run it on a development computer, communicating with a
+:doc:`simulated vehicle` running on the same machine (via a UDP connection).
+
+This section contains topics explaining how to develop with DroneKit-Python,
+covering subjects like installation, setting up the target vehicle or simulator, best practices
+and coding standards.
+
+
+.. toctree::
+ :maxdepth: 1
+
+ installation
+ companion-computers
+ Simulated Vehicle
+ best_practice
+ coding_standards
\ No newline at end of file
diff --git a/docs/develop/installation.rst b/docs/develop/installation.rst
new file mode 100644
index 000000000..bcfe09f64
--- /dev/null
+++ b/docs/develop/installation.rst
@@ -0,0 +1,49 @@
+.. _installing_dronekit:
+
+===================
+Installing DroneKit
+===================
+
+DroneKit-Python can be installed on a Linux, Mac OSX, or Windows computer that
+has Python 2.7 or Python 3 installed and can install Python packages from the Internet.
+
+It is installed from **pip** on all platforms:
+
+.. code-block:: bash
+
+ pip install dronekit
+
+
+**Installation notes:**
+
+* Install `dronekit` with `pip` inside a virtualenv:
+
+ .. code-block:: bash
+
+ python3 -m venv .venv
+ . .venv/bin/activate
+ pip install dronekit
+
+* On Linux you may need to first install **pip** and **python-dev**:
+
+ .. code-block:: bash
+
+ sudo apt-get install python-pip python-dev
+
+ Alternatively, you can use the `ensurepip` module to install or upgrade Pip on your system:
+
+
+ .. code-block:: bash
+
+ python -m ensurepip --upgrade
+
+* :doc:`companion-computers` are likely to run on stripped down versions of Linux. Ensure
+ you use a variant that supports Python 2.7 and can install Python packages from the Internet.
+* Windows does not come with Python by default, but there are
+ `many distributions available `_.
+ We have tested against:
+
+ * `WinPython 2.7 64bit `_ (see
+ `these instructions for installation and registration `_). This is the most tested version.
+ * `ActiveState ActivePython 2.7 `_.
+* Python 3 is fully supported.
diff --git a/docs/develop/sitl_setup.rst b/docs/develop/sitl_setup.rst
new file mode 100644
index 000000000..8da0c3871
--- /dev/null
+++ b/docs/develop/sitl_setup.rst
@@ -0,0 +1,200 @@
+.. _sitl_setup:
+
+=====================================
+Setting up a Simulated Vehicle (SITL)
+=====================================
+
+The `SITL (Software In The Loop) `_
+simulator allows you to create and test DroneKit-Python apps without a real vehicle (and from the comfort of
+your own developer desktop!).
+
+SITL can run natively on Linux (x86 architecture only), Mac and Windows, or within a virtual machine. It can be
+installed on the same computer as DroneKit, or on another computer on the same network.
+
+The sections below explain how to install and run SITL, and how to connect to DroneKit-Python and Ground
+Stations at the same time.
+
+
+.. _dronekit_sitl:
+
+DroneKit-SITL
+=============
+
+DroneKit-SITL is the simplest, fastest and easiest way to run SITL on Windows, Linux (x86 architecture only), or Mac OS X.
+It is installed from Python's *pip* tool on all platforms, and works by downloading and running pre-built
+vehicle binaries that are appropriate for the host operating system.
+
+This section provides an overview of how to install and use DroneKit-SITL. For more information, see
+the `project on Github `_.
+
+.. note::
+
+ DroneKit-SITL is still relatively experimental and there are only a few pre-built vehicles
+ (some of which are quite old and/or unstable).
+
+ The binaries are built and tested on Windows 10, Ubuntu Linux, and Mac OS X
+ "El Capitan". Binaries are only available for x86 architectures. ARM builds
+ (e.g. for RPi) are not supported.
+
+ Please report any issues on `Github here `_.
+
+Installation
+------------
+
+The tool is installed (or updated) on all platforms using the command:
+
+.. code-block:: bash
+
+ pip install dronekit-sitl -UI
+
+Running SITL
+------------
+
+To run the latest version of Copter for which we have binaries (downloading the binaries if needed), you can simply call:
+
+.. code-block:: bash
+
+ dronekit-sitl copter
+
+SITL will then start and wait for TCP connections on ``127.0.0.1:5760``.
+
+You can specify a particular vehicle and version, and also parameters like the home location,
+the vehicle model type (e.g. "quad"), etc. For example:
+
+.. code-block:: bash
+
+ dronekit-sitl plane-3.3.0 --home=-35.363261,149.165230,584,353
+
+There are a number of other useful arguments:
+
+.. code-block:: bash
+
+ dronekit-sitl -h #List all parameters to dronekit-sitl.
+ dronekit-sitl copter -h #List additional parameters for the specified vehicle (in this case "copter").
+ dronekit-sitl --list #List all available vehicles.
+ dronekit-sitl --reset #Delete all downloaded vehicle binaries.
+ dronekit-sitl ./path [args...] #Start SITL instance at target file location.
+
+
+.. note::
+
+ You can also use *dronekit-sitl* to start a SITL executable that you have built locally from source.
+ To do this, put the file path of the target executable in the `SITL_BINARY` environment variable,
+ or as the first argument when calling the tool.
+
+
+.. _connecting_dronekit_sitl:
+
+Connecting to DroneKit-SITL
+---------------------------
+
+DroneKit-SITL waits for TCP connections on ``127.0.0.1:5760``. DroneKit-Python scripts running on the same
+computer can connect to the simulation using the connection string as shown:
+
+.. code-block:: python
+
+ vehicle = connect('tcp:127.0.0.1:5760', wait_ready=True)
+
+After something connects to port ``5760``, SITL will then wait for additional connections on port ``5763``
+(and subsequently ``5766``, ``5769`` etc.)
+
+.. note::
+
+ While you can connect to these additional ports, some users have reported problems when
+ viewing the running examples with *Mission Planner*. If you need to connect a ground station
+ and DroneKit at the same time we recommend you use *MAVProxy* (see :ref:`viewing_uav_on_map`).
+
+
+
+.. _dronekit_sitl_api:
+
+DroneKit-SITL Python API
+------------------------
+
+DroneKit-SITL `exposes a Python API `_, which you can use to start and control simulation from within your scripts. This is particularly useful for test code and :ref:`examples `.
+
+
+
+
+Building SITL from source
+=========================
+
+You can natively build SITL from source on Linux, Windows and Mac OS X,
+or from within a Vagrant Linux virtual environment.
+
+Building from source is useful if you want to need to test the latest changes (or any use
+a version for which DroneKit-SITL does not have pre-built binaries).
+It can also be useful if you have problems getting DroneKit-SITL to work.
+
+SITL built from source has a few differences from DroneKit-SITL:
+
+* MAVProxy is included and started by default. You can use MAVProxy terminal to control the autopilot.
+* You connect to SITL via UDP on ``127.0.0.1:14550``. You can use MAVProxy's ``output add`` command to add additional ports if needed.
+* You may need to disable arming checks and load autotest parameters to run examples.
+* It is easier to `add a virtual rangefinder `_ and `add a virtual gimbal `_ for testing.
+
+The following topics from the ArduPilot wiki explain how to set up Native SITL builds:
+
+* `Setting up SITL on Linux `_
+* `Setting up SITL on Windows `_
+* `Setting up SITL using Vagrant `_
+
+
+.. _viewing_uav_on_map:
+
+Connecting an additional Ground Station
+=======================================
+
+You can connect a ground station to an unused port to which messages are being forwarded.
+
+The most reliable way to add new ports is to use *MAVProxy*:
+
+* If you're using SITL built from source you will already have *MAVProxy* running.
+ You can add new ports in the MAVProxy console using ``output add``:
+
+ .. code:: bash
+
+ output add 127.0.0.1:14552
+
+* If you're using Dronekit-SITL you can:
+
+ * `Install MAVProxy `_
+ for your system.
+ * In a second terminal spawn an instance of *MAVProxy* to forward messages from
+ TCP ``127.0.0.1:5760`` to other UDP ports like ``127.0.0.1:14550`` and ``127.0.0.1:14551``:
+
+ .. code-block:: bash
+
+ mavproxy.py --master tcp:127.0.0.1:5760 --sitl 127.0.0.1:5501 --out 127.0.0.1:14550 --out 127.0.0.1:14551
+
+Once you have available ports you can connect to a ground station using one UDP address, and DroneKit-Python using the other.
+
+For example, first connect the script:
+
+.. code-block:: python
+
+ vehicle = connect('127.0.0.1:14550', wait_ready=True)
+
+
+Then connect Mission Planner to the second UDP port:
+
+* `Download and install Mission Planner `_
+* Ensure the selection list at the top right of the Mission Planner screen says *UDP* and then select the **Connect** button next to it.
+ When prompted, enter the port number (in this case 14552).
+
+ .. figure:: MissionPlanner_ConnectPort.png
+ :width: 50 %
+
+ Mission Planner: Listen Port Dialog
+
+After connecting, vehicle parameters will be loaded into *Mission Planner* and the vehicle is displayed on the map.
+
+.. tip::
+
+ If you're using the :ref:`dronekit_sitl_api` then you will instead have to
+ connect to SITLs TCP port (as there is no way to set up MAVProxy in this case).
+ So if DroneKit is connecting to TCP port 5760, you would connect your GCS to 5763.
+
+ Note that a few examples may not behave perfectly using this approach. If you need to
+ observe them in a GCS you should run SITL externally and use MAVProxy to connect to it.
+
diff --git a/docs/examples/channel_overrides.rst b/docs/examples/channel_overrides.rst
new file mode 100644
index 000000000..8c95143f9
--- /dev/null
+++ b/docs/examples/channel_overrides.rst
@@ -0,0 +1,176 @@
+.. _example_channel_overrides:
+.. _vehicle_state_channel_override:
+
+=======================================
+Example: Channels and Channel Overrides
+=======================================
+
+This example shows how to get channel information and to get/set channel-override information.
+
+.. warning::
+
+ Channel overrides (a.k.a. "RC overrides") are highly dis-commended (they are primarily intended
+ for simulating user input and when implementing certain types of joystick control).
+
+ Instead use the appropriate MAVLink commands like DO_SET_SERVO/DO_SET_RELAY, or more generally set
+ the desired position or direction/speed.
+
+ If you have no choice but to use a channel-override please explain why in a
+ `Github issue `_ and we will attempt to find a
+ better alternative.
+
+
+Running the example
+===================
+
+The example can be run as described in :doc:`running_examples` (which in turn assumes that the vehicle
+and DroneKit have been set up as described in :ref:`installing_dronekit`).
+
+In summary, after cloning the repository:
+
+#. Navigate to the example folder as shown:
+
+ .. code-block:: bash
+
+ cd dronekit-python/examples/channel_overrides/
+
+
+#. You can run the example against a simulator (DroneKit-SITL) by specifying the Python script without any arguments.
+ The example will download SITL binaries (if needed), start the simulator, and then connect to it:
+
+ .. code-block:: bash
+
+ python channel_overrides.py
+
+ On the command prompt you should see (something like):
+
+ .. code:: bash
+
+ Starting copter simulator (SITL)
+ SITL already Downloaded.
+ Connecting to vehicle on: tcp:127.0.0.1:5760
+ >>> APM:Copter V3.3 (d6053245)
+ >>> Frame: QUAD
+ >>> Calibrating barometer
+ >>> Initialising APM...
+ >>> barometer calibration complete
+ >>> GROUND START
+ Channel values from RC Tx: {'1': 1500, '3': 1000, '2': 1500, '5': 1800, '4': 1500, '7': 1000, '6': 1000, '8': 1800}
+ Read channels individually:
+ Ch1: 1500
+ Ch2: 1500
+ Ch3: 1000
+ Ch4: 1500
+ Ch5: 1800
+ Ch6: 1000
+ Ch7: 1000
+ Ch8: 1800
+ Number of channels: 8
+ Channel overrides: {}
+ Set Ch2 override to 200 (indexing syntax)
+ Channel overrides: {'2': 200}
+ Ch2 override: 200
+ Set Ch3 override to 300 (dictionary syntax)
+ Channel overrides: {'3': 300}
+ Set Ch1-Ch8 overrides to 110-810 respectively
+ Channel overrides: {'1': 110, '3': 310, '2': 210, '5': 510, '4': 4100, '7': 710, '6': 610, '8': 810}
+ Cancel Ch2 override (indexing syntax)
+ Channel overrides: {'1': 110, '3': 310, '5': 510, '4': 4100, '7': 710, '6': 610, '8': 810}
+ Clear Ch3 override (del syntax)
+ Channel overrides: {'1': 110, '5': 510, '4': 4100, '7': 710, '6': 610, '8': 810}
+ Clear Ch5, Ch6 override and set channel 3 to 500 (dictionary syntax)
+ Channel overrides: {'3': 500}
+ Clear all overrides
+ Channel overrides: {}
+ Close vehicle object
+ Completed
+
+#. You can run the example against a specific connection (simulated or otherwise) by passing the :ref:`connection string ` for your vehicle in the ``--connect`` parameter.
+
+ For example, to connect to SITL running on UDP port 14550 on your local computer:
+
+ .. code-block:: bash
+
+ python channel_overrides.py --connect 127.0.0.1:14550
+
+
+How does it work?
+=================
+
+The RC transmitter channels are connected to the autopilot and control the vehicle.
+
+The values of the first four channels map to the main flight controls: 1=Roll, 2=Pitch, 3=Throttle, 4=Yaw (the mapping is defined in ``RCMAP_`` parameters in
+`Plane `_,
+`Copter `_ ,
+`Rover `_).
+
+The remaining channel values are configurable, and their purpose can be determined using the
+`RCn_FUNCTION parameters `_.
+In general a value of 0 set for a specific ``RCn_FUNCTION`` indicates that the channel can be
+`mission controlled `_ (i.e. it will not directly be
+controlled by normal autopilot code).
+
+You can read the values of the channels using the :py:attr:`Vehicle.channels ` attribute. The values are regularly updated,
+from the UAV, based on the RC inputs from the transmitter. These can be read either as a set or individually:
+
+.. code:: python
+
+ # Get all channel values from RC transmitter
+ print "Channel values from RC Tx:", vehicle.channels
+
+ # Access channels individually
+ print "Read channels individually:"
+ print " Ch1: %s" % vehicle.channels['1']
+ print " Ch2: %s" % vehicle.channels['2']
+
+You can override the values sent to the vehicle by the autopilot using :py:attr:`Vehicle.channels.overrides `.
+The overrides can be written individually using an indexing syntax or as a set using a dictionary syntax.
+
+.. code:: python
+
+ # Set Ch2 override to 200 using indexing syntax
+ vehicle.channels.overrides['2'] = 200
+ # Set Ch3, Ch4 override to 300,400 using dictionary syntax"
+ vehicle.channels.overrides = {'3':300, '4':400}
+
+To clear all overrides, set the attribute to an empty dictionary.
+To clear an individual override you can set its value to ``None`` (or call ``del`` on it):
+
+.. code:: python
+
+ # Clear override by setting channels to None
+ # Clear using index syntax
+ vehicle.channels.overrides['2'] = None
+
+ # Clear using 'del' syntax
+ del vehicle.channels.overrides['3']
+
+ # Clear using dictionary syntax (and set override at same time!)
+ vehicle.channels.overrides = {'5':None, '6':None,'3':500}
+
+ # Clear all overrides by setting an empty dictionary
+ vehicle.channels.overrides = {}
+
+Read the channel overrides either as a dictionary or by index.
+
+.. code:: python
+
+ # Get all channel overrides
+ print " Channel overrides: %s" % vehicle.channels.overrides
+ # Print just one channel override
+ print " Ch2 override: %s" % vehicle.channels.overrides['2']
+
+.. note::
+
+ You'll get a ``KeyError`` exception if you read a channel override that has
+ not been set.
+
+
+Source code
+===========
+
+The full source code at documentation build-time is listed below (`current version on github `_):
+
+.. literalinclude:: ../../examples/channel_overrides/channel_overrides.py
+ :language: python
+
diff --git a/docs/examples/create_attribute.rst b/docs/examples/create_attribute.rst
new file mode 100644
index 000000000..0f83b22f2
--- /dev/null
+++ b/docs/examples/create_attribute.rst
@@ -0,0 +1,283 @@
+.. _example_create_attribute:
+
+================================
+Example: Create Attribute in App
+================================
+
+This example shows how you can subclass :py:class:`Vehicle ` in order to support
+new attributes for MAVLink messages within your DroneKit-Python script. The new class is defined in a
+separate file (making re-use easy) and is very similar to the code used to implement the in-built attributes.
+The new attributes are used *in the same way* as the built-in
+:py:class:`Vehicle ` attributes.
+
+The new class uses the :py:func:`Vehicle.on_message() ` decorator
+to set a function that is called to process a specific message, copy its values into an attribute, and notify
+observers. An observer is then set on the new attribute using
+:py:func:`Vehicle.add_attribute_listener() `.
+
+Additional information is provided in the guide topic :ref:`mavlink_messages`.
+
+.. tip::
+
+ This approach is useful when you urgently need to access messages that are not yet supported as
+ :py:class:`Vehicle ` attributes.
+
+ Please :ref:`contribute your code to the API ` so that it is available to
+ (and can be tested by) the whole DroneKit-Python community.
+
+
+
+Running the example
+===================
+
+The example can be run as described in :doc:`running_examples` (which in turn assumes that the vehicle
+and DroneKit have been set up as described in :ref:`installing_dronekit`).
+
+In summary, after cloning the repository:
+
+#. Navigate to the example folder as shown:
+
+ .. code-block:: bash
+
+ cd dronekit-python\examples\create_attribute\
+
+#. You can run the example against a simulator (DroneKit-SITL) by specifying the Python script without any arguments.
+ The example will download SITL binaries (if needed), start the simulator, and then connect to it:
+
+ .. code-block:: bash
+
+ python create_attribute.py
+
+ On the command prompt you should see (something like):
+
+ .. code:: bash
+
+ Starting copter simulator (SITL)
+ SITL already Downloaded.
+ Connecting to vehicle on: tcp:127.0.0.1:5760
+ >>> APM:Copter V3.3 (d6053245)
+ >>> Frame: QUAD
+ >>> Calibrating barometer
+ >>> Initialising APM...
+ >>> barometer calibration complete
+ >>> GROUND START
+ Display RAW_IMU messages for 5 seconds and then exit.
+ RAW_IMU: time_boot_us=15340000,xacc=0,yacc=0,zacc=-1000,xgyro=0,ygyro=1,zgyro=0,xmag=161,ymag=19,zmag=-365
+ RAW_IMU: time_boot_us=15580000,xacc=0,yacc=0,zacc=-1000,xgyro=0,ygyro=0,zgyro=0,xmag=161,ymag=19,zmag=-365
+ RAW_IMU: time_boot_us=15820000,xacc=0,yacc=0,zacc=-999,xgyro=0,ygyro=1,zgyro=0,xmag=161,ymag=19,zmag=-365
+ RAW_IMU: time_boot_us=16060000,xacc=0,yacc=1,zacc=-999,xgyro=0,ygyro=0,zgyro=0,xmag=161,ymag=19,zmag=-365
+ RAW_IMU: time_boot_us=16300000,xacc=0,yacc=0,zacc=-999,xgyro=0,ygyro=0,zgyro=0,xmag=161,ymag=19,zmag=-365
+ RAW_IMU: time_boot_us=16540000,xacc=0,yacc=0,zacc=-1000,xgyro=0,ygyro=1,zgyro=0,xmag=161,ymag=19,zmag=-365
+ RAW_IMU: time_boot_us=16780000,xacc=0,yacc=0,zacc=-999,xgyro=0,ygyro=0,zgyro=0,xmag=161,ymag=19,zmag=-365
+ RAW_IMU: time_boot_us=17020000,xacc=1,yacc=0,zacc=-999,xgyro=0,ygyro=0,zgyro=0,xmag=161,ymag=19,zmag=-365
+ RAW_IMU: time_boot_us=17260000,xacc=0,yacc=0,zacc=-999,xgyro=0,ygyro=0,zgyro=0,xmag=161,ymag=19,zmag=-365
+ RAW_IMU: time_boot_us=17500000,xacc=0,yacc=0,zacc=-1000,xgyro=1,ygyro=0,zgyro=0,xmag=161,ymag=19,zmag=-365
+ RAW_IMU: time_boot_us=17740000,xacc=0,yacc=0,zacc=-999,xgyro=0,ygyro=0,zgyro=0,xmag=161,ymag=19,zmag=-365
+ RAW_IMU: time_boot_us=17980000,xacc=0,yacc=0,zacc=-999,xgyro=0,ygyro=0,zgyro=0,xmag=161,ymag=19,zmag=-365
+ RAW_IMU: time_boot_us=18220000,xacc=0,yacc=0,zacc=-1000,xgyro=0,ygyro=0,zgyro=1,xmag=161,ymag=19,zmag=-365
+ RAW_IMU: time_boot_us=18460000,xacc=0,yacc=0,zacc=-1000,xgyro=0,ygyro=0,zgyro=0,xmag=161,ymag=19,zmag=-365
+ RAW_IMU: time_boot_us=18700000,xacc=0,yacc=0,zacc=-999,xgyro=0,ygyro=0,zgyro=0,xmag=161,ymag=19,zmag=-365
+ RAW_IMU: time_boot_us=18940000,xacc=1,yacc=0,zacc=-1000,xgyro=0,ygyro=1,zgyro=0,xmag=161,ymag=19,zmag=-365
+ RAW_IMU: time_boot_us=19180000,xacc=1,yacc=0,zacc=-1000,xgyro=0,ygyro=0,zgyro=0,xmag=161,ymag=19,zmag=-365
+ RAW_IMU: time_boot_us=19420000,xacc=0,yacc=0,zacc=-999,xgyro=0,ygyro=0,zgyro=0,xmag=161,ymag=19,zmag=-365
+ RAW_IMU: time_boot_us=19660000,xacc=0,yacc=0,zacc=-1000,xgyro=0,ygyro=0,zgyro=0,xmag=154,ymag=52,zmag=-365
+ RAW_IMU: time_boot_us=19900000,xacc=0,yacc=0,zacc=-999,xgyro=0,ygyro=0,zgyro=0,xmag=154,ymag=52,zmag=-365
+ RAW_IMU: time_boot_us=20140000,xacc=0,yacc=0,zacc=-1000,xgyro=0,ygyro=0,zgyro=0,xmag=154,ymag=52,zmag=-365
+ Close vehicle object
+
+
+#. You can run the example against a specific connection (simulated or otherwise) by passing the :ref:`connection string ` for your vehicle in the ``--connect`` parameter.
+
+ For example, to connect to SITL running on UDP port 14550 on your local computer:
+
+ .. code-block:: bash
+
+ python create_attribute.py --connect 127.0.0.1:14550
+
+
+
+
+How does it work?
+=================
+
+Subclassing Vehicle
+-------------------
+
+The example file **my_vehicle.py** defines a class for the new attribute (``RawIMU``) and a new vehicle subclass (``MyVehicle``).
+
+.. note::
+
+ The example uses the same documentation markup used by the native code, which can be generated into a document set using
+ Sphinx/autodoc.
+
+
+``RawIMU`` has members for each of the values in the message
+(in this case `RAW_IMU `_). It provides an initialiser that sets all the values to
+``None`` and a string representation for printing the object.
+
+.. code:: python
+
+ class RawIMU(object):
+ """
+ The RAW IMU readings for the usual 9DOF sensor setup.
+ This contains the true raw values without any scaling to allow data capture and system debugging.
+
+ The message definition is here: http://mavlink.org/messages/common#RAW_IMU
+
+ :param time_boot_us: Timestamp (microseconds since system boot). #Note, not milliseconds as per spec
+ :param xacc: X acceleration (mg)
+ :param yacc: Y acceleration (mg)
+ :param zacc: Z acceleration (mg)
+ :param xgyro: Angular speed around X axis (millirad /sec)
+ :param ygyro: Angular speed around Y axis (millirad /sec)
+ :param zgyro: Angular speed around Z axis (millirad /sec)
+ :param xmag: X Magnetic field (milli tesla)
+ :param ymag: Y Magnetic field (milli tesla)
+ :param zmag: Z Magnetic field (milli tesla)
+ """
+
+ def __init__(self, time_boot_us=None, xacc=None, yacc=None, zacc=None, xygro=None, ygyro=None, zgyro=None, xmag=None, ymag=None, zmag=None):
+ """
+ RawIMU object constructor.
+ """
+ self.time_boot_us = time_boot_us
+ self.xacc = xacc
+ self.yacc = yacc
+ self.zacc = zacc
+ self.xgyro = zgyro
+ self.ygyro = ygyro
+ self.zgyro = zgyro
+ self.xmag = xmag
+ self.ymag = ymag
+ self.zmag = zmag
+
+ def __str__(self):
+ """
+ String representation of the RawIMU object
+ """
+ return "RAW_IMU: time_boot_us={},xacc={},yacc={},zacc={},xgyro={},ygyro={},zgyro={},xmag={},ymag={},zmag={}".format(self.time_boot_us, self.xacc, self.yacc,self.zacc,self.xgyro,self.ygyro,self.zgyro,self.xmag,self.ymag,self.zmag)
+
+
+``MyVehicle`` is a superclass of ``Vehicle`` (and hence inherits all its attributes).
+This first creates a private instance of ``RawIMU``.
+
+We create a listener using the :py:func:`Vehicle.on_message() `
+decorator. The listener is called for messages that contain the string "RAW_IMU",
+with arguments for the vehicle, message name, and the message. It copies the message information into
+the attribute and then notifies all observers.
+
+.. code-block:: python
+ :emphasize-lines: 6, 9-10, 32
+
+ class MyVehicle(Vehicle):
+ def __init__(self, *args):
+ super(MyVehicle, self).__init__(*args)
+
+ # Create an Vehicle.raw_imu object with initial values set to None.
+ self._raw_imu = RawIMU()
+
+ # Create a message listener using the decorator.
+ @self.on_message('RAW_IMU')
+ def listener(self, name, message):
+ """
+ The listener is called for messages that contain the string specified in the decorator,
+ passing the vehicle, message name, and the message.
+
+ The listener writes the message to the (newly attached) ``vehicle.raw_imu`` object
+ and notifies observers.
+ """
+ self._raw_imu.time_boot_us=message.time_usec
+ self._raw_imu.xacc=message.xacc
+ self._raw_imu.yacc=message.yacc
+ self._raw_imu.zacc=message.zacc
+ self._raw_imu.xgyro=message.xgyro
+ self._raw_imu.ygyro=message.ygyro
+ self._raw_imu.zgyro=message.zgyro
+ self._raw_imu.xmag=message.xmag
+ self._raw_imu.ymag=message.ymag
+ self._raw_imu.zmag=message.zmag
+
+ # Notify all observers of new message (with new value)
+ # Note that argument `cache=False` by default so listeners
+ # are updaed with every new message
+ self.notify_attribute_listeners('raw_imu', self._raw_imu)
+
+ @property
+ def raw_imu(self):
+ return self._raw_imu
+
+
+.. note::
+
+ The notifier function (:py:func:`Vehicle.notify_attribute_listeners() `)
+ should be called every time there is an update from the vehicle.
+
+ You can set a third parameter (``cache=True``) so that it only invokes the listeners when the value *changes*.
+ This is normally used for attributes like the vehicle mode, where the information is updated
+ regularly from the vehicle, but client code is only interested when the attribute changes.
+
+ You should not set ``cache=True`` for attributes that represent sensor information or other "live" information, including
+ the RAW_IMU attribute demonstrated here. Clients can then implement their own caching strategy if needed.
+
+
+At the end of the class we create the public properly ``raw_imu`` which client code may read and observe.
+
+.. note::
+
+ The decorator pattern means that you can have multiple listeners for a particular message or for different
+ messages and they can all have the same function name/prototype (in this case ``listener(self, name, message``).
+
+
+Using the Vehicle subclass
+--------------------------
+
+The **create_attribute.py** file first imports the ``MyVehicle`` class.
+
+
+.. code-block:: python
+ :emphasize-lines: 2
+
+ from dronekit import connect, Vehicle
+ from my_vehicle import MyVehicle #Our custom vehicle class
+ import time
+
+
+We then call ``connect()``, specifying this new class in the ``vehicle_class`` argument.
+
+.. code-block:: python
+
+ # Connect to our custom vehicle_class `MyVehicle` at address `args.connect`
+ vehicle = connect(args.connect, wait_ready=True, vehicle_class=MyVehicle)
+
+``connect()`` returns a ``MyVehicle`` class which can be used in *exactly the same way* as ``Vehicle`` but with an
+additional attribute ``raw_imu``. You can query the attribute to get any of its members, and even add an observer as shown:
+
+.. code:: python
+
+ # Add observer for the custom attribute
+
+ def raw_imu_callback(self, attr_name, value):
+ # attr_name == 'raw_imu'
+ # value == vehicle.raw_imu
+ print value
+
+ vehicle.add_attribute_listener('raw_imu', raw_imu_callback)
+
+
+
+Known issues
+============
+
+This code has no known issues.
+
+
+Source code
+===========
+
+The full source code at documentation build-time is listed below (`current version on github `_):
+
+.. literalinclude:: ../../examples/create_attribute/create_attribute.py
+ :language: python
+
+.. literalinclude:: ../../examples/create_attribute/my_vehicle.py
+ :language: python
\ No newline at end of file
diff --git a/docs/examples/drone_delivery.rst b/docs/examples/drone_delivery.rst
index e7f1ae520..371708e9b 100644
--- a/docs/examples/drone_delivery.rst
+++ b/docs/examples/drone_delivery.rst
@@ -2,7 +2,9 @@
Example: Drone Delivery
===========================
-This demonstration is a bit more extensive. It is a `CherryPy `_ based web application that displays a mapbox map to let you view the current vehicle position and send the vehicle commands to fly to a particular latitude and longitude.
+This example shows how to create a `CherryPy `_ based web application that
+displays a mapbox map to let you view the current vehicle position and send the vehicle commands
+to fly to a particular latitude and longitude.
New functionality demonstrated by this example includes:
@@ -10,34 +12,92 @@ New functionality demonstrated by this example includes:
* Starting *CherryPy* from a DroneKit application.
-Starting the demo
-=================
+Running the example
+===================
+
+The example can be run much as described in :doc:`running_examples` (which in turn assumes that the vehicle
+and DroneKit have been set up as described in :ref:`installing_dronekit`). The main exception is that you need to
+install the CherryPy dependencies and view the behaviour in a web browser.
+
+In summary, after cloning the repository:
+
+#. Navigate to the example folder as shown:
+
+ .. code-block:: bash
+
+ cd dronekit-python\examples\drone_delivery\
+
+
+#. Install *CherryPy* and any other dependencies from **requirements.pip** in that directory:
+
+ .. code-block:: bash
+
+ pip install -r requirements.pip
+
+#. You can run the example against the simulator by specifying the Python script without any arguments.
+ The example will download and start DroneKit-SITL, and then connect to it:
+
+ .. code-block:: bash
+
+ python drone_delivery.py
+
+ On the command prompt you should see (something like):
+
+ .. code:: bash
-The demonstration is started similar to the previous tutorials. You should see output that looks like the following:
+ >python drone_delivery.py
+
+ D:\Github\dronekit-python\examples\drone_delivery>drone_delivery.py
+ Starting copter simulator (SITL)
+ SITL already Downloaded.
+ local path: D:\Github\dronekit-python\examples\drone_delivery
+ Connecting to vehicle on: tcp:127.0.0.1:5760
+ >>> APM:Copter V3.3 (d6053245)
+ >>> Frame: QUAD
+ >>> Calibrating barometer
+ >>> Initialising APM...
+ >>> barometer calibration complete
+ >>> GROUND START
+ Launching Drone...
+ [DEBUG]: Connected to vehicle.
+ [DEBUG]: DroneDelivery Start
+ [DEBUG]: Waiting for location...
+ [DEBUG]: Waiting for ability to arm...
+ [DEBUG]: Running initial boot sequence
+ [DEBUG]: Changing to mode: GUIDED
+ [DEBUG]: ... polled mode: GUIDED
+ [DEBUG]: Waiting for arming...
+ >>> ARMING MOTORS
+ >>> GROUND START
+ >>> Initialising APM...
+ [DEBUG]: Taking off
+ http://localhost:8080/
+ Waiting for cherrypy engine...
-::
+#. You can run the example against a specific connection (simulated or otherwise) by passing the :ref:`connection string ` for your vehicle in the ``--connect`` parameter.
+ For example, to connect to Solo:
+
+ .. code-block:: bash
+
+ python drone_delivery.py --connect udpin:0.0.0.0:14550
+
+
+#. After a short while you should be able to reach your new webserver at http://localhost:8080.
+ Navigate to the **Command** screen, select a target on the map, then select **Go**.
+ The command prompt will show something like the message below.
+
+ .. code-block:: bash
+
+ [DEBUG]: Goto: [u'-35.4', u'149.2'], 29.98
+
+ The web server will switch you to the **Track** screen. You can view the vehicle progress by pressing the
+ **Update** button.
- GUIDED> api start drone_delivery.py
- GUIDED> [DEBUG]: DroneDelivery Start
- [DEBUG]: Waiting for GPS Lock
- [DEBUG]: DroneDelivery Armed Callback
- [DEBUG]: GPS: GPSInfo:fix=3,num_sat=10
- [DEBUG]: Running initial boot sequence
- [DEBUG]: Arming
- [DEBUG]: Taking off
- [DEBUG]: Mode: GUIDED
- INFO:cherrypy.error:[03/Mar/2015:14:29:01] ENGINE Bus STARTING
- INFO:cherrypy.error:[03/Mar/2015:14:29:01] ENGINE Started monitor thread '_TimeoutMonitor'.
- INFO:cherrypy.error:[03/Mar/2015:14:29:01] ENGINE Started monitor thread 'Autoreloader'.
- INFO:cherrypy.error:[03/Mar/2015:14:29:01] ENGINE Serving on http://0.0.0.0:8080
- INFO:cherrypy.error:[03/Mar/2015:14:29:01] ENGINE Bus STARTED
- ARMED
- GPS lock at 0 meters
Screenshots
===========
-You should be able to reach your new webserver at http://localhost:8080. It will look like the following:
+The webserver (http://localhost:8080) will look like the following:
.. image:: drone-delivery-splash.png
@@ -46,31 +106,37 @@ You should be able to reach your new webserver at http://localhost:8080. It will
.. image:: drone-delivery-command.png
-Looking at the code
-===================
+How it works
+============
Using attribute observers
-------------------------
-All attributes in DroneKit can have observers - this is the primary mechanism you should use to be notified of changes in vehicle state. For instance, `drone_delivery.py `_ calls:
-
-::
+All attributes in DroneKit can have observers - this is the primary mechanism you should use to be notified of changes in vehicle state.
+For instance, `drone_delivery.py `_ calls:
- self.vehicle.add_attribute_observer('location', self.location_callback)
+.. code-block:: python
- ...
+ self.vehicle.add_attribute_listener('location', self.location_callback)
- def location_callback(self, location):
- location = self.vehicle.location
+ ...
- if location.alt is not None:
- self.altitude = location.alt
+ def location_callback(self, vehicle, name, location):
+ if location.global_relative_frame.alt is not None:
+ self.altitude = location.global_relative_frame.alt
- self.current_location = location
+ self.current_location = location.global_relative_frame
This results in DroneKit calling our ``location_callback`` method any time the location attribute gets changed.
+.. tip::
+
+ It is also possible (and often more elegant) to add listeners using a decorator
+ - see :py:func:`Vehicle.on_attribute `.
+
+
+
Starting CherryPy from a DroneKit application
---------------------------------------------
@@ -78,9 +144,16 @@ We start running a web server by calling ``cherrypy.engine.start()``.
*CherryPy* is a very small and simple webserver. It is probably best to refer to their eight line `tutorial `_ for more information.
-Next we'll look at the basics of using the webservice and the local vehicle API to 'replay' a flight which has been uploaded to `Droneshare `_.
+Known issues
+============
+
+This example has the following issues:
+
+* `#537: Dronekit delivery tracking needs to zoom and also ideally auto update `_
+* `#538: Dronekit delivery example does not exit `_
+
Source code
===========
diff --git a/docs/examples/flight_replay.rst b/docs/examples/flight_replay.rst
index 4f8fac2be..63b3d175b 100644
--- a/docs/examples/flight_replay.rst
+++ b/docs/examples/flight_replay.rst
@@ -1,76 +1,192 @@
-=========================
+======================
Example: Flight Replay
-=========================
-
-This is an interesting demo that uses our web API to query raw flight data from a particular flight.
-
-
-Starting the demo
-=================
-
-In this case, we pick some public flight from `Droneshare `_:
-
-.. image:: flight_replay_example.png
-
-You'll notice that the mission number for this flight is 101.
-
-Now we'll launch **flight_replay.py** (/examples/flight_replay/flight_replay.py) and ask it to try and 'replay' mission 101. It will ask the web server for representative points from the flight, parse the JSON response and use that data to generate 100 waypoints we would like our vehicle to hit. For safety rather than using the altitude from the original flight we instead ask our vehicle to fly at a height of 30 meters.
-
-One possible use of some variant of this tool to replay your old flights at your regular test field.
-
-::
-
- STABILIZE> api start flight_replay.py 101
- STABILIZE> JSON downloaded...
- Genrating 95 waypoints from replay...
- APIThread-1 exiting...
- Got MAVLink msg: MISSION_ACK {target_system : 255, target_component : 0, type : 0}
- Sent waypoint 0 : MISSION_ITEM {target_system : 1, target_component : 1, seq : 0, frame : 3, command : 16, current : 0, autocontinue : 0, param1 : 0, param2 : 0, param3 : 0, param4 : 0, x : 45.7379052, y : 126.6273574, z : 30.0}
- Sent waypoint 1 : MISSION_ITEM {target_system : 1, target_component : 1, seq : 1, frame : 3, command : 16, current : 0, autocontinue : 0, param1 : 0, param2 : 0, param3 : 0, param4 : 0, x : 45.7378905, y : 126.6273609, z : 30.0}
- Sent waypoint 2 : MISSION_ITEM {target_system : 1, target_component : 1, seq : 2, frame : 3, command : 16, current : 0, autocontinue : 0, param1 : 0, param2 : 0, param3 : 0,
- ...
- Sent waypoint 92 : MISSION_ITEM {target_system : 1, target_component : 1, seq : 92, frame : 3, command : 16, current : 0, autocontinue : 0, param1 : 0, param2 : 0, param3 : 0, param4 : 0, x : 45.737971, y : 126.6274908, z : 30.0}
- Sent waypoint 93 : MISSION_ITEM {target_system : 1, target_component : 1, seq : 93, frame : 3, command : 16, current : 0, autocontinue : 0, param1 : 0, param2 : 0, param3 : 0, param4 : 0, x : 45.738018, y : 126.6275664, z : 30.0}
- Sent waypoint 94 : MISSION_ITEM {target_system : 1, target_component : 1, seq : 94, frame : 3, command : 16, current : 0, autocontinue : 0, param1 : 0, param2 : 0, param3 : 0, param4 : 0, x : 45.7380429, y : 126.6275067, z : 30.0}
- Sent all 95 waypoints
- Got MAVLink msg: MISSION_ACK {target_system : 255, target_component : 0, type : 0}
- APM: flight plan received
-
-
+======================
+
+This example creates and runs a waypoint mission using position information from a TLOG file.
+
+The log used in this example contains around 2700 points. This is too many points to upload
+to the autopilot (and to usefully display). Instead we only add points that are more than
+3 metres away from the previously kept point, and only store 99 points in total.
+After 60 seconds the mission is ended by setting the mode to RTL (return to launch).
+
+.. figure:: flight_replay_example.png
+ :width: 50%
+
+ 99 point mission generated from log
+
+
+.. note::
+
+ The method used to reduce the number of points is fairly effective, but we
+ could do better by grouping some of the waypoints, and mapping others using
+ spline waypoints. This might be a
+ `fun research project `_!
+
+
+
+Running the example
+===================
+
+The example can be run as described in :doc:`running_examples` (which in turn assumes that the vehicle
+and DroneKit have been set up as described in :ref:`installing_dronekit`).
+
+In summary, after cloning the repository:
+
+#. Navigate to the example folder as shown:
+
+ .. code-block:: bash
+
+ cd dronekit-python/examples/flight_replay/
+
+#. You can run the example against a simulator (DroneKit-SITL) by specifying the Python script without any arguments.
+ The example will download SITL binaries if needed, start the simulator, and then connect to it:
+
+ .. code-block:: bash
+
+ python flight_replay.py
+
+ On the command prompt you should see (something like):
+
+ .. code:: bash
+
+ Generating waypoints from tlog...
+ Generated 100 waypoints from tlog
+ Starting copter simulator (SITL)
+ SITL already Downloaded.
+ Connecting to vehicle on: tcp:127.0.0.1:5760
+ >>> APM:Copter V3.3 (d6053245)
+ >>> Frame: QUAD
+ >>> Calibrating barometer
+ >>> Initialising APM...
+ >>> barometer calibration complete
+ >>> GROUND START
+ Uploading 100 waypoints to vehicle...
+ Arm and Takeoff
+ Waiting for vehicle to initialise...
+ >>> flight plan received
+ Waiting for arming...
+ Waiting for arming...
+ Waiting for arming...
+ Waiting for arming...
+ >>> ARMING MOTORS
+ >>> GROUND START
+ Waiting for arming...
+ >>> Initialising APM...
+ Waiting for arming...
+ >>> ARMING MOTORS
+ Taking off!
+ Altitude: 0.000000 < 28.500000
+ Altitude: 0.010000 < 28.500000
+ ...
+ Altitude: 26.350000 < 28.500000
+ Altitude: 28.320000 < 28.500000
+ Reached target altitude of ~30.000000
+ Starting mission
+ Distance to waypoint (1): 3.02389745499
+ >>> Reached Command #1
+ Distance to waypoint (2): 5.57718471895
+ Distance to waypoint (2): 4.1504263025
+ >>> Reached Command #2
+ Distance to waypoint (3): 0.872847106279
+ Distance to waypoint (3): 1.88967925144
+ Distance to waypoint (3): 2.16157704522
+ >>> Reached Command #3
+ Distance to waypoint (4): 4.91867197924
+ ...
+ ...
+ Distance to waypoint (35): 4.37309981133
+ >>> Reached Command #35
+ Distance to waypoint (36): 5.61829417257
+ >>> Reached Command #36
+ Return to launch
+ Close vehicle object
+ Completed...
+
+
+ .. tip::
+ It is more interesting to watch the example run on a map than the console. The topic :ref:`viewing_uav_on_map`
+ explains how to set up *Mission Planner* to view a vehicle running on the simulator (SITL).
+
+#. You can run the example against a specific connection (simulated or otherwise) by passing the :ref:`connection string ` for your vehicle in the ``--connect`` parameter.
+
+ For example, to connect to SITL running on UDP port 14550 on your local computer:
+
+ .. code-block:: bash
+
+ python simple_goto.py --connect 127.0.0.1:14550
+
+
+
How it works
============
Getting the points
------------------
-The following simple function asks for the droneshare flight data:
-
-::
+The example parses the **flight.tlog** file for position information. First we read all the points.
+We then keep the first 99 points that are at least 3 metres separated from the preceding kept point.
+
+For safety reasons, the altitude for the waypoints is set to 30 meters (irrespective of the recorded height).
+
+.. code:: python
+
+ def position_messages_from_tlog(filename):
+ """
+ Given telemetry log, get a series of wpts approximating the previous flight
+ """
+ # Pull out just the global position msgs
+ messages = []
+ mlog = mavutil.mavlink_connection(filename)
+ while True:
+ try:
+ m = mlog.recv_match(type=['GLOBAL_POSITION_INT'])
+ if m is None:
+ break
+ except Exception:
+ break
+ # ignore we get where there is no fix:
+ if m.lat == 0:
+ continue
+ messages.append(m)
+
+ # Shrink the number of points for readability and to stay within autopilot memory limits.
+ # For coding simplicity we:
+ # - only keep points that are with 3 metres of the previous kept point.
+ # - only keep the first 100 points that meet the above criteria.
+ num_points = len(messages)
+ keep_point_distance=3 #metres
+ kept_messages = []
+ kept_messages.append(messages[0]) #Keep the first message
+ pt1num=0
+ pt2num=1
+ while True:
+ #Keep the last point. Only record 99 points.
+ if pt2num==num_points-1 or len(kept_messages)==99:
+ kept_messages.append(messages[pt2num])
+ break
+ pt1 = LocationGlobalRelative(messages[pt1num].lat/1.0e7,messages[pt1num].lon/1.0e7,0)
+ pt2 = LocationGlobalRelative(messages[pt2num].lat/1.0e7,messages[pt2num].lon/1.0e7,0)
+ distance_between_points = get_distance_metres(pt1,pt2)
+ if distance_between_points > keep_point_distance:
+ kept_messages.append(messages[pt2num])
+ pt1num=pt2num
+ pt2num=pt2num+1
+
+ return kept_messages
- def download_messages(mission_id, max_freq = 1.0):
- """Download a public mission from droneshare (as JSON)"""
- f = urllib.urlopen("%s/api/v1/mission/%s/messages.json?max_freq=%s&api_key=%s" % (api_server, mission_id, max_freq, api_key))
- j = json.load(f, object_hook=_decode_dict)
- f.close()
- return j
-
-Some comments:
-
-* ``max_freq`` is used to throttle the messages found in the raw flight data to a lower message rate
-* ``_decode_dict`` is a utility function found on stack overflow which extracts usable strings from unicode encoded JSON (see `flight_replay.py `_ for its implementation).
Setting the new waypoints
-=========================
+-------------------------
-We generate up to 100 waypoints for the vehicle with the following code:
+The following code shows how the vehicle writes the received messages as commands (this part of the code is very similar to that
+shown in :ref:`example_mission_basic`):
-::
+.. code:: python
print "Generating %s waypoints from replay..." % len(messages)
- cmds = v.commands
+ cmds = vehicle.commands
cmds.clear()
- v.flush()
for i in xrange(0, len(messages)):
pt = messages[i]
lat = pt['lat']
@@ -86,11 +202,16 @@ We generate up to 100 waypoints for the vehicle with the following code:
0, 0, 0, 0, 0, 0,
lat, lon, altitude)
cmds.add(cmd)
- v.flush()
+ #Upload clear message and command messages to vehicle.
+ cmds.upload()
-Next we'll work with existing Linux services (gpsd) to add a new drone based feature called :ref:`Follow Me `.
+Known issues
+============
+
+There are no known issues with this example.
+
Source code
===========
@@ -100,4 +221,3 @@ The full source code at documentation build-time is listed below (`current versi
.. literalinclude:: ../../examples/flight_replay/flight_replay.py
:language: python
-
\ No newline at end of file
diff --git a/docs/examples/flight_replay_example.png b/docs/examples/flight_replay_example.png
index 5464c7ec8..67f29570f 100644
Binary files a/docs/examples/flight_replay_example.png and b/docs/examples/flight_replay_example.png differ
diff --git a/docs/examples/follow_me.rst b/docs/examples/follow_me.rst
index e9691a279..532c362b9 100644
--- a/docs/examples/follow_me.rst
+++ b/docs/examples/follow_me.rst
@@ -4,39 +4,157 @@
Example: Follow Me
==================
-This is a significantly more complex example – showing closed-loop control of the vehicle. It will use a USB GPS attached to your laptop to have the vehicle follow you as you walk around a field.
+The *Follow Me* example moves a vehicle to track your position, using location information from a USB GPS attached to your (Linux) laptop.
-Run this example with caution - be ready to exit follow-me mode by switching the flight mode switch on your RC radio.
+The source code is a good *starting point* for your own applications. It can be extended to use other
+python language features and libraries (OpenCV, classes, lots of packages etc...)
-In practice, you don't really want to use this follow-me implementation, rather you can use this example as a starting point to build your own custom application.
-Before running this demo you'll need to make sure your computer has the gpsd service installed.
+.. note:: This example can only run on a Linux computer, because it depends on the Linux-only *gpsd* service.
+
+.. warning:: Run this example with caution - be ready to exit follow-me mode by switching the flight mode switch on your RC radio.
-*Ubuntu install*
-.. code-block:: bash
+Running the example
+===================
- apt-get install gpsd gpsd-clients
+DroneKit (for Linux) and the vehicle should be set up as described in :ref:`installing_dronekit`.
-You can then plug in a USB GPS and run the "xgps" client to confirm that it is working. If you do not have a USB GPS you can use simulated data by running *dronekit-python/examples/run-fake-gps.sh*.
+Once you've done that:
-Once your GPS is plugged in you can start follow-me by running the following command inside of MAVProxy:
+#. Install the *gpsd* service (as shown for Ubuntu Linux below):
-.. code-block:: bash
+ .. code-block:: bash
- RTL> api start follow_me.py
- RTL> Going to: Location:lat=50.616468333,lon=7.131903333,alt=30,is_relative=True
- Got MAVLink msg: MISSION_ACK {target_system : 255, target_component : 0, type : 0}
- GUIDED> Mode GUIDED
- Going to: Location:lat=50.616468333,lon=7.131903333,alt=30,is_relative=True
- Got MAVLink msg: MISSION_ACK {target_system : 255, target_component : 0, type : 0}
- ...
+ sudo apt-get install gpsd gpsd-clients
-These debugging messages will appear every two seconds - when a new target position is sent to the vehicle, to stop follow-me either change the vehicle mode switch on your RC transmitter or type "api stop".
+ You can then plug in a USB GPS and run the "xgps" client to confirm that it is working.
+
+ .. note::
+
+ If you do not have a USB GPS you can use simulated data by running *dronekit-python/examples/follow_me/run-fake-gps.sh*
+ (in a separate terminal from where you're running DroneKit-Python). This approach simulates a single location, and so
+ is really only useful for verifying that the script is working correctly.
+
-The source code for this example is a good starting point for your own application, from here you can use all python language features and libraries (OpenCV, classes, lots of packages etc...)
+#. Get the DroneKit-Python example source code onto your local machine. The easiest way to do this
+ is to clone the **dronekit-python** repository from Github. On the command prompt enter:
+
+ .. code-block:: bash
+
+ git clone http://github.com/dronekit/dronekit-python.git
+
+#. Navigate to the example folder as shown:
+
+ .. code-block:: bash
+
+ cd dronekit-python/examples/follow_me/
+
+
+#. You can run the example against a simulator (DroneKit-SITL) by specifying the Python script without any arguments.
+ The example will download SITL binaries (if needed), start the simulator, and then connect to it:
+
+ .. code-block:: bash
+
+ python follow_me.py
+
+ On the command prompt you should see (something like):
+
+ .. code:: bash
+
+ Starting copter simulator (SITL)
+ SITL already Downloaded.
+ Connecting to vehicle on: tcp:127.0.0.1:5760
+ >>> APM:Copter V3.4-dev (e0810c2e)
+ >>> Frame: QUAD
+ Link timeout, no heartbeat in last 5 seconds
+ Basic pre-arm checks
+ Waiting for GPS...: None
+ ...
+ Waiting for GPS...: None
+ Taking off!
+ Altitude: 0.019999999553
+ ...
+ Altitude: 4.76000022888
+ Reached target altitude
+ Going to: Location:lat=50.616468333,lon=7.131903333,alt=30,is_relative=True
+ ...
+ Going to: Location:lat=50.616468333,lon=7.131903333,alt=30,is_relative=True
+ Going to: Location:lat=50.616468333,lon=7.131903333,alt=30,is_relative=True
+ User has changed flight modes - aborting follow-me
+ Close vehicle object
+ Completed
+
+ .. note::
+
+ The terminal output above was created using simulated GPS data
+ (which is why the same target location is returned every time).
+
+ To stop follow-me you can change the vehicle mode or do Ctrl+C
+ (on a real flight you can just change the mode switch on your
+ RC transmitter).
+
+
+#. You can run the example against a specific connection (simulated or otherwise) by passing the :ref:`connection string ` for your vehicle in the ``--connect`` parameter.
+
+ For example, to connect to SITL running on UDP port 14550 on your local computer:
+
+ .. code-block:: bash
+
+ python follow_me.py --connect 127.0.0.1:14550
+
+
+
+How does it work?
+=================
+
+Most of the example should be fairly familiar as it uses the same code as other examples for connecting to the vehicle,
+:ref:`taking off `, and closing the vehicle object.
+
+The example-specific code is shown below. All this does is attempt to get a gps socket and read the location in a two second loop. If it is successful it
+reports the value and uses :py:func:`Vehicle.simple_goto ` to move to the new position. The loop exits when
+the mode is changed.
+
+.. code-block:: python
+
+ import gps
+ import socket
+
+ ...
+
+ try:
+ # Use the python gps package to access the laptop GPS
+ gpsd = gps.gps(mode=gps.WATCH_ENABLE)
+
+ #Arm and take off to an altitude of 5 meters
+ arm_and_takeoff(5)
+
+ while True:
+
+ if vehicle.mode.name != "GUIDED":
+ print "User has changed flight modes - aborting follow-me"
+ break
+
+ # Read the GPS state from the laptop
+ gpsd.next()
+
+ # Once we have a valid location (see gpsd documentation) we can start moving our vehicle around
+ if (gpsd.valid & gps.LATLON_SET) != 0:
+ altitude = 30 # in meters
+ dest = LocationGlobalRelative(gpsd.fix.latitude, gpsd.fix.longitude, altitude)
+ print "Going to: %s" % dest
+
+ # A better implementation would only send new waypoints if the position had changed significantly
+ vehicle.simple_goto(dest)
+
+ # Send a new target every two seconds
+ # For a complete implementation of follow me you'd want adjust this delay
+ time.sleep(2)
+
+ except socket.error:
+ print "Error: gpsd service does not seem to be running, plug in USB GPS or run run-fake-gps.sh"
+ sys.exit(1)
-Next, take a look at the full :ref:`api_reference` for more information.
Source code
diff --git a/docs/examples/guided-set-speed-yaw-demo.rst b/docs/examples/guided-set-speed-yaw-demo.rst
index 7c272927d..22554157f 100644
--- a/docs/examples/guided-set-speed-yaw-demo.rst
+++ b/docs/examples/guided-set-speed-yaw-demo.rst
@@ -4,9 +4,14 @@
Example: Guided Mode Movement and Commands (Copter)
===================================================
-This example shows how to control Copter movement and send immediate commands in :ref:`GUIDED mode `. It demonstrates three methods for explicitly specifying a target position and two commands for controlling movement by setting the vehicle's velocity vectors. It also shows how to send commands to control the yaw (direction that the front of the vehicle is pointing), region of interest, speed and home position, along with some useful functions for converting between frames of reference.
+This example shows how to control Copter movement and send immediate commands in :ref:`GUIDED mode `.
+It demonstrates three methods for explicitly specifying a target position and two commands for controlling movement by
+setting the vehicle's velocity vectors. It also shows how to send commands to control the yaw (direction that the front
+of the vehicle is pointing), region of interest, speed and home location, along with some useful functions for
+converting between frames of reference.
-The example is :ref:`documented in the source code `. More detailed information about using GUIDED mode can be found in the guide: :ref:`guided_mode_copter`.
+The example is :ref:`documented in the source code `.
+More detailed information about using GUIDED mode can be found in the guide: :ref:`guided_mode_copter`.
.. figure:: GuidedModeExample_FlyByPosition.png
@@ -27,123 +32,149 @@ The example is :ref:`documented in the source code `
Running the example
===================
-The vehicle and DroneKit should be set up as described in :ref:`get-started`.
-If you're using a simulated vehicle, remember to :ref:`disable arming checks ` so
-that the example can run.
+The example can be run as described in :doc:`running_examples` (which in turn assumes that the vehicle
+and DroneKit have been set up as described in :ref:`installing_dronekit`).
-Once *MAVProxy* is running and the API is loaded, you can start the example by typing: ``api start guided_set_speed_yaw.py``.
+In summary, after cloning the repository:
+
+#. Navigate to the example folder as shown:
+
+ .. code-block:: bash
+
+ cd dronekit-python/examples/guided_set_speed_yaw/
-.. note::
- The command above assumes you started the *MAVProxy* prompt in a directory containing the example script. If not,
- you will have to specify the full path to the script (e.g. on Linux):
- ``api start /home/user/git/dronekit-python/examples/guided_set_speed_yaw/guided_set_speed_yaw.py``.
-
-On the *MAVProxy* console you should see (something like):
-
-::
-
- MAV> api start /home/user/git/dronekit-python/examples/guided_set_speed_yaw/guided_set_speed_yaw.py
- STABILIZE> Basic pre-arm checks
- Arming motors
- Waiting for arming...
- Waiting for arming...
- GUIDED> Waiting for arming...
- Taking off!
- Altitude: 0.00999999977648
- Altitude: 0.159999996424
- Altitude: 0.920000016689
- Altitude: 2.38000011444
- Altitude: 3.93000006676
- Altitude: 4.65000009537
- Altitude: 4.82999992371
- Reached target altitude
-
- TRIANGLE path using standard Vehicle.commands.goto()
- Position North 80 West 50
- Distance to target: 100.792762965
- Distance to target: 100.25918006
- ...
- Distance to target: 2.34237912414
- Distance to target: 0.308823685384
- Reached target
- Position North 0 East 100
- Distance to target: 122.62321461
- ...
- Distance to target: 5.39403923852
- Distance to target: 1.00445126117
- Reached target
- Position North -80 West 50
- goto_target_globalint_position
- Distance to target: 100.792430952
- Distance to target: 100.221083739
- ...
- Distance to target: 1.69678155659
- Distance to target: 0.0798488767383
- Reached target
-
- TRIANGLE path using standard SET_POSITION_TARGET_GLOBAL_INT message and with varying speed.
- Position South 100 West 130
- Set speed to 5m/s.
- Distance to target: 181.439594672
- Distance to target: 132.170351744
- ...
- Distance to target: 2.67615248028
- Distance to target: 0.382959594982
- Reached target
- Set speed to 15m/s (max).
- Position South 0 East 200
- Distance to target: 318.826739407
- Distance to target: 317.613357051
- ...
- Distance to target: 3.5935761745
- Distance to target: 0.114090613451
- Reached target
- Set speed to 10m/s (max).
- Position North 100 West 130
- goto_target_globalint_position
- Distance to target: 188.182423388
- Distance to target: 187.540272979
- ...
- Distance to target: 4.82317050152
- Distance to target: 0.377390539948
- Reached target
-
- SQUARE path using SET_POSITION_TARGET_LOCAL_NED and position parameters
- North 50m, East 0m, 10m altitude for 20 seconds
- Point ROI at current location (home position)
- North 50m, East 50m, 10m altitude
- Point ROI at current location
- North 0m, East 50m, 10m altitude
- North 0m, East 0m, 10m altitude
-
- SQUARE path using SET_POSITION_TARGET_LOCAL_NED and velocity parameters
- Velocity South & up
- Yaw 180 absolute (South)
- Velocity West & down
- Yaw 270 absolute (West)
- Velocity North
- Yaw 0 absolute (North)
- Velocity East
-
- DIAMOND path using SET_POSITION_TARGET_GLOBAL_INT and velocity parameters
- Velocity North, East and up
- Yaw 225 absolute
- Velocity South, East and down
- Yaw 90 relative (to previous yaw heading)
- Set new Home location to current location
- Get new home location
- Home WP: MISSION_ITEM {target_system : 255, target_component : 0, seq : 0, frame : 0, command : 16, current : 0, autocontinue : 1, param1 : 0.0, param2 : 0.0, param3 : 0.0, param4 : 0.0, x :
- -35.3632583618, y : 149.164352417, z : 593.91998291}
- Velocity South and West
- Yaw 90 relative (to previous yaw heading)
- Velocity North and West
- Yaw 90 relative (to previous yaw heading)
-
- Setting LAND mode...
- Completed
- APIThread-0 exiting...
- LAND>
+#. You can run the example against a simulator (DroneKit-SITL) by specifying the Python script without any arguments.
+ The example will download SITL binaries if needed, start the simulator, and then connect to it:
+
+ .. code-block:: bash
+
+ python guided_set_speed_yaw.py
+
+ On the command prompt you should see (something like):
+
+ .. code:: bash
+
+ Starting copter simulator (SITL)
+ SITL already Downloaded.
+ Connecting to vehicle on: tcp:127.0.0.1:5760
+ >>> APM:Copter V3.3 (d6053245)
+ >>> Frame: QUAD
+ >>> Calibrating barometer
+ >>> Initialising APM...
+ >>> barometer calibration complete
+ >>> GROUND START
+ Basic pre-arm checks
+ Waiting for vehicle to initialise...
+ ...
+ Waiting for vehicle to initialise...
+ Arming motors
+ Waiting for arming...
+ ...
+ Waiting for arming...
+ >>> ARMING MOTORS
+ >>> GROUND START
+ Waiting for arming...
+ >>> Link timeout, no heartbeat in last 5 seconds
+ >>> ...link restored.
+ >>> Initialising APM...
+ Taking off!
+ Altitude: 0.0
+ Altitude: 0.28
+ ...
+ Altitude: 4.76
+ Reached target altitude
+ TRIANGLE path using standard Vehicle.simple_goto()
+ Set groundspeed to 5m/s.
+ Position North 80 West 50
+ Distance to target: 100.792763565
+ Distance to target: 99.912599325
+ ...
+ Distance to target: 1.21731863826
+ Distance to target: 0.846001925791
+ Reached target
+ Position North 0 East 100
+ Distance to target: 122.623210813
+ ...
+ Distance to target: 4.75876224557
+ Distance to target: 0.244650555031
+ Reached target
+ Position North -80 West 50
+ Distance to target: 100.792430814
+ Distance to target: 100.592652053
+ ...
+ Distance to target: 2.48849019535
+ Distance to target: 0.73822537077
+ Reached target
+ TRIANGLE path using standard SET_POSITION_TARGET_GLOBAL_INT message and with varying speed.
+ Position South 100 West 130
+ Set groundspeed to 5m/s.
+ Distance to target: 188.180927131
+ Distance to target: 186.578341133
+ ...
+ Distance to target: 9.87090024758
+ Distance to target: 1.4668164732
+ Reached target
+ Set groundspeed to 15m/s (max).
+ Position South 0 East 200
+ Distance to target: 318.826732298
+ Distance to target: 320.787965033
+ ...
+ Distance to target: 11.5626483964
+ Distance to target: 0.335164775811
+ Reached target
+ Set airspeed to 10m/s (max).
+ Position North 100 West 130
+ Distance to target: 188.182420209
+ Distance to target: 189.860730713
+ ...
+ Distance to target: 10.4263414971
+ Distance to target: 1.29857175712
+ Reached target
+ SQUARE path using SET_POSITION_TARGET_LOCAL_NED and position parameters
+ North 50m, East 0m, 10m altitude for 20 seconds
+ Point ROI at current location (home position)
+ North 50m, East 50m, 10m altitude
+ Point ROI at current location
+ North 0m, East 50m, 10m altitude
+ North 0m, East 0m, 10m altitude
+ SQUARE path using SET_POSITION_TARGET_LOCAL_NED and velocity parameters
+ Yaw 180 absolute (South)
+ Velocity South & up
+ Yaw 270 absolute (West)
+ Velocity West & down
+ Yaw 0 absolute (North)
+ Velocity North
+ Yaw 90 absolute (East)
+ Velocity East
+ DIAMOND path using SET_POSITION_TARGET_GLOBAL_INT and velocity parameters
+ Yaw 225 absolute
+ Velocity South, West and Up
+ Yaw 90 relative (to previous yaw heading)
+ Velocity North, West and Down
+ Set new home location to current location
+ Get new home location
+ Home Location: LocationGlobal:lat=-35.363243103,lon=149.164337158,alt=593.890014648
+ Yaw 90 relative (to previous yaw heading)
+ Velocity North and East
+ Yaw 90 relative (to previous yaw heading)
+ Velocity South and East
+ Setting LAND mode...
+ Close vehicle object
+ Completed
+
+ .. tip::
+
+ It is more interesting to watch the example run on a map than the console. The topic :ref:`viewing_uav_on_map`
+ explains how to set up *Mission Planner* to view a vehicle running on the simulator (SITL).
+
+#. You can run the example against a specific connection (simulated or otherwise) by passing the :ref:`connection string ` for your vehicle in the ``--connect`` parameter.
+
+ For example, to connect to SITL running on UDP port 14550 on your local computer:
+
+ .. code-block:: bash
+
+ python guided_set_speed_yaw.py --connect 127.0.0.1:14550
@@ -154,43 +185,56 @@ The example is :ref:`documented in source code `. Ad
The functions for controlling vehicle movement are:
-* :ref:`Vehicle.commands.goto() ` is the standard DroneKit position controller method. It is called from :ref:`goto ` to fly a triangular path.
-* :ref:`goto_position_target_global_int() ` is a position controller that uses the `SET_POSITION_TARGET_GLOBAL_INT `_ command.
-* :ref:`goto_position_target_local_ned() ` is a position controller that uses `SET_POSITION_TARGET_LOCAL_NED `_ command (taking values in NED frame, relative to the home position). This is used to fly a square path. The script is put to sleep for a certain time in order to allow the vehicle to reach the specified position.
-* :ref:`send_ned_velocity() ` is a velocity controller. It uses `SET_POSITION_TARGET_LOCAL_NED `_ to fly a square path using velocity vectors to define the speed in each direction.
-* :ref:`send_global_velocity() ` is a velocity controller. It uses `SET_POSITION_TARGET_GLOBAL_INT `_ to fly a diamond-shaped path. The behaviour is essentially the same as for ``send_ned_velocity()`` because the velocity components in both commands are in the NED frame.
-* :ref:`goto ` is a convenience function for specifying a target location in metres from the current location and reporting the result.
+* :ref:`Vehicle.simple_goto() ` is the standard
+ DroneKit position controller method. It is called from :ref:`goto ` to fly a triangular path.
+* :ref:`goto_position_target_global_int() `
+ is a position controller that uses the
+ `SET_POSITION_TARGET_GLOBAL_INT `_ command.
+* :ref:`goto_position_target_local_ned() `
+ is a position controller that uses `SET_POSITION_TARGET_LOCAL_NED `_
+ command (taking values in NED frame, relative to the home position). This is used to fly a square path.
+ The script is put to sleep for a certain time in order to allow the vehicle to reach the specified position.
+* :ref:`send_ned_velocity() ` is a velocity controller.
+ It uses `SET_POSITION_TARGET_LOCAL_NED `_
+ to fly a square path using velocity vectors to define the speed in each direction.
+* :ref:`send_global_velocity() ` is a velocity controller.
+ It uses `SET_POSITION_TARGET_GLOBAL_INT `_
+ to fly a diamond-shaped path. The behaviour is essentially the same as for ``send_ned_velocity()``
+ because the velocity components in both commands are in the NED frame.
+* :ref:`goto ` is a convenience function for specifying a target location
+ in metres from the current location and reporting the result.
The functions sending immediate commands are:
* :ref:`condition_yaw() `
* :ref:`set_roi(location) `
-* :ref:`set_speed(speed) `
-* :ref:`set_home() `
-The example uses a number functions to convert global locations co-ordinates (decimal degrees) into local coordinates relative to the vehicle (in metres). These are :ref:`described in the guide `.
+The example uses a number functions to convert global locations co-ordinates (decimal degrees) into local
+coordinates relative to the vehicle (in metres). These are :ref:`described in the guide `.
+
.. _example_guided_mode_goto_convenience:
goto() - convenience function
-----------------------------
-This is a convenience function for setting position targets in metres North and East of the current location. It reports the distance to the target every two seconds and completes when the target is reached.
+This is a convenience function for setting position targets in metres North and East of the current location.
+It reports the distance to the target every two seconds and completes when the target is reached.
-This takes a function argument of either :ref:`Vehicle.commands.goto() ` or :ref:`goto_position_target_global_int() `
+This takes a function argument of either :ref:`Vehicle.simple_goto() ` or
+:ref:`goto_position_target_global_int() `
.. code-block:: python
- def goto(dNorth, dEast, gotoFunction=vehicle.commands.goto):
- currentLocation=vehicle.location
+ def goto(dNorth, dEast, gotoFunction=vehicle.simple_goto):
+ currentLocation=vehicle.location.global_relative_frame
targetLocation=get_location_metres(currentLocation, dNorth, dEast)
targetDistance=get_distance_metres(currentLocation, targetLocation)
gotoFunction(targetLocation)
- vehicle.flush()
-
- while not api.exit and vehicle.mode.name=="GUIDED": #Stop action if we are no longer in guided mode.
- remainingDistance=get_distance_metres(vehicle.location, targetLocation)
+
+ while vehicle.mode.name=="GUIDED": #Stop action if we are no longer in guided mode.
+ remainingDistance=get_distance_metres(vehicle.location.global_frame, targetLocation)
print "Distance to target: ", remainingDistance
if remainingDistance<=targetDistance*0.01: #Just below target, in case of undershoot.
print "Reached target"
@@ -205,8 +249,9 @@ send_ned_velocity()
-------------------
The function ``send_ned_velocity()`` generates a ``SET_POSITION_TARGET_LOCAL_NED`` MAVLink message
-which is used to directly specify the speed components of the vehicle. The distance travelled is controlled
-by a delay before the next command is sent.
+which is used to directly specify the speed components of the vehicle.
+
+The message is resent at 1Hz for a set duration.
This is documented in :ref:`the guide here `.
@@ -216,65 +261,82 @@ This is documented in :ref:`the guide here
send_global_velocity()
----------------------
-The function ``send_global_velocity()`` generates a `SET_POSITION_TARGET_GLOBAL_INT `_ MAVLink message
-which is used to directly specify the speed components of the vehicle. The function behaviour is otherwise exactly the same as when using :ref:`SET_POSITION_TARGET_LOCAL_NED `
+The function ``send_global_velocity()`` generates a
+`SET_POSITION_TARGET_GLOBAL_INT `_
+MAVLink message which is used to directly specify the speed components of the vehicle in the NED
+frame.
+
+The function behaviour is otherwise exactly the same as when using
+:ref:`SET_POSITION_TARGET_LOCAL_NED `.
.. code-block:: python
- def send_global_velocity(velocity_x, velocity_y, velocity_z):
+ def send_global_velocity(velocity_x, velocity_y, velocity_z, duration):
"""
Move vehicle in direction based on specified velocity vectors.
"""
msg = vehicle.message_factory.set_position_target_global_int_encode(
0, # time_boot_ms (not used)
0, 0, # target system, target component
- mavutil.mavlink.MAV_FRAME_GLOBAL_RELATIVE_ALT_INT, # frame
+ mavutil.mavlink.MAV_FRAME_GLOBAL_RELATIVE_ALT_INT, # frame
0b0000111111000111, # type_mask (only speeds enabled)
0, # lat_int - X Position in WGS84 frame in 1e7 * meters
0, # lon_int - Y Position in WGS84 frame in 1e7 * meters
0, # alt - Altitude in meters in AMSL altitude(not WGS84 if absolute or relative)
- # altitude above terrain if GLOBAL_TERRAIN_ALT_INT
+ # altitude above terrain if GLOBAL_TERRAIN_ALT_INT
velocity_x, # X velocity in NED frame in m/s
- velocity_y, # Y velocity in NED frame in m/s
- velocity_z, # Z velocity in NED frame in m/s
+ velocity_y, # Y velocity in NED frame in m/s
+ velocity_z, # Z velocity in NED frame in m/s
0, 0, 0, # afx, afy, afz acceleration (not supported yet, ignored in GCS_Mavlink)
0, 0) # yaw, yaw_rate (not supported yet, ignored in GCS_Mavlink)
- # send command to vehicle
- vehicle.send_mavlink(msg)
- vehicle.flush()
+
+ # send command to vehicle on 1 Hz cycle
+ for x in range(0,duration):
+ vehicle.send_mavlink(msg)
+ time.sleep(1)
+
+.. note::
+
+ The message is re-sent every second for the specified duration. From Copter 3.3 the vehicle will stop
+ moving if a new message is not received in approximately 3 seconds. Prior to Copter 3.3 the message only
+ needs to be sent once, and the velocity remains active until the next movement message is received.
+ The above code works for both cases!
+
-
.. _example_guided_mode_goto_position_target_global_int:
goto_position_target_global_int()
---------------------------------
-The function ``goto_position_target_global_int()`` generates a `SET_POSITION_TARGET_GLOBAL_INT `_ MAVLink message
-which is used to directly specify the target location of the vehicle. When used with ``MAV_FRAME_GLOBAL_RELATIVE_ALT_INT`` as shown below, this method is effectively the same as :ref:`Vehicle.commands.goto `.
-
+The function ``goto_position_target_global_int()`` generates a
+`SET_POSITION_TARGET_GLOBAL_INT `_
+MAVLink message which is used to directly specify the target location of the vehicle.
+When used with ``MAV_FRAME_GLOBAL_RELATIVE_ALT_INT`` as shown below,
+this method is effectively the same as :ref:`Vehicle.simple_goto `.
+
.. code-block:: python
def goto_position_target_global_int(aLocation):
"""
Send SET_POSITION_TARGET_GLOBAL_INT command to request the vehicle fly to a specified location.
- """
+ """
msg = vehicle.message_factory.set_position_target_global_int_encode(
0, # time_boot_ms (not used)
0, 0, # target system, target component
- mavutil.mavlink.MAV_FRAME_GLOBAL_RELATIVE_ALT_INT, # frame
+ mavutil.mavlink.MAV_FRAME_GLOBAL_RELATIVE_ALT_INT, # frame
0b0000111111111000, # type_mask (only speeds enabled)
aLocation.lat*1e7, # lat_int - X Position in WGS84 frame in 1e7 * meters
aLocation.lon*1e7, # lon_int - Y Position in WGS84 frame in 1e7 * meters
aLocation.alt, # alt - Altitude in meters in AMSL altitude, not WGS84 if absolute or relative, above terrain if GLOBAL_TERRAIN_ALT_INT
0, # X velocity in NED frame in m/s
- 0, # Y velocity in NED frame in m/s
- 0, # Z velocity in NED frame in m/s
+ 0, # Y velocity in NED frame in m/s
+ 0, # Z velocity in NED frame in m/s
0, 0, 0, # afx, afy, afz acceleration (not supported yet, ignored in GCS_Mavlink)
0, 0) # yaw, yaw_rate (not supported yet, ignored in GCS_Mavlink)
+
# send command to vehicle
vehicle.send_mavlink(msg)
- vehicle.flush()
In the example code this function is called from the :ref:`goto() ` convenience function.
@@ -285,8 +347,10 @@ In the example code this function is called from the :ref:`goto() `_ MAVLink message
-which is used to directly specify the target location in the North, East, Down frame. The ``type_mask`` enables the position parameters (the last three bits of of the mask are zero).
+The function ``goto_position_target_local_ned()`` generates a
+`SET_POSITION_TARGET_LOCAL_NED `_
+MAVLink message which is used to directly specify the target location in the North, East, Down frame.
+The ``type_mask`` enables the position parameters (the last three bits of of the mask are zero).
.. warning::
@@ -295,47 +359,42 @@ which is used to directly specify the target location in the North, East, Down f
.. note::
- The `documentation `_ lists a number of possible frames of reference. At time of writing experimentation indicates that the actual frame use is always relative to the home location (not the vehicle, as indicated by MAV_FRAME_BODY_NED).
-
+ The `MAVLink protocol documentation `_
+ lists a number of possible frames of reference. Up until Copter 3.2.1 the actual frame used is always
+ relative to the home location (as indicated by MAV_FRAME_LOCAL_NED). Starting from Copter 3.3
+ you can specify `other frames `_,
+ for example to move the vehicle relative to its current position.
-.. code-block:: python
+.. code-block:: python
def goto_position_target_local_ned(north, east, down):
- """
+ """
Send SET_POSITION_TARGET_LOCAL_NED command to request the vehicle fly to a specified
location in the North, East, Down frame.
- """
+ """
msg = vehicle.message_factory.set_position_target_local_ned_encode(
0, # time_boot_ms (not used)
0, 0, # target system, target component
- mavutil.mavlink.MAV_FRAME_BODY_NED, # frame
+ mavutil.mavlink.MAV_FRAME_LOCAL_NED, # frame
0b0000111111111000, # type_mask (only positions enabled)
- north, east, down, # x, y, z positions (or North, East, Down in the MAV_FRAME_BODY_NED frame
+ north, east, down,
0, 0, 0, # x, y, z velocity in m/s (not used)
0, 0, 0, # x, y, z acceleration (not supported yet, ignored in GCS_Mavlink)
0, 0) # yaw, yaw_rate (not supported yet, ignored in GCS_Mavlink)
# send command to vehicle
vehicle.send_mavlink(msg)
- vehicle.flush()
-
-At time of writing, acceleration and yaw bits are ignored.
-Testbed settings
-================
+At time of writing, acceleration and yaw bits are ignored.
-This demo has been tested on Windows against SITL running both natively and in a virtual machine (as described in :ref:`get-started`).
-DroneKit environment (from PIP):
-
-* droneapi: 1.2.0
-* pymavlink: 1.1.57
-* MAVProxy: 1.4.23
-* protobuf: 2.6.1
+Testbed settings
+================
-ArduPilot version:
+This example has been tested on Windows against SITL running both natively and in a virtual machine (as described in :ref:`installing_dronekit`).
-* `3.3.0beta2 `_.
+* DroneKit version: 2.0.2
+* ArduPilot version: 3.3
@@ -344,7 +403,8 @@ ArduPilot version:
Source code
===========
-The full source code at documentation build-time is listed below (`current version on github `_):
+The full source code at documentation build-time is listed below
+(`current version on Github `_):
.. literalinclude:: ../../examples/guided_set_speed_yaw/guided_set_speed_yaw.py
:language: python
diff --git a/docs/examples/index.rst b/docs/examples/index.rst
index 65b983659..d2d815158 100644
--- a/docs/examples/index.rst
+++ b/docs/examples/index.rst
@@ -18,9 +18,13 @@ during missions and outside missions using custom commands.
Guided Movement and Commands
Basic Mission
Mission Import/Export
+ Create Attribute in App
Follow Me (Linux only)
Drone Delivery
Flight Replay
+ Channel Overrides
+ Performance Test
+
diff --git a/docs/examples/mission_basic.rst b/docs/examples/mission_basic.rst
index 9e41a0faf..a37afc571 100644
--- a/docs/examples/mission_basic.rst
+++ b/docs/examples/mission_basic.rst
@@ -12,92 +12,107 @@ command.
The guide topic :ref:`auto_mode_vehicle_control` provides more detailed explanation of how the API
should be used.
+.. figure:: mission_basic_example_copter_path.png
+ :width: 50 %
+ :alt: Basic Mission Path
+
+ Basic Mission Example: Flight path
+
Running the example
===================
-The vehicle and DroneKit should be set up as described in :ref:`get-started`.
-
-If you're using a simulated vehicle remember to :ref:`disable arming checks ` so
-that the example can run.
-
-Once MAVProxy is running and the API is loaded, you can start the example by typing: ``api start mission_basic.py``.
-
-.. note::
-
- The command above assumes you started the *MAVProxy* prompt in a directory containing the example script. If not,
- you will have to specify the full path to the script (something like):
- ``api start /home/user/git/dronekit-python/examples/mission_basic/mission_basic.py``.
-
-
-On the *MAVProxy* console you should see (something like):
-
-.. code:: bash
-
- MAV> api start mission_basic.py
- STABILIZE> Clear the current mission
- Got MAVLink msg: MISSION_ACK {target_system : 255, target_component : 0, type : 0}
- Requesting 0 waypoints t=Wed Jul 29 21:27:58 2015 now=Wed Jul 29 21:27:58 2015
- Create a new mission
- Got MAVLink msg: MISSION_ACK {target_system : 255, target_component : 0, type : 0}
- Sent waypoint 0 : MISSION_ITEM {target_system : 1, target_component : 0, seq : 0, frame : 0, command : 16, current : 0, autocontinue : 1, param1 : 0.0, param2 : 0.0, param3 : 0.0, param4 : 0.0, x : -35.3632621765, y : 149.165237427, z : 584.0}
- Sent waypoint 1 : MISSION_ITEM {target_system : 1, target_component : 0, seq : 1, frame : 3, command : 22, current : 0, autocontinue : 0, param1 : 0, param2 : 0, param3 : 0, param4 : 0, x : 0, y : 0, z : 10}
- Sent waypoint 2 : MISSION_ITEM {target_system : 1, target_component : 0, seq : 2, frame : 3, command : 16, current : 0, autocontinue : 0, param1 : 0, param2 : 0, param3 : 0, param4 : 0, x : -35.3628118424, y : 149.164679124, z : 11}
- Sent waypoint 3 : MISSION_ITEM {target_system : 1, target_component : 0, seq : 3, frame : 3, command : 16, current : 0, autocontinue : 0, param1 : 0, param2 : 0, param3 : 0, param4 : 0, x : -35.3628118424, y : 149.165780676, z : 12}
- Sent waypoint 4 : MISSION_ITEM {target_system : 1, target_component : 0, seq : 4, frame : 3, command : 16, current : 0, autocontinue : 0, param1 : 0, param2 : 0, param3 : 0, param4 : 0, x : -35.3637101576, y : 149.165780676, z : 13}
- Sent waypoint 5 : MISSION_ITEM {target_system : 1, target_component : 0, seq : 5, frame : 3, command : 16, current : 0, autocontinue : 0, param1 : 0, param2 : 0, param3 : 0, param4 : 0, x : -35.3637101576, y : 149.164679124, z : 14}
- Sent all 6 waypoints
- Got MAVLink msg: MISSION_ACK {target_system : 255, target_component : 0, type : 0}
- APM: flight plan received
- Basic pre-arm checks
- Arming motors
- Waiting for arming...
- Got MAVLink msg: COMMAND_ACK {command : 11, result : 0}
- Waiting for arming...
- APM: ARMING MOTORS
- APM: GROUND START
- Waiting for arming...
- GUIDED> Mode GUIDED
- APM: Initialising APM...
- Got MAVLink msg: COMMAND_ACK {command : 400, result : 0}
- Waiting for arming...
- ARMED
- Taking off!
- Altitude: 0.0
- Got MAVLink msg: COMMAND_ACK {command : 22, result : 0}
- GPS lock at 0 meters
- Altitude: 0.10000000149
- ...
- Altitude: 8.84000015259
- Altitude: 9.60999965668
- Reached target altitude
- Starting mission
- Got MAVLink msg: COMMAND_ACK {command : 11, result : 0}
- waypoint 1
- waypoint 2
- AUTO> Mode AUTO
- Distance to waypoint (2): 79.3138466142
- Distance to waypoint (2): 79.1869592549
- Distance to waypoint (2): 77.8436803794
- ...
- Distance to waypoint (2): 20.7677087176
- Distance to waypoint (2): 15.4592692026
- APM: Reached Command #2
- waypoint 3
- Distance to waypoint (3): 115.328425048
- Skipping to Waypoint 4 when reach waypoint 3
- waypoint 4
- Distance to waypoint (4): 152.376018911
- Distance to waypoint (4): 154.882233097
- ...
- Distance to waypoint (4): 20.4052797291
- Distance to waypoint (4): 15.0592597507
- APM: Reached Command #4
- waypoint 5
- Distance to waypoint (5): 114.450267446
- Exit 'standard' mission when start heading to final waypoint (5)
- Return to launch
- APIThread-0 exiting...
+The example can be run as described in :doc:`running_examples` (which in turn assumes that the vehicle
+and DroneKit have been set up as described in :ref:`installing_dronekit`).
+
+In summary, after cloning the repository:
+
+#. Navigate to the example folder as shown:
+
+ .. code-block:: bash
+
+ cd dronekit-python/examples/mission_basic/
+
+#. You can run the example against a simulator (DroneKit-SITL) by specifying the Python script without any arguments.
+ The example will download SITL binaries (if needed), start the simulator, and then connect to it:
+
+ .. code-block:: bash
+
+ python mission_basic.py
+
+ On the command prompt you should see (something like):
+
+ .. code:: bash
+
+ Starting copter simulator (SITL)
+ SITL already Downloaded.
+ Connecting to vehicle on: tcp:127.0.0.1:5760
+ >>> APM:Copter V3.3 (d6053245)
+ >>> Frame: QUAD
+ >>> Calibrating barometer
+ >>> Initialising APM...
+ >>> barometer calibration complete
+ >>> GROUND START
+ >>> Mission Planner 1.3.35
+ Create a new mission (for current location)
+ Clear any existing commands
+ Define/add new commands.
+ Upload new commands to vehicle
+ Basic pre-arm checks
+ Waiting for vehicle to initialise...
+ >>> flight plan received
+ Waiting for vehicle to initialise...
+ ...
+ Waiting for vehicle to initialise...
+ Arming motors
+ Waiting for arming...
+ ...
+ Waiting for arming...
+ >>> ARMING MOTORS
+ >>> GROUND START
+ Waiting for arming...
+ >>> Initialising APM...
+ Taking off!
+ Altitude: 0.0
+ Altitude: 0.11
+ ...
+ Altitude: 8.9
+ Altitude: 9.52
+ Reached target altitude
+ Starting mission
+ Distance to waypoint (0): None
+ Distance to waypoint (1): 78.8000191616
+ Distance to waypoint (1): 78.3723704927
+ ...
+ Distance to waypoint (1): 20.7131390269
+ Distance to waypoint (1): 15.4196151863
+ >>> Reached Command #1
+ Distance to waypoint (2): 115.043560356
+ Distance to waypoint (2): 117.463458185
+ ...
+ Distance to waypoint (2): 25.7122243168
+ Distance to waypoint (2): 16.8624794106
+ >>> Reached Command #2
+ Distance to waypoint (3): 100.45231832
+ Skipping to Waypoint 5 when reach waypoint 3
+ Distance to waypoint (5): 154.645144788
+ Exit 'standard' mission when start heading to final waypoint (5)
+ Return to launch
+ Close vehicle object
+
+
+ .. tip::
+
+ It is more interesting to watch the example run on a map than the console. The topic :ref:`viewing_uav_on_map`
+ explains how to set up *Mission Planner* to view a vehicle running on the simulator (SITL).
+
+#. You can run the example against a specific connection (simulated or otherwise) by passing the :ref:`connection string