Idiot’s Guide to DroneKit Android: Reskinning Tower for Fun and Profit

I had so much fun playing around with DroneKit Python over the last month or so, that I thought I would try my hand at DroneKit Android. Specifically, I was interested in building a customized version of Tower.

The DIY Drones community is probably well aware of Tower’s expansive capabilities as a mobile ground control station, specifically with regards the built in autonomous mapping and scanning modes. Some tens of thousands of users are currently leveraging Tower to control their Pixhawk-powered drones, many of these for small business or large enterprise. However, these commercial users are stuck with a multitool when all they need is a knife. Tower has so many features and functions that it can be quite overwhelming for first time users to create even simple survey. Furthermore, it is fairly easy for even advanced users to make simple mistakes like accidentally pushing the drone into ACRO using the drop down menu up top.

For my first DroneKit Android project, I set out to create an Agribotix branded GCS for Solo AGCO Edition. This isn’t any kind of official AGCO product, but just a fun project I thought would help me learn about DK-Android.

Key features I wanted to explore in DroneKit Android were how to:

  • Change styling, colors, and logos
  • Remove unnecessary flight modes
  • Fix camera settings
  • Remove hobby oriented settings
  • Force a UDP connection

While this project is obviously mostly an exercise in deletion, it served as a great introduction to what functions are available in DroneKit Android, how code is split between Tower and 3DR Services, and how a basic Android app is structured. Prior to this undertaking, I had never touched a line of Java or Kotlin or worked with an Android app, so I will assume the reader hails from a similar background.

I hope this guide inspires/enables some of you to create your own custom versions of Tower! My example apk is available here and my my source code is here.

Step 1: Get ready

If you aren’t already familiar with SITL, DroneKit, git, and the various developer tools I’ll mention here, head over to my Idiot’s Guide to DK-Python: A Journey to WHOZ CHILLIN and give it a quick read. You will be using many of the tools and concepts discussed previously to debug and test your custom version of Tower.

Note: DK-Python is fairly simple and well documented. DK-Android is not. If you are interested in an easier journey to a custom GCS, it may make sense to work in Python.

Next, download Android Studio. Google has built an incredible Integrated Development Environment (IDE) for building Android apps and you will be using it to do all of your work on Tower.

The Tower source code comes next. Because Tower is open source, all of its source code can be downloaded from the DroidPlanner GitHub account. Run

git clone

from the terminal in the directory where you’d like to work on your version of Tower. Git will automatically download all of the files you will need.

Next open Tower in Android Studio. Alternatively you can use the VCS ⇒ Checkout from Version Control ⇒ GitHub flow to automatically import Tower into Android Studio.

Android Studio will then attempt to build the Gradle, which must succeed before you can do anything. If you just installed Android Studio, it will fail because you will need to install both the latest Android SDK and BuildTools. Wait for the Gradle build to fail and follow Android Studio’s instructions to get both of these items installed.

Finally, it’s possible to test your app on either a simulated device or a real one. On my computer, the simulated device runs very slowly, so I prefer to debug using a real tablet. To do this, you must plug your tablet into your computer’s USB and set it to developer mode. Briefly, find the Android Build Number section in settings and tap it seven times. After the seventh tap, you will see Developer Mode enabled and you will be able to run your code on the connected tablet.

Step 2: Build Tower

Now that you’re ready to roll, try building Tower yourself. First, click Run ‘Android’ under the Run menu. Assuming you’ve followed all the instructions in Step 1 successfully, Android Studio should compile the Tower source code and spin up a copy of Tower on your connected device. Cool! Now you never need to download compiled .apks of open source projects. You can just compile them yourself.

Go ahead and start up an instance of SITL and connect your compiled version of Tower, which should be called Tower debug on your tablet. You should be able to control your virtual copter just like the you can using the production version of Tower available in the app store.

Running your program is great for quickly testing your changes, but you will need to compile your own .apk for distribution. Try clicking Build APK under the Build menu, building your own version of Tower, and installing it on an Android device. Easy!

Step 3: Android app basics

