Controller <- MAVLink -> QgroundControl Minimal Example

Hi, I’ve got a custom research ROV under development that up until now has used an in-house serial protocol over a short tether to send user input from my joystick to the custom vehicle controller.

I’m trying to upgrade to control over ethernet with the Fathom-X tether along with first-person video streaming from the low light USB cam. I’ve got video streaming to QGroundControl working fine with gstreamer on a Raspberry Pi inside the vehicle.

I thought it would be straightforward to minimally implement manual control and basic telemetry via QGroundControl just like the block diagram at https://www.ardusub.com/software/components.html

But I’m having a hard time finding a clear conceptual description anywhere of how I would replace the Pixhawk with my custom controller and establish a successful MAVLink connection to QGC without installing or using ArduSub/ArduPilot or PX4 or whatever software stack on “supported hardware.”

I generated MAVLink C headers for a few messages and far as I can tell I’m sending valid MAVLink heartbeats from my vehicle controller. With a USB-to-serial adapter connection to my controller, I can get a pymavlink script to receive and print the heartbeats.

I then tried with a manually-set-up serial connection in QGC, expecting (erroneously?) to at least see something in MAVLink inspector, but nothing. I found this: Redirecting to latest version of document (master) but I’m not sure if all of that is required to get a two-way link between a vehicle and QGroundControl.

I’m starting to dive into the ArduSub and QGroundControl source code to see if I can figure out how the connection is negotiated but if anyone has other suggestions for a more understandable starting point to set up a very basic MAVLink manual control and telemetry connection to QGroundControl without the rest of the autopilot software, it’d be appreciated.

Thanks,
Dan

1 Like

You are going to need to inspect the source code of QGroundControl. QGroundControl produces a different interface depending on the type of vehicle connected and firmware that it identifies itself with. If you want to get the same interface as ArduSub, you are going to have to mimic the things that ArduSub presents to QGC.

In QGC, a new vehicle object is instantiated once a heartbeat has been seen on a link: qgroundcontrol/MultiVehicleManager.cc at 3.2.4 · bluerobotics/qgroundcontrol · GitHub

This driver for the water linked gps creates a new vehicle in QGC that shows the surface vehicle’s heading and position. The telemetry from this script will appear in the mavlink inspector.

Thanks Jacob.

The Water Linked GPS script helped me modify my code to get some telemetry into MAVLink inspector, so at least I’ve verified that connection and I’ve also got it running through MAVProxy on the Raspberry Pi.

I’ll see what I can do to work through the QGC code.

Working through the code is not very productive image

I’ve also been working on just printing and inspecting the MAVLink messages QGC is sending out and responding to all the QGC requests for vehicle, mission, and autopilot parameters.

If I pretend to be a PX4 autopilot, I can clear out all the “parameters are missing” and “component requires setup” errors except something about firmware versioning that I’m not faking right, I guess.

If I say I’m a Generic autopilot, I can get QGC to a state where it doesn’t complain at all, it has a Vehicle and it goes back to just sending its own heartbeats. It doesn’t complain about any missing parameters and doesn’t say that anything requires setup.

It says the vehicle is manual flight mode,and so on.

However, something is still wrong, and I don’t get to the Vehicle Connected state and I don’t get any new settings so I can’t setup a joystick, for example.

I still need to try some stuff with autopilot capabilities flags, maybe, and probably other flags, but I don’t know.

I wish QGC had a “minimal MAVLink manual teleoperation” autopilot type that just transmitted joystick and parameter data and received telemetry for use with simple MAVLink messaging.

The vehicle doesn’t connect until the parameter negotiation is complete and all parameters have been received. Look in the code for things like parameterReadyVehicle. QGC is multi threaded, so the code that waits for the parameters to come in is in a different place than refreshAllParameters.

I’m not aware of a complete system for control over an arbitrary vehicle with video stream. QGC is close to this, you just need to get your hands dirty with it.

I didn’t actually make any progress figuring this out from the code. I paused to look into ROS + gstreamer setups for the video side because ROS is probably more long-term more useful to me in the big picture (though not for my short-term goal).

So I was working to debug ROS gscam and wanted to make sure I was getting UDP video to the new Ubuntu laptop I set up for ROS. Since that worked beautifully out-of-the-box in in QGroundControl, I downloaded the official QGroundControl Linux binary from http://qgroundcontrol.com/

