gobot icon indicating copy to clipboard operation
gobot copied to clipboard

Fill Out Bebop Events, GPS Support?

Open ghost opened this issue 10 years ago • 14 comments

Hi folks,

Gobot support figured highly in my purchasing decision to get a Bebop, and I'm having fun already getting to know Gobot and imagining ways to paste my Bebop to Arduino or microcomputer hacks.

Looking through the Bebop code in Gobot versus other frameworks, including some by HybridGroup, I see that it doesn't have much support yet for onboard events? For example, the "flying" event is fired by Gobot presumptively after sending the TakeOff instruction, whereas it seems (from perusal of the...difficult...official API documentation) that the device itself issues events when its state changes from "Taking off" to "Hovering" to "Flying" to "Landing" to "Emergency".

Likewise, the official API makes it very difficult to understand, but I gather the device either regularly, or on request, issues sensor updates including GPS, accelerometer, etcetera. GPS in particular would be very valuable, because it would allow one to write homing code to help the device navigate through flight-paths.

I would happily help contribute these features, if there were somewhere to go learn about the low-level Bebop API that Gobot is reimplementing. Which of the defined magic Bytes are commands sent to the drone, and which are tokens designating what kind of data is being received from the drone? How does one write code to issue an instruction including arguments, and how does one receive and post (all?) events to the Gobot event handler? If I could get this kind of information I'd happily run off and try to implement this stuff myself, but the official API is very oddly laid out and the documentation stops short of anything but the basics, much less GPS.

Thanks again for Gobot, looking forward to helping or at least making use of it. :)

ghost avatar Nov 07 '15 23:11 ghost

Just documenting my learning process as I tease apart the code..

In bebop's client, UDP messages seem to be received by the goroutine on line 273, and are passed to the Bebop.packetReceiver([]byte) method, which at present appears to only decide what, if any, ACKs to send.

If I'm not mistaken then, this is the appropriate place to put code that decodes the data returned by the device, looking for telemetry data and state changes?

For a more specific guidance-question then, is there any readable documentation on how incoming packets are structured, how to parse and identify them relative to one another, and how the payload data is structured (besides its being Little-Endian..)? Will keep digging.

If I figure this out and can parse packets, I can start doing something with them.. what's the Gobot-way to handle streams of incoming events like this? I imagine registering more event handlers (currently only "flying") is a good place to start, and then just start pushing them to the global event queue?

ghost avatar Nov 08 '15 00:11 ghost

Hi, @cathalgarvey

Totally love what you are doing here.

So yes, you are exactly correct about packetReceiver.

This is how we did the same thing in node-bebop https://github.com/hybridgroup/node-bebop/blob/master/lib/bebop.js#L198

If you implemented the same equivalent in Gobot as we have done there in Node.js, it would be an amazing step forward.

The best docs I've found on the Bebop protocol are thanks to @robotika located here:

https://github.com/robotika/katarina/blob/master/bebop-protocol.md

deadprogram avatar Nov 08 '15 02:11 deadprogram

Fantastic, thanks; I'll go read up. :)

ghost avatar Nov 08 '15 03:11 ghost

By way of documentation and to invite comment early: I'm in the process of writing something I hope will suffice. Rough outline of where I'm going with this so far:

  • Adding a method to the Bebop client: Telemetry() chan struct{Title string, Data []byte} (I don't know if re-using anon structs between packages in this way is kosher, I'll find out when it fails to compile). This returns a 10-buffered channel that telemetry events are sent back on. All non-video Bebop frames received are sent; if they aren't handled specifically, they are sent as "unknown". Telemetry data is parsed if it's understood, but is still returned as a []byte. So, a uint32 decoded to an expected byte between 1 and 8 is cast to a single byte and sent back. This is probably the wrong way to do things.
  • Setting up a goroutine in the Bebop driver to pull from this channel and post global events in the usual way. This happens in the drivers' "start" method.
  • Trying to cleanly shut down this telemetry system when the driver's "stop" method is called. Likewise the client's "Stop" method closes a channel to let all existing goroutines waiting on Telemetry stop.

Has anyone got a handy reference of the heirarchy of constants? I.e. which Classes belong to which Types/Projects, and which Ids belong to which Classes? Assuming they are heirarchical, which is perhaps not a reasonable assumption, but it is based on an XML template..

ghost avatar Nov 08 '15 09:11 ghost

Finally getting the hang of reading the XML code, thanks to having @robotika's code to compare against and learn from.

Have some raw, untested, incomplete code committed to my repo, will spend some time tomorrow adding more.

Looking forward to testing this. If even the GPS works, I'll be happy; killer feature, right there. :)

ghost avatar Nov 08 '15 10:11 ghost