I am definitely not the most qualified person to write this section and likely will have some errors in my assumptions, but I think my basic understanding is generally sound. If any of the Android wizards out here have improvements or corrections, I would love to roll them in. However, having spent some time bumbling through Tower’s structure without any background in Android applications, I hope I can provide a more accessible view into how to start digging in.

When you open Tower in Android Studio, you’ll notice two high level menus: Android and Gradle Scripts. Android is where most of the meat lives, but some of the files found within Gradle Scripts are responsible for very high level functions like the app name.

2016-01-18 06.40.01 pm

Within Android, you’ll see manifests, java, and res. manifests dictates what types of devices are compatible with our app. When you open the xml file within manifests, you’ll notice most of the file is concerned with various hardware configurations. For this project, we don’t care about hardware, but you might imagine that for your custom version of Tower, you might want to restrict users to connecting over Bluetooth and thus would like to throw up an error if a user tried to run your app on a tablet that did not have Bluetooth capability.

The java folder contains, not surprisingly, all of the java files that provide the structure of the app. However, in an Android application, the java files in many cases only serve as a general framework into which content is populated from the xml files found in the res folder. This will become abundantly clear as we walk through the tutorial, but Tower is a delicate dance between the java files in the java folder and the xml files in the res folder.

Take a minute to scan through the java and res folders with Tower open by your side and see what you recognize. I certainly was pretty amazed by how much I was able to understand by just generally scanning the code while poking through Tower. If there is a specific feature you are interested in, try Find in Path, Shift+Command+F on a Mac, and you generally can see where in the code base a specific feature resides.

Step 4: Let’s try some easy stuff

So you think Tower is a boring name? Me, too. Within Android Studio, open the Gradle Scripts/build.gradle (Module Android) file. Head down to lines 140, 148, and 154. You’ll notice that you can replace Tower with a name of your choosing. I used Agribotix for my example, but let your creative juices flow.


Don’t like the Tower logo? Replace the ic_launcher.png logos found in res/drawable/ic_launcher with your own. The different files are for different resolution icons that are displayed on different size devices. If you want to be really fancy, you can use an online tool like this one to automatically generate all of these files from a vector image.

2016-01-18 06.41.27 pm
Want to establish some branding within the app? The sidebar seems like a good place to start. Head to res/layout/nav_header_main.xml. You’ll see something like the image below. The screen is split between Android Studio’s best guess as to how nav_header_main.xml will appear on an device and the actual .xml file. If you CMD + click on some of the elements, you can see how they are linked to the rest of the code. Try it and see. After playing around for a few minutes, it should be fairly obvious what’s going on inside this .xml file.

2016-01-18 06.43.02 pm
Now, let’s get to your custom branding. You can either do things the hard way or the easy way. The hard way is scan through the text and identify which lines of code likely correspond to which design element. Here, is is fairly obvious that android:text= specifies what the text in the header will say, but that’s not always to case. However, Android Studio is pretty amazing. You can simply click on the item of interest, say the text, and Android Studio will highlight what code is responsible for that element. Go ahead and change the background color, logo, and text to match your branding.

2016-01-18 06.43.59 pm

Great, now you should understand the basics of how Tower, and Android apps in general for that matter, is structured from a design perspective. I just identified a few specific touch points here, but with some pretty straightforward digging, you should now be able to completely own the style and design of Tower.

After you’ve tinkered to your heart’s content, go ahead and Run ‘Android’ or build an APK and see how it looks.

Step 5: Let’s dive a little deeper

Now that you own the design, let’s start to own the functionality. One of my biggest issues with Tower, especially when showing it off to a commercial user interested in mapping, is the 15 flight modes available from the telemetry bar. It is far too easy for a user interested in autonomous flight to accidentally kick the copter into ACRO mode and cause a crash. Let’s fix that.

2016-01-18 06.45.50 pm

This is the first time where we will be working at the intersection of Tower and 3DR Services. You’ll notice that if you navigate res/layout/fragment_action_bar_telem.xml, you’ll find the design responsible for this feature. However, what you will not find is the ability to add or remove menu items using a simple .xml file. Rather, you will see a reference to android:id=”@+id/bar_flight_mode” when you click on the flight mode piece of the telemetry bar. If you search your app for that string, you will find a java file called

