-
Notifications
You must be signed in to change notification settings - Fork 92
Andropilot Developers Guide
This document is intended to be a collaborative set of instructions/design decisions for developers interested in extending or reusing the Andropilot code. I'll get things started by creating some initial notes - if you have questions that are not addressed by this document either:
- Poke around a bit, find the answer and update the document
- Add you question inline and then send Kevin a note
This software is written in Scala. If you have never written Scala code - don't be scared! When getting started you can think of it as Java with a much cleaner syntax. After you've looked at the code a bit and made some simple changes you can begin to use more functional programming features. If you've never written Scala code beofre, I recommend reading this short tutorial.
Because Scala 'mixes and matches' with Java. If you have some bit of Java code that you want to reuse, there is no need to port it. Just add it to the source tree and use it just like any other Scala/Java class.
The android developer site is very good. If you've never developed Android code before, I recommend going through one of their small 'Hello World' examples first. To make sure your IDE is working etc... before trying to build/extend this project.
Because a running GCS has numerous 'moving parts' (UDP senders, HTTP servers, USB interfaces, simulation threads etc...) the application makes extensive use of 'actors'. Actors are a general computer science concept of self contained widgets that receive messages and perform actions based on those messages. Typically in a JVM this is implemented behind the scenes as execution contexts that reuse a small pool of threads - with each context having a message queue of requests.
The actor system we are using is modeled after Akka. However due to some Android limitations we could not depend on the large & complex Akka environment. Our 'baby' actor environment is provided through a few key classes in com.geeksville.akka:
- InstrumentedActor - You should extend this trait with any object you want to make into an actor. You will also need to provide a 'onReceive' method to handle any messages your actor understands (grep the code to see numerous examples)
- MockAkka - The singleton top level actor controller. Usually to create an actor you will call MockAkka.actorOf(new MyActor(args), "debuggablenameformyactor")
- Scheduler - Used to send periodic or single time based messages to actors (it is bad to sleep in an actor, so if you want to do something periodically this is the way to go)
- EventStream - Provides a publish/subscribe model for distributing different types of data. Useful for GPS locations, received Mavlink messages etc...
Andropilot is actually part of a larger framework for a JVM based ground controller. The top level project actually builds a number of different sub targets:
- Andropilot - the top level Android application - allowed to use Android. Please try to put only android specific code in this project. If you are adding a feature useful to other platforms, please put it into common instead.
- Posixpilot - A command line 'desktop' GCS, currently it is mostly used as a test harness to run code that will eventually be in Andropilot. However, it wouldn't be too hard to add a basic GUI to this application or to run it as a headless daemon. This project is allowed to assume it is running on a Posixish architecture.
- Common - Common mavlink and flight code used by any target. Please use only standard java or scala code and no platform specific native libraries.
- Scandroid - A library of utility classes to make Scala development on Android more idiomatic. Until you get into things deeper you probably just want to use this library 'as-is'.
There is a fair amount of internal documentation. Eventually someone will add a buildrule to run scaladoc to generate nice HTML documentation, but for now this will have to suffice...
- com.geeksville.flight.lead.FlightLead - The current slightly crufty 'main' app of Posixpilot.
- com.geeksville.mavlink.MavlinkFtdi - The code that talks to FTDI based devices on libusb based machines
- com.geeksville.flight.VehicleModel - This class attempts to maintain a complete model of some Mavlink vehicle. In andropilot & posixpilot we create one instance of this class and use it for most of the interesting behavior in the app.
This section gives additional guidance on how to build and debug this software (see README.md in the project for setup instructions).
If you are new to scala having an IDE that does completion is really helpful. So I'd recommend waiting on emacs etc... until you are reasonably comfortable.
The compile-link-debug cycle for Android is a little slow. So I try to do as much debugging and development in Posixpilot as possible. The usual workflow is to add a new feature in the common tree, then build and test it in posixpilot. This works well because the Eclipse IDE (with the Scala-IDE plugin) gives a very nice debugger environment.
Currently I do all my executable android builds in SBT alone (using eclipse only to debug syntax errors and get code completion as I edit). Use 'project andropilot' in sbt to select the android project.
If you are using the USB link on your tablet for the 3dr radio, you'll probably want to install an 'adb wifi' app from the market then use 'android:start-emulator' to install onto the device.
If you are directly connecting your tablet to the desktop via USB you should run 'android:start-device'.
One note on performance: SSDs (or ramdisk) makes a huge difference in the proguard portion of the build. This step is run implicitly when you build an android package. With a SSD this step takes about two seconds, without it is closer to a minute.
These are some notes from the original author on how he'd recommend adding particular new features. If you'd like to add a new feature but have no idea on how to get started, send Kevin a note and he'll add a sketch which might be useful (or not ;-)).
To add a HTTP server serving up vehicle data and static content I'd recommend the following.
There are a lot to choose from, but to run well on Android or embedded devices you should make or reuse something tiny. It just needs to accept connections on port 80 and serve up either static content or something generated by some sort of callback.
If you do decide to implement something from scratch, you can just associate some sort of RESTHandler class with a table of base URLs (with methods like handleGET, handlePOST, etc...). Then make a subclass called FilesystemHandler to read files from a directory tree and return the appropriate response for handleGET.
You'd also make a MavlinkServer subclass of RESTHandler to serve up all your mavlink based data.
You'll want to make your MavlinkServer extend InstrumentedActor and use the global VehicleModel instance to do the 'heavy lifting' of your app. (If I have time in the next few days I could add a little stub demonstrating this to common?). The code of this little stub will look an awful lot like AndroServiceClient.MyVehicleListener. In your onReceive method you can listen for messages like MsgModeChanged etc...
Alternatively, if your API is entirely 'polled' you might be able skip listening to VehicleModel messages. You could instead just use VehicleModel. It has a bunch of data structures that are meant to be read by any client code to see the current state of the vehicle, i.e. waypoints, location, status etc...
To change vehicle state you send messages to the vehicle monitor (search for DoGotoGuided to see an example).