I turned on my robot and everything just started working. I achieved “connected” status and got the Joystick plugin and now I’ve got manual control messages streaming to my robot. I haven’t tried Blue Robotics QGroundControl on Linux to see if that works.

I will post more detail later, but the following seems to work for the official Ubuntu binary AppImage here: Redirecting to latest version of document (master)

My robot is sending a heartbeat that says it’s MAV_TYPE_SUBMARINE, with an autopilot of MAV_AUTOPILOT_GENERIC. It has a base mode of
(MAV_MODE_MANUAL_ARMED | MAV_MODE_FLAG_CUSTOM_MODE_ENABLED),
has a custom mode of 0, and is in state MAV_STATE_ACTIVE

QGC sees this and starts to request things. I negotiate the following:

QGC sends PARAM_REQUEST_LIST

I respond with repeated #22 PARAM_VALUE
to send some parameters using mavlink_msg_param_value_pack_chan() I don’t think it matters much what the parameters are, I’m sending four parameters total at the moment, one right after the other.

QGC sends COMMAND_LONG
The command it sends using COMMAND_LONG is 520 MAV_REQUEST_AUTOPILOT_CAPABILITIES with param1 of 1 (request autopilot version)

I respond with #148 AUTOPILOT_VERSION using mavlink_msg_autopilot_version_pack_chan() with basically random data.

QGC sends #43 MISSION_REQUEST_LIST

I respond with #44 MISSION_COUNT using mavlink_msg_mission_count_pack_chan() I say that there are zero mission items.

I’m also always sending some #1 SYS_STATUS messages. They don’t contain anything besides my battery voltage yet. That shows up in the proper places in the QGC GUI.

This is enough for the official QGC on Ubuntu 16.04. Connection is achieved and it starts sending MANUAL_CONTROL messages with live data from my F710 joystick.

Again, I’ve changed nothing on the robot side since the last post. I figured out this exchange from printing and responding to each of the messages from the Blue Robotics forked QGC (3.2.4 IIRC?) on Windows. The Blue Robotics fork on Windows eventually stopped querying the robot and showed the responses in MAVLink Inspector, but did not connect or present the joystick interface.

The official QGC install for Windows never sent any packets to my robot. It sent its heartbeat but never saw my robot. I think this might have been a port issue, but I didn’t debug that yet.

What system/component id are you using? (should be 1/1)

Can you send a telemetry log recorded by QGC?

No, I’m using 5/1, thinking that the system ID was arbitrary. I’ll try 1/1 on Monday and report back.

Our fork only connects to 1/1 as the active vehicle. A sort of workaround for ease of use with the water linked system.

1 Like

Yes, it was the system ID. All working now, thanks! System/component ID 1/1 in addition to the steps described above allows connection with Blue Robotics QGC v3.2.4-Rev4.

Is the “Setup Disabled While Vehicle Is Armed” message in the joystick window specific to the BR fork? I was able to calibrate and change joystick settings with the vehicle connected in the recent official QGC on Linux. It appears I needed to add arm/disarm functionality to my robot to allow joystick configuration with the BR version.

I did that, and it works, but it appears that handling
#76 COMMAND_LONG, 400 MAV_CMD_COMPONENT_ARM_DISARM and acknowledging it with #77 COMMAND_ACK needs to be added to the steps I took above to fully enable a connection with the BR fork.

It looks like they enabled the joystick page while armed. I don’t think this should be the case; it may have been a mistake. I will ask them about it.

The answer is yes, but I don’t think it should be.

I send heartbeat message from the autopilot to QGC but I could not see that message in QGC MAVLink Inspector. Also I could not see any packet is sending from the GQC to autopilot either. Under the MAVLink setting in QGC I have enable heartbeat expecting at least heart beat is send. Actually, I have installed QGC released version and using MAVLink version 1 packets.

Will you guys be able to post some examples showing binary/hexa messages to make sure I am doing everything fine.

Thanks,
Madu

You should write a program that will tell you the status of parsing messages, as well as show you the raw data, then you will be able to see what is going wrong. We cannot make an example like this, it is too low-level and application specific. You should refer to the current implementations in the source code of programs like QGC, MAVProxy, and ArduPilot.

For future reference for people who find this thread, I wrote up an example connection between an Arduino-compatible controller and QGroundControl:

1 Like

Hi Dan,

Thank you for sharing this with the community !