If you stare at this file for long enough, you will realize that the menu of options in the telemetry drop down is populated by FlightModeAdapter.

2016-01-18 06.47.26 pm

If you CMD + click on FlightModeAdapter, Android Studio will take you to a file called FlightModeAdapter.kt, which is written in a language called Kotlin, which is similar to Java. It may be worthwhile to stop at this point and download the Kotlin plugin for Android Studio to make your code look a little more beautiful. Inside FlightModeAdapter.kt, you will see that there is another layer to the onion.
2016-01-18 06.46.33 pmTower is pulling the flightModes from a variable called VehicleMode. CMD + click on VehicleMode and you’ll notice that Android Studio takes you to the locked This file is locked because it is not actually part of Tower, but rather 3DR Services, which provides many of the functions called by Tower and DroneKit-Android apps. While you certainly could modify that file and compile a new version of 3DR Services, it is easier to step out a layer and try to address all of our changes from the Tower level.

To do this, reopen FlightModeAdapter.kt and put on your Java hat. flightModes is simply an array populated by 3DR Service’s VehicleMode variable. To remove elements from the array, we use the Java remove command. For example, to remove ACRO from your version of Tower, include  


underneath flightModes. For my app, I removed every flight mode aside from RTL, Auto, and Guided.

2016-01-18 06.48.13 pmGreat. Now build your app and make sure everything still works.

2016-01-18 06.48.56 pm

Step 6: Like Solo? Let’s make Tower connect automatically over WiFi (UDP).

Solo AGCO Edition users obviously are only interested in flying Solo. Bluetooth, USB, and TCP connections are painful for the uninitiated to understand and totally unnecessary. To force a UDP connection, open java/ You can see that this file handles all kinds of connectivity-related functionality.

Around line 300, you’ll see

final int connectionType = dpPrefs.getConnectionParameterType();

If you look at the code carefully, you’ll see that we can cheat and short circuit the whole connection type selection process by just hard coding in a UDP connection. You’ll notice that the connectionType variable in an integer. If you do a little CMD + click digging, you’ll learn that that integer is 0 for USB, 1 for UDP, 2 for TCP, and 3 for Bluetooth. To force a UDP connection, we can just go behind all of the logic and menus and replace





2016-01-18 06.50.28 pm

This cheat will not remove any of the UI, but no matter what connection type you specific, Tower will look for a vehicle over UDP. Which brings us to…

Step 7: Remove unnecessary menus

Now that we’ve hardcoded a UDP connection, we should remove all of the connectivity menus. And, while we’re at it, let’s get rid of everything else we find distracting. Personally, I don’t like the Flight History or Checklist top level menus and think the user is exposed to way too many settings.

Go ahead and open up res/menu/navigation_drawer_items.xml to clean up the navigation drawer and res/xml/preferences.xml to get rid of the preferences you don’t like.

You may find that with some of the xml items that you remove, you may have to find the associated Java reference and comment it out as well. This should be fairly straightforward to work through, but feel free to look to the Agribotix app for specific examples.

In this general vein, I also removed Dronie, Follow, and Land from the top level menus and everything aside from Spline Survey from the Editor screen, because the Solo AGCO Edition owners are essentially only interested in building maps. You can see how I did this by looking at what I commented out in java/ and /res/layout/fragment_editor_tools.xml

Step 8: Simplify the Editor screen for the optimal survey

Solo AGCO Edition customers use the editor screen to do only one thing: spline survey. They also user only one camera, GoPro, and should never have to play with sidelap or overlap. The mapping workflow can be dramatically simplified by hardcoding all of these values in, which is possible in java/

I started to get a little sloppy here (you’ll notice that I didn’t change the camera UI, although the camera is hardcoded to GoPro in the backend), but I hardcoded the camera to Hero 4 Black, the sidelap to 70%, and the overlap to 85%.

2016-01-18 06.51.55 pm

Step 9: Profit?

Whew! That was a lot of work, but in the end we created a custom version of Tower that is built to address specific user needs and reinforce a platform partner’s branding. Tower is a very extensible base for a huge variety of custom mobile GCSs, so I hope this guide makes modification a little more accessible for all of the 3DR platform partners, like Agribotix, out there doing great things with Pixhawk.