Oh yea, and I changed things so the events are emitting JSON, which is slightly more sane than emitting parsed-then-re-dumped binary. Not ideal, but compatible with the way things are done in gobot already and somewhat intuitive provided the keys in the JSON correspond to Bebop API parameters (which I've tried to hew to).

ghost avatar Nov 08 '15 10:11 ghost

Seems like you are making some great progress!

Please let me know anything I can do to help out.

deadprogram avatar Nov 08 '15 15:11 deadprogram

OK, I've pushed to my own repo some incomplete additions that have partial telemetry support. It appears to be working on my Bebop while it rests on the table, and when it encounters events it can't yet handle it posts "unknown" event with a useful message.

There's a new example file: platforms/bebop/client/examples/telemetry.go (which properly ought to live a directory down as technically it's using the Driver, not the Client). This connects to the 'bot, issues no instructions, and just prints all incoming events that aren't too spammy to handle.

Observation: there are only two "commandProject" values expected according to the XML layouts and other reference code, but according to this it's picking up an incrementing set of commandProjects that rise to 255 and roll over. This likely indicates something nasty going on in the frame handling code. It doesn't stop the spammier events (camerastate!) from getting through though, so actual data frames appear unaffected?

I'm not confident that this won't blow up a drone yet so I'm not issuing a PR, but would love thoughts if you have time. Or, if you feel like risking a bot and have space to test (which I lack right now), a flight test! :)

ghost avatar Nov 09 '15 07:11 ghost

OK, good news: I tracked down and killed a bunch of bugs, implemented an incomplete but acceptable set of telemetry class handlers, and tested on my drone in live flight, and I've got telemetry working. :)

There's a lot of it: It spams a load of information about attitude/altitude/gps, though GPS is either broken or simply returns dummy values (500,500,500) in indoor mode. Altitude only reports greater than nil in flight. Attitude appears to work even when inactive.

I don't suggest a pull yet, and am not issuing a PR, because the Land() method seems not to be working anymore, which is odd because I don't recall touching it! When I get that working I'll issue a PR?

Before I do, if you have a chance to check out the coding arrangement I've got going it might avoid questions later.

Basic strategy: Dataframes go to a dispatcher, which looks up commandProject in a map, then looks up commandClass in the returned sub-map, and issues the frame to the handler. Handlers mostly use a switch to pick the right code by commandId, and dispatch, passing back (found bool, commandName string, err error) for error messaging context. Dispatching of all telemetry is done in its own goroutine but when it comes to messaging to the global cue it happens through a 10-length channel, discarding overflow, so if the telemetry channel isn't read the messages (and goroutines) are discarded.

The incoming telemetry is pulled by a goroutine that's spun up at Bebop starttime and posted to the Gobot event cue, though the event names could do with an overhaul to namespace them and make them clearer.

Hope you like it! :)

ghost avatar Nov 11 '15 06:11 ghost

Hi, @cathalgarvey just wondering if you were still up for submitting a PR for your changes for Bebop?

In the interim, we've got the "full API" supported now in https://github.com/hybridgroup/node-bebop thanks to work from @johan-olsson that might be helpful to look at.

deadprogram avatar Feb 17 '16 02:02 deadprogram

Yes, absolutely; they should still be considered "beta grade" though, I haven't flown the Bebop much yet and certainly haven't been controlling it much from the computer, either (life's been busy..). Here be dragons and flying death machines of another sort, etcetera.

I'll give it a code review later and check my stale notes to be sure nothing glaring is yet to be finished, finally check if it's OK with the master branch as-is, then issue a PR.

On Tue, 2016-02-16 at 18:04 -0800, Ron Evans wrote:

Hi, @cathalgarvey just wondering if you were still up for submitting a PR for your changes for Bebop?

In the interim, we've got the "full API" supported now in https://github.com/hybridgroup/node-bebop thanks to work from @johan-olsson that might be helpful to look at.

— Reply to this email directly or view it on GitHub.

ghost avatar Feb 17 '16 09:02 ghost

Sounds great, thanks @cathalgarvey

deadprogram avatar Feb 17 '16 15:02 deadprogram

Right.. I've done some cleanup, and some re-org, currently incomplete. I haven't tested the code as-is on my bebop, so I'm not comfortable PRing yet. But, you're welcome to give it a look over, if you like!

ghost avatar Feb 17 '16 22:02 ghost

Hi @cathalgarvey I was just checking out your branch with the Bebop changes, and there are a bunch of interesting ideas and useful-looking code there. Thanks again for having worked on that.

Of course is way out of date with the massive refactors that have happened with Gobot 1.0. Sorry about that. You might not be doing anything with Bebop these days, but I'd love to figure out how to get some of this back into the mainline Gobot, if possible. Or at least incorporate some of it. Any thoughts?

deadprogram avatar Dec 27 '16 11:12 deadprogram