Bunch of UAV::Pilot Updates on CPAN

UAV::Pilot::Video::Ffmpeg v0.2, UAV::Pilot, UAV::Pilot::WumpusRover v0.2, and UAV::Pilot::WumpusRover::Server v0.2

These modules just got some Yak Shaving done. Fixed up their CHANGELOG, spammed license headers on everything, and added a test for POD errors.

UAV::Pilot v0.10

Fixed a regression bug (and added a test case) of FileDump taking a filehandle.

UAV::Pilot::Command will now call uav_module_quit() on the implementation libraries for cleanup purposes.

Same Yak Shaving as above.

UAV::Pilot::ARDrone v0.2

Added bin/ardrone_display_video.pl for processing the video data. This can either
be over STDIN, or in a raw filehandle. This is implemented in a way that should work for both
Unixy operating systems and Windows.

Added UAV::Pilot::ARDrone::Video::Stream and UAV::Pilot::ARDrone::Video::Fileno to support the above.

In the uav shell for ARDrone, there is a parameter you can pass to start_video. Calling it without a parameter has the video stream handled in an external process with the fileno() method, which keeps the stream latency down. Calling it with 1 will instead use a pipe, which has a small but often noticeable lag in the video output. Calling with 2 will use the old fashioned way, which does not open an external process. Using an external process tends to take advantage of multicore CPUs better.

Nav data now correctly parses roll/pitch/yaw. The SDL output was updated to accommodate the corrected values.

Same Yak Shaving as above.

Well, I Feel Stupid

Given that the AR.Drone’s control system sends roll/pitch/yaw parameters as floats between 1.0 and -1.0, I thought the navdata sent back things the same way. I was never getting the output I expected in the SDL nav window, though.

Then last night, I was comparing how NodeCopter parses the same nav packets and seeing completely different numbers. Turns out the AR.Drone sends back numbers in millidegrees instead.

I feel dumb for not noticing this before. OTOH, this is only “documented” in the AR.Drone source code. The actual docs tell you to look at the navdata in Wireshark and figure out the rest for yourself.

Corrections are now up on github. Should be a new release of UAV::Pilot distros coming up soon. These releases will cleanup quite a few details that I wanted to get done before YAPC, so we should be in good shape.

Hopefully, the TSA won’t bother me too much with an AR.Drone in my carry-on. Some people at my local hackerspace managed to get a whole Power Wheels Racer, including the battery, into their carry-on, so I think I’ll be good.

Announcing: The Great UAV::Pilot Split

The main UAV::Pilot distro was getting too big. The WumpusRover server had already been spun off into its own distribution, and now the same is happening for many other portions of the system.

Reasons:

  • UAV::Pilot hasn’t been passing CPAN smoke testing because of the ffmpeg dependency. Splitting that off means the main distro can still be tested.
  • There’s no reason to get the WumpusRover stuff if you just want to play with the AR.Drone
  • General aim towards making UAV::Pilot into the DBI of Drones

UAV::Pilot itself will contain all the basic roles used to build UAV clients and servers, as well as what video handling we can do in pure Perl.

UAV::Pilot::Video::Ffmpeg will have the non-pure Perl video decoding.

UAV::Pilot::SDL will take the current SDL handling, such as for joysticks and video display.

UAV::Pilot::ARDrone and UAV::Pilot::WumpusRover will take the client end of things for thier respective drones.

I expect the first release to have interdependency issues. I’ve tested things out on a clean install, but I still might have missed something. I’m going to be watching the CPAN smoke test reports closely and filling in fixes as they come.

UAV::Pilot v0.8 Released — Now Supports WumpusRover

At long last, UAV::Pilot v0.8 has been released. This is a big update with lots of API improvements. Most of those improvements were decoupling the code to support my own WumpusRover in addition to the Parrot AR.Drone. That means a big goal has been reached, where UAV::Pilot can support multiple types of automated vehicles. It also means UAV::Pilot is a major component of the code running on board a UAV, in addition to running the client side.