The drones of CES in pictures

When I stepped into the Drone Zone at CES, I was greeted by not three (DJI, Yuneec, and 3DR), as seen at AUVSI and NAB, but probably more than a dozen very high quality, professional looking drone booths. AEE, Hubsan, and other toy companies have moved seriously upmarket and new entrants like Xiro and Ehang had seemingly very high quality products on display. Without further ado, here are some of my favorites.

IMG_0224For those of you who didn’t see it in the mainstream news cycle, the Ehang flying car stole the show. Yes, the company that Kickstarted its way to the fairly pathetic Ghost had the most impressive presence in the drone area.


Phantom, Bepop, and Inspire clones for days. There were literally hundreds of these on display. It’s not clear if the drone industry has converged on several basic designs because they are best, similar to the auto industry, or, more likely, fast following is winning over true innovation.IMG_0242The Yuneec H920 integrated with a Pansonic GH4. This is the first time I’ve seen one in real life and it seems far too large to be practical. I would far rather lug around Inspire, assuming the X5 RAW matches the GH4 quality, for professional aerial video capture.


The new collision avoiding Yuneec Typhoon H. This hex feels much, much higher quality than the Typhoon 4K (my Typhoon 4K fell out of the sky, likely due to an ESU failure within 5 minutes of pulling it out of the box), but still shares the same chintzy gimbal. Yuneec has made some huge strides with this product.


Black Inspire 1 Pro with X5R looks mean.

IMG_0247Gimbaled FLIR Vue for Inspire enables easy aerial thermal imaging.
IMG_02536 months after release, Xiro has already revved the Xplorer. Xplorer 2 appears to have a spinning LIDAR collision avoidance system. The fit and finish is great and they upgraded to an integrated 4K camera. I have an original Xplorer and was generally impressed with the performance until the cheap battery latch failed on my third flight and I was permanently grounded due to a $0.10 part failing.

Idiot’s Guide to DroneKit-Python: A Journey to WHOZ CHILLIN

Ever since I moved to Berkeley and started at 3DR, I dreamed of developing an app that ran on-board Solo that would let me see who was chillin’ on my roof deck 2,200 feet from the 3DR world HQ in Berkeley. I dreamed of, as my day was wrapping up, sending Solo to snap a picture of my roof deck, post it online, and tell me if I should head home to grill on my roof with my neighbors. After the wonderful week-long hackathon we had at 3DR in December, I finally realized that dream.

And, it wasn’t that hard. While the documentation still leaves a little bit to be desired, DroneKit Python is amazingly accessible. I have a modest background in academic computing, but little to no experience with modern software engineering. After a few days of effort, which could be shortened to a few hours for those of you reading this guide, I was able to programmatically coerce Solo into some really rich behaviors driven by the on-board computer. I have enormous confidence that anyone in the DIY Drones community, after reading this guide, could do the same.

First, some basics. Solo is unique with its programmable Linux computer on board. While other platforms, including Solo, ship with a mobile SDK, mobile development is significantly more challenging (stay tuned for my guide to 3DR Services/DroneKit Android…). The computer on board Solo ships with Python, a very simple programming language, preinstalled. This makes it very easy for rote novices like me to write software that controls Solo.

OK, how do you actually do this? Follow the steps below and frequently refer to both and The former is the Solo development guide. It describes specifically how to get your code running on Solo and how you, as a new Solo developer, can use all of the tools 3DR has built to make your job easy. The latter is the DroneKit Python documentation. It more generally describes what you can do with DroneKit Python and how to get DroneKit running on non-Solo vehicles.

Note: This guide is written for the Mac user. I’m sure there are equivalent Windows commands for many of these steps, but it will be up to the reader to track them down.

Note: WordPress likes to shorten two hyphens “-“”-” to a dash “–“. This will obviously cause errors when copying and pasting from this site, so keep this is mind. Any time you see a dash, it likely should be replaced by two hyphens in your terminal or in your code.

Step 1: Install Python

If you don’t have Python installed on your computer, it likely makes the most sense to install using Homebrew, a package manager for OS X that makes sure all of your packages are linked properly. Installation is straightforward and full instructions can be found at, but essentially you just need to run

ruby -e “$(curl -fsSL”

from any directory in your terminal.

After Homebrew is installed, run

brew install python

from any directory in your terminal. Full instructions are at if you have any trouble.

Note: Brew installing this version of Python is critical to your success with DroneKit. I spent a couple hours removing multiple old Python installs and relinking tools on my dad’s computer while installing DroneKit. I would highly recommend removing any old install of Python and restarting with the Homebrew tap.

Step 2: Install DroneKit Python and SITL

DroneKit Python is the actual software that will interpret your easy-to-write commands and translate them into ones and zeros that are readable by Solo. SITL, or software in the loop, is a simulated vehicle that runs inside your computer. SITL represents the only safe way to test your code (software bugs become a lot more problematic when you’re programming the behavior of a real, physical object). I’m sure everyone on DIY Drones has heard of SITL at one time or another, but until very recently (today!) it was fairly difficult to set up.

Note: Please ignore other documentation floating around the internet regarding installing SITL on a virtual machine and follow these instructions.

Both DroneKit Python and SITL are installed using the pip command. Pip is an install command built into Python, which you just installed using Homebrew, that brings amazing software to your from the command line.

From any directory, run

pip install dronekit

to install DroneKit. Remember that, because pip is a Python command, there is no reason to specific as to which DroneKit we are installing.

Next, also from any directory, run

pip install dronekit-sitl

to install SITL.

Step 3: Run SITL

This step is fairly opaque in most of the documentation online, but it actually quite straightforward. SITL is a virtual computer running on your computer. Try it. Run

dronekit-sitl copter

from any directory. You will see the command return something like

Started model quad at -35.363261,149.165230,584,353 at speed 1.0
bind port 5760 for 0
Starting sketch ‘ArduCopter’
Serial port 0 on TCP port 5760
Starting SITL input
Waiting for connection ….

Running this is equivalent to turning on IRIS or Solo in your front yard and without connecting to a GCS. Your simulated vehicle is sitting inside your computer at a model airport in Australia, which I imagine is Tridge’s local airfield, sending out a TCP signal from port 5760 waiting for a GCS to connect. If you decide you’d prefer that your simulated vehicle take off in Berkeley, rather than Australia, run

dronekit-sitl copter –home=37.873894,-122.302141,584,353

See what happened? Other SITL options can be accessed by running

dronekit-sitl –help


dronekit-sitl copter –help

You’ll notice that you can simulate a plane or a rover and change various simulated vehicle settings.

Step 4: Connect SITL to arbitrary ground control stations

DroneKit Python contains a connect command, but to actually see how your simulated copter responds to your code, you will need to connect a GCS. This is done through MAVProxy, which as best as I can tell is both a text based GCS and a way to plumb mavlink messages from SITL or a real copter to other GCSs.

Unfortunately, installing MAVProxy is not as straightforward as the rest of this guide. The best instructions are at, but to keep this guide linear I will reproduce them. Run

brew tap homebrew/science

brew install wxmac wxpython opencv

from any directory in the terminal. The first command taps a repository that is not normally indexed in Homebrew. The second command installs wxMac, which is total mystery to me, wxPython, which is also a mystery to me, and OpenCV, which is an amazing open source computer vision project from which, I believe, sprang Pix4D and Agisoft.

Next, run

sudo pip uninstall python-dateutil

sudo pip install numpy pyparsing

sudo pip install MAVProxy

The sudo part means that you are running the command as an administrator on your computer and the pip command is our old friend from before.

Now MAVProxy should be installed and you are ready to start playing with your virtual copter. Start up SITL, if you closed the terminal window, by running

dronekit-sitl copter –home=37.873894,-122.302141,584,353

Then open a new terminal window and run –master=tcp: –out=udpout: –out=udpout: –out=udpout:

Notice that your SITL window has now bound to the MAVProxy master. This is because we’ve pointed MAVProxy to listen to MAVLink messages over TCP at local IP address (, although will work as well) using port 5760, all of which was specified when you initially booted up SITL. The three –out items give me three sockets to which I can connect GCSs.

You can now use MAVProxy to control your virtual vehicle (or your real vehicle if you choose to do so, to connect MAVProxy to a real vehicle connect your computer to Solo’s WiFi and replace tcp: with udpin: Try typing

mode guided

arm throttle

takeoff 10

into the terminal window running MAVProxy. You’ll notice your virtual vehicle will switch modes, arm itself, and takeoff. However, as interesting as it is to control a virtual vehicle from the command line, we are here to write software to control Solo’s behavior and need a visual way to monitor your virtual Solo’s behavior.

This is where the sockets come in. The first refers to my tablet running Tower, which I can use to both monitor and control my instance of SITL. The 3DR network assigned IP address to my Android tablet, which I determined by navigating to the advanced WiFi settings menu, and Tower is set up to listen for a vehicle on port 14550. Now, when I connect my tablet to the same WiFi network on which I am running SITL, I can see my virtual copter parked near the Berkeley office and can control it just like a real copter. To connect your Android tablet running Tower, you should replace my IP address with your own.

The second will be used for running the DroneKit Python examples. We need a socket free for DroneKit’s connect command to bind to.

The third is an extra for Tower-Web, a nice web app that let’s you track the status of your real or virtual vehicle. This is nice because it lets you debug your DroneKit Python applications without an Android tablet handy, but this step is totally optional and redundant if you plan on using your tablet running Tower to visualize your virtual Solo’s behavior. To install Tower-Web, simply run

sudo -H pip install -UI git+

from the terminal. Once the installation completes, run

tower udpin:

and you will bind the Tower-Web backend to your instance of SITL. Point your favorite web browser to http://localhost:24403/ and you should see your virtual vehicle flying around on your screen.

To quickly review, you now should have a virtual vehicle running on your computer that you can control using MAVProxy running in the terminal, Tower running on your Android device, or Tower-Web (sort of) in your web browser. Whew!

Step 5: Run the DroneKit Python example apps

Great! Now you’ve made it this far and are ready to start having some real fun. Let’s run the examples.

The easiest way to get the examples is using Git, which is a great and widespread tool for sharing and code on the internet. If you don’t have Git installed on your computer, we can return to our favorite program Homebrew and run

brew install git

from the terminal. Once Git is installed, navigate to the directory where you’d like the examples to be stored and run

git clone

The DroneKit Python examples will download into the folder from which you ran this command. Navigate to the Vehicle State example by typing

cd dronekit-python/examples/vehicle_state/

and run

python –connect

If you get an error regarding the gimbal status, remember that your simulated copter does not have a gimbal unless you specify one using the –gimbal command.

dronekit-sitl copter –gimbal

Note that we now have used all three of the sockets generated by MAVProxy (if you’d like to prove this to yourself, try connecting to 14550 with both DroneKit and Tower-Web) and the Vehicle State application will run. I’ll leave it to the DroneKit Python documentation to explain exactly what this program does, but needless to say you’ve run your first application on your virtual drone and are well on your way to writing your own.

I’d recommend running the rest of the examples, reading the documentation, and getting a rough sense of what they do. By the end of this, you should have a pretty good idea of what kinds of functionality is built into DroneKit Python and how you might write an application to control your real drone.

Step 6: Run the DroneKit Python example apps on Solo

SITL is fun and all, but we don’t read posts on DIY Drones to learn about controlling virtual vehicles. We want to control the real thing. Let’s try running some of these examples on Solo.

Simple Go To is a great one to start with. All of the locations are in Australia, so, if you don’t live with Tridge, open up with a text editor (I like Sublime Text) and edit the lattituide, longitrude, and alitude in points one and two (LocationGlobalRelative(your lat, your lon, your alt). Next, test your changes in SITL and make sure you simulated Solo is behaving as you anticipated.

Once you are satisfied with your code, bring Solo out to your airfield, connect your computer to Solo’s WiFi network, and spin up MAVProxy to plumb the whole system together. For the lazy, the terminal command is –master=udpin: –out=udpout: –out=udpout: –out=udpout:

You now can run

python –connect

from the Simple Go To’s directory and Solo will execute the Python commands and perform the mission. Pretty cool!

However, the observant reader might catch that in this case the code is actually running on your computer, not the computer on board Solo. To move the code and all of its dependencies on to Solo, we have to return to the Solo Development Guide and take advantage of some neat tools that the engineers at 3DR have written.

First, let’s install the Solo command line interface using pip

pip install -UI git+

This CLI lets you run a number of useful commands from the terminal. For example, if you’d like to connect your computer to both the internet and Solo over WiFi, which is very useful for development, run

solo wifi –name=network name –password=network password

To run your example code on Solo, run

solo script pack

from the directory containing This command will prepare a package containing your Python application and all of its dependencies on your computer. To install and run (note that this is a single step) this package on Solo, connect to Solo’s WiFi network and run

solo script run

Solo will takeoff and execute its mission based solely on the code you loaded onto its companion computer. You can verify that this by turning off your controller and seeing Solo execute its mission without an external signal in the loop.

Step 7: Controlling the camera and gimbal

Now that you’ve run the examples both in SITL and on Solo and spent some time understanding the various DroneKit Python functions, you are essentially ready to program your own Python-based GCS. It’s that easy!

However, one of the most amazing pieces of Solo is the fully controllable gimbal and camera. Simple camera functions haven’t quite made it into DroneKit Python and we at 3DR are still working to integrate all of the Solo-specific MAVLink messages into our SDK, but, because it’s close to Christmas and generosity is in the air, I will post some shortcuts here.

Both the gimbal and GoPro are controlled by MAVLink messages and DroneKit Python is backwards compatible with PyMAVLink, a great way to send arbitrary MAVLink messages to Solo. The general format of a MAVLink message sent through PyMAVLink is somewhat complicated. An example of a yaw message is below.

msg = vehicle.message_factory.command_long_encode(

        0, 0,     # target system, target component

       mavutil.mavlink.MAV_CMD_CONDITION_YAW, #command

      0, #confirmation

        90,     # param 1, yaw in degrees

        45,           # param 2, yaw speed deg/s

        1,           # param 3, direction -1 ccw, 1 cw

        0, # param 4, relative offset 1, absolute angle 0

        0, 0, 0)     # param 5 ~ 7 not used

I am no PyMAVLink expert, but, as we can see in both the comments and the MAVLink documentation for the yaw command, we use the vehicle.message_factory.command_long_encode function to pass an 11 argument message to some component. The first two arguments serve as the address of the message–0 and 0 refer to Pixhawk, which is doing the yawing. The third argument refers to what MAVLink message you’d like to send. Feel free to experiment with different messages. The fourth does nothing and the fifth through eleventh refer to the up to seven commands that can be passed through any MAVLink message. For this particular yaw command, only four are used–the amount of yaw requested, the yaw speed, the direction, and whether yaw should be absolute or relative to the position of the copter before the yaw was initialized. Now you’ve had the opportunity to look under the hood at DroneKit.

We will use a similar strategy to control the camera and the gimbal with one caveat–mavlink-solo-master is still private. We at 3DR are working hard to clean everything up for public consumption so these commands will work on board Solo, but not on your computer or in SITL.

To switch GoPro from video to photo mode, try the code below.

msg = vehicle.message_factory.gopro_set_request_encode(MAVLINK_GIMBAL_SYSTEM_ID, MAVLINK_GIMBAL_COMPONENT_ID, mavutil.mavlink.GOPRO_COMMAND_CAPTURE_MODE, (1, 0, 0, 0))



Notice we are now using the gopro_set_request_encode variable rather than the command_long_encode, but the general format is the same. Here the system and component IDs, which were 0 and 0 for Pixhawk, are declared as variables rather than numbers. You can either include MAVLINK_GIMBAL_SYSTEM_ID = 1 and

MAVLINK_GIMBAL_COMPONENT_ID = 154 as constants in the start of your code, or just substitute these numbers for the text. Notice the MAVLink message is GOPRO_COMMAND_CAPTURE mode, which is not found on the list of Arducopter MAVLink messages. This is because it is found in the in the still private mavlink-solo-master and documentation has not yet been written. That said, I can tell you right now that switching the first bit in the message from a 1 to a 0 will switch the camera from photo to video mode. Cool!

To take a picture, I used the code below.

def take_a_pic():

   msg = vehicle.message_factory.gopro_set_request_encode(MAVLINK_GIMBAL_SYSTEM_ID, MAVLINK_GIMBAL_COMPONENT_ID, mavutil.mavlink.GOPRO_COMMAND_SHUTTER, (1, 0, 0, 0))



Notice that this time I wrote a definition, so each time I want to take a picture in my code I can simply write take_a_pic().

To control gimbal, I wrote an eponymous definition, nadir_point.

def nadir_point():


   msg = vehicle.message_factory.mount_configure_encode(

           0, 1,    # target system, target component

           mavutil.mavlink.MAV_MOUNT_MODE_MAVLINK_TARGETING,  #mount_mode

           1,  # stabilize roll

           1,  # stabilize pitch

           1,  # stabilize yaw




   msg = vehicle.message_factory.mount_control_encode(

           0, 1,    # target system, target component

           -90*100, # pitch is in centidegrees

           0.0, # roll

           0, # yaw is in centidegrees

           0 # save position




This time it takes two MAVLink messages to get the job done, but it still does the trick. Now whenever I’d like to point the gimbal toward nadir, I simply call nadir_point(). If I wanted to be even more clever, I would write a function called point(XX) whose argument appeared in place of -90 in the pitch field so the function could be used to point the gimbal wherever I wanted.

You should now have all of the tools in your toolbox to write your own WHOZCHILLIN app.


You can download my WHOZ CHILLIN code here (change extension from .txt to .py to execute). You can see that the user gets several different CHILL options. Go ahead and replace my GPS locations with your own and  give it a rip. Note that the CHILLIN app turns off the R/C failsafes. Test your code in SITL extensively before you even consider doing this.

Step 9: Future directions

But wait, you say. I promised that WHOZ CHILLIN would let me open a web browser and see an image of who was chillin’ on my roof. The code here just takes a picture that GoPro saves to the SD card that I have to pull out to take a look at. This is way too painful of a workflow to really be CHILLIN. You are right, but this is enough for now.

Instructions for grabbing stills from the video feed, setting up a Python server, and posting the result online will be contained in the next installment of Idiot’s Guide to DK-Python and soon you will be able to complete your journey to WHOZ CHILLIN.

Until next time…


2015-12-30 07.16.41 pm


Reporting from my first University of Colorado Alumni Association board meeting

Since graduating from the University of Colorado (three times!), I’ve been somewhat flabbergasted how few touches I’ve gotten from the University. While peers at other institutions have gotten invitations to 5 year reunions, calendars, red books updating them as to their classmates whereabouts, and other frequent reminders not to forget their almae matres, I feel relatively forgotten. I get a monthly magazine, The Coloradan, a few untargeted emails here and there, and occasional invites to not particularly compelling events in San Francisco. That said, growing up in Boulder and attending CU for probably too many years, I do feel a sense of pride anchored in the University and I know that if the alumni association is not engaging with me, they are probably not engaging with my peers as well. And, now is the time to begin a relationship with one’s alma mater. Recent graduates have fresh positive memories from college, maintain a social network around college friends, and are relatively free from the burdens of real adult life.

So I decided to do something. I applied to serve on the Alumni Association Board and share some of my thoughts with the Marketing Committee. I wasn’t sure what to expect for my first meeting, but I am happy to report those expectations have been blown out of the water. While it apparently is a relatively recent transition, the CU Alumni Association is now being run like a Silicon Valley tech company. The OKRs Google (and 3DR!) is so famous for using to benchmark its employees are in full force at the Alumni Association. The impact of events and publications are quantitatively measured and those results are used to feedback into planning for the next iteration. While this effort is still nascent, I have full confidence that these types of organizational metrics will allow the CU Alumni Association to become the best in the country.

What does this mean for other young alumni? Hopefully, we will begin to reach you in more targeted, meaningful avenues. Not a day drinking football fan? You won’t get invited to the Saturday watch party at Tupelo. Huge skier? You will get reminded and connected to other Buffs in your area for pre-Crested Butte ski trip planning. Stay tuned for more action and Go Buffs!