The WumpusRover is a project I’ve been working on for a while. It’s an old RC car I had laying around, retrofitted with a brushless motor controller, an Arduino, and a Raspberry Pi.

Update: Video of the WumpusRover will be up at http://youtu.be/yeDwb-6ASxw. Going to be leaving soon out of town, but wanted to make sure this gets up before I go out the door.

UAV::Pilot runs on the Raspberry Pi as a server, taking packets from the client and passing turning and throttle data to the Arduino. The reason for the split between Rapsberry Pi and Arduino is:

  1. The Arduino has better support for the communication pulses used by RC servos and ESCs
  2. The Raspberry Pi with Linux is not a real-time OS–that means a carefully timed signal to the servo could be interrupted by the OS
  3. The Raspberry Pi can run Perl, support any WiFi adaptor that Linux does, and has an excelent camera module

(The camera module is not yet implemented directly with Perl support. This is one of my upcoming projects, which will give the WumpusRover a video stream, among other things.)

As you can see, the two complement each other’s strengths. In the future, we might see cheap boards that can combine these two uses; the recently announced Arduino Tre looks promising.

I’ll be posting more detailed instructions later. If you’d like to get started on your own rover, you can start with the Arduino code here:

https://github.com/frezik/wumpus-rover

There are also some improvements to the older AR.Drone code. While making changes to the joystick API to support the WumpusRover, I found a case in the AR.Drone where its navdata sends a floating point -NaN. (More evidence that they shouldn’t have been using floating point for this purpose, and that the AR.Drone was badly implemented in general). UAV::Pilot was crashing in this case, but now handles it gracefully.

Also, the nav data will now be sent over ol’ fashioned unicast IP by default instead of multicast. This should make Mac users happy, as multicast isn’t setup out of the box on OSX.

UAV::Pilot v0.6 Released

UAV::Pilot version 0.6 is now on CPAN. Lots of little changes this time. The big thing is an API change, where Control::ARDrone and Driver::ARDrone were instead named ARDrone::Control and ARDrone::Driver, respectively. This keeps everything related to a single type of UAV under one namespace directory, which I think will be nicer going forward as I implement other UAV systems.

I had hoped to get multiconfig working, which would have made the 720p stream work. I ran into problems getting it to work, though, and my message on the ARDrone dev forums has so far gone unanswered. No idea what I’m doing wrong, but I didn’t want to hold up this release any longer. Might have to see how (or if) Nodecopter handles this.

For version 0.7, I’m building a rover. This is my backup plan since the WumpusUAV Indiegogo campaign didn’t work out (because I suck at marketing). I have an old RC car that I’ve upgraded with a brushless motor and LiPo battery, and retrofitting with a Raspberry Pi and Arduino. The Raspberry Pi will handle the WiFi and video stream (the Rapsberry Pi camera module is supposed to be really nice), while the Arduino handles motor control.

The protocol will be the Ardupilot protocol, or at least something close to it. I won’t be testing it against an actual Ardupilot, at least not at first. It should get the system close enough that we can implement an actual Ardupilot later.

UAVs and FOSS — AR.Drone

This is the first in a series of articles about the state of FOSS software in terms of UAVs. We start with the place where I have the most experience, the Parrot AR.Drone.

On the client side, Parrot has released a complete SDK for controlling the AR.Drone. It includes support for the control protocol, the navigation protocol, and the video streams (which is handled by ffmpeg).

However, many people choose to make a clean implementation based on the SDK docs. This includes my own UAV::Pilot, and also NodeCopter, an implementation for Node.js. Both of these are under a BSD-style license. The parts of UAV::Pilot that interface to ffmpeg are LGPL.

Control is done over WiFi. It will create its own ad-hoc network by default. With some trickery, you can connect it to an open access point, though it doesn’t seem to support WPA authentication.

The on-board electronics for the AR.Drone has a Linux system with Busybox, which you can telnet into. This seems to be mostly useful for debugging the commands sent over the network, or configuring it to connect to an open access point. Hacking it to control external devices via USB seems like it should be possible, though I haven’t been able to find anybody who actually accomplished this. Just a lot of people talking about it. C’est la vie.

Version 2.0 of the AR.Drone includes front and bottom cameras, which can stream 720p video. They’re on par with cheap webcam quality.

As I’ve complained about before the AR.Drone’s SDK doc is rather poorly documented. The control protocol is mostly fine, but there are a lot of missing details about the nav data and video protocols. The information you need is spread out on the dev fourms, and it just shouldn’t be that way. I’m also dealing with the multiconfig options, which requires getting the ACK bit off the nav data stream, which seems all backwards to me even if it was well-documented. The config should have been handled over a TCP stream, especially when multiconfig was implemented.

It is relatively cheap, though, at $300. A basic ArduPilot setup will be around $700 if you include the telemetry module and a cheap 6-channel radio. That setup wouldn’t even have a camera.

All things said, I think the AR.Drone is a good way to get started considering what’s out there right now. But it could definitely be improved.

Musings on Hackable UAVs

Programming the AR.Drone has been a mostly fun challenge, and occasionally a frustrating challenge. The nav data is particularly under-documented, and UAV::Pilot still suffers from a few video parsing issues, probably because the documentation doesn’t fully explain the PaVE headers. But I pushed through them, figured it all out, and now there’s a release that I would consider close to feature-complete.

I never intended to stop with just the AR.Drone. It was a cheap way to get started–cost about $300 rather than $500-700 for a some other types–but it’s ultimately a toy. I don’t have a problem with big-boy toys; in fact, I own quite a few of them. But it’s a bit limited.

More “serious” UAV platforms, such as Ardupilot, often use some kind of mission planner software that allows you to put in a path of GPS coordinates and do something at the waypoints (like take pictures). With a GPS attachment and the right software, this is technically possible with the AR.Drone, but not out of the box.

The AR.Drone also has decent but somewhat limited hacking potential. If you’re willing to void your warranty, you can set on-board scripts to connect to AP-mode WiFi, add cheaper high-capacity batteries, or use the USB port to run attached devices. But it’s ultimately a closed platform with all the limitations that implies.

I find some of the other autopilots out there just as frustrating, for a somewhat opposite reason. They allow you to do anything, but their starting point is more sophisticated and need some work to dial them back down. The Ardupilot hardware, for instance, needs a compass, GPS, barometer, and some other assorted electronics. Not all this stuff is necessary for all uses. If you’re flying lower than 20-50 feet or so, the barometer isn’t much use and is too inexact. An ultrasonic range finder would be better for that case.

It’s all FOSS, so I’m sure you can get it all to work one way or another, but it isn’t designed for it.

By way of analogy, for years before the iPad, Microsoft had tried pushing tablets by taking their desktop OS and scaling it down to a tablet. They were largely ignored. What Apple (and later, Google) showed was that the correct strategy was to take a smartphone OS and scale it up.

That’s similar to the strategy I’d like to try with UAVs. If you want a toy UAV like the AR.Drone, you should be able to put it together cheaply without a GPS or barometer or anything. But if you want to get more serious, you should be able to add all that stuff without much trouble.

The platform should allow you to alter every aspect of the design, allowing the frame to be fully 3D-printable. Some printable UAV designs are already out there, such as the PL1Q Vampire, though often under a non-commercial license, which doesn’t meet widely accepted definitions of FOSS.

My goal is to build a UAV platform with the following requirements:

  • Complete design is under FOSS-compatible licenses, allowing modification for personal or commercial use. Licenses like BSD, Lesser GPL, or CC-BY[-SA] (but not CC-NC).
    • Software will probably be BSD, with CC-BY for hardware
  • On-board systems controlled by cheap and easily available computing platforms, such as Raspberry Pi, Arduino, and/or ATtiny.
  • Frame is fully 3D printable
  • Wide choice in attaching hardware; GPS, barometer, cameras, nerf guns, etc.
  • Wide choice in control methods; WiFi, XBee, cell phone towers, etc.
  • Complete documentation on control, navigation data, and accessories

I respect the work that’s already gone into projects like Ardupilot, but they don’t seem well suited for toy UAVs. And there’s nothing particularly wrong with toy UAVs; they are bound to have some rather un-toy-like uses, and even if not, there’s nothing wrong with a few toys. This looks like an open niche among the FOSS autopilots, which I intend to fill.

UAV::Pilot v0.5 Released, Now Supports Real Time Video

UAV::Pilot, a Perl library for controlling the Parrot AR.Drone, has released version 0.5.

This was the big one. With the ffmpeg library installed, you can decode the h.264 video stream coming right off the drone, in real time. This is where UAV::Pilot starts to get really interesting, opening up applications like augmented reality games and object recognition.

Demo video:

I’m going to be taking a short break from working on UAV::Pilot for a while. After lazing about, I’ll start work on the next release, which will mostly be cleaning up the API and bugs.

Also, I’ll be giving a presentation on UAV::Pilot in September for the Madison Perlmongers Group, which I plan on recording.

UAV::Pilot v0.4 Released, Now Supports Video

UAV::Pilot, a Perl library for controlling the Parrot AR.Drone, has released version 0.4.

The big change for this update is streaming video to a file. Display in real-time is not yet
implemented–that’s coming in 0.5.

There are also some API changes in how event loops are initialized to make the naming more consistent. There will probably be another API change in the video handling in 0.5. Once I do a complete release, API changes will have a proper deprecation plan, but for right now I think it’s fine to change things willy-nilly.

UAV::Pilot v0.3 Released

Version 0.3 of UAV::Pilot has been released on CPAN. The major change in this version is an improved event loop based on AnyEvent.

AnyEvent is a very nice framework overall, but unfortunately doesn’t have quite the right syntax for UAV::Pilot’s purposes. Consider this plain-English description of a UAV flight:

Takeoff, wait 5 seconds, then pitch forward for 2 seconds, then pitch backwards
for 2 seconds, then land

In AnyEvent’s standard interface, things would work out something like this:

my $timer; $timer = AnyEvent->timer(
    after => 5,
    cb => sub {
        $uav->pitch( -1.0 );
        my $timer2; $timer2 = AnyEvent->timer(
            after => 2, 
            cb => sub {
                $uav->pitch( 1.0 );
                my $timer3; $timer3 = AnyEvent->timer(
                    after => 2,
                    cb => sub {
                        $uav->land;
                        $cv->send;
                    },
                );
                $timer2;
            },
        );
        $timer;
    },
);

$uav->takeoff;
$cv->recv;

All that indentation gets hairy. So I created an interface on top of AnyEvent, UAV::Pilot::EasyEvent, which is based on the Node.js event interface used by NodeCopter. Here’s how you’d write the same problem using EasyEvent:

my $cv = AnyEvent->condvar;
my $event = UAV::Pilot::EasyEvent->new({
    condvar => $cv,
});

$event
    ->add_timer(
        duration => 2000,
        duration_units => $event->UNITS_MILLISECOND,
        cb => sub { $uav->pitch( -1.0 ) },
    )->add_timer(
        duration => 2000,
        duration_units => $event->UNITS_MILLISECOND,
        cb => sub { $uav->pitch( 1.0 ) },
    )->add_timer(
        duration => 2000,
        duration_units => $event->UNITS_MILLISECOND,
        cb => sub { 
            $uav->land;
            $cv->send;
        },
    );

$event->activate_events;
$uav->takeoff;
$cv->recv;

Much better.

As an added bonus, having a good event interface means we can also support controlling UAVs through SDL joysticks. See bin/uav_joysticks in the distribution for details.