Connect to drone via HereLink and Drone-kit Python

Hello all,

My drone flies fine with the HereLink. I can connect it to Mission Planner without issue as well. I have done this via WiFi where the controller and laptop are on the same network. For whatever reason, I can’t get USB tethering to work - but thats not my most emergent issue. I need to execute a Python mission script and use the HereLink as a radio to the drone. When I use the RFD-900x, it shows up as an actual USB device and the connection string is easy. With the HereLink because the only way I can connect is via WiFi, when trying a TCP connection of the HereLink ip address, it just says “No connection could be made because the target machine actively refused it.”

I am somewhat at a loss now as I don’t know what I need to put in the vehicle connection string in Python to connect to the HereLink to use it as a radio to talk to the drone via MavLink.

Any thoughts, pointers, suggestions?

Thank you!

I think you would need to verify the connectivity to Mission Planner first
https://docs.cubepilot.org/user-guides/herelink/herelink-user-guides/connect-to-mission-planner

Then you can use the same IP address to connect as UDPCI. Once connected, the mavlink traffic should be visible.

Yep, no issue connecting via MP on the same machine. Using the exact same connection ip, protocol, and baud rate results in rejected message (I need to reconfirm that’s it) but it fails to connect.

Can you try if you can connect via mavproxy?

So with mavproxy, I can connect using “–master=udpout:192.168.1.106:14552” and everything works as expected. So I used that string without the master flag in Python for Dronekit and get the following - I have tried different baud rates with the same results:

vehicle = connect('udpout:192.168.1.106:14552', wait_ready=True,baud=57600)
C:\Users\munsterlander\PythonProjects\Drone>python TestTelemetry.py
WARNING:dronekit:Link timeout, no heartbeat in last 5 seconds
ERROR:dronekit:Exception in message handler for HEARTBEAT
Traceback (most recent call last):
  File "C:\Users\munsterlander\AppData\Local\Programs\Python\Python36-32\lib\site-packages\dronekit\__init__.py", line 1531, in notify_message_listeners
    fn(self, name, msg)
  File "C:\Users\munsterlander\AppData\Local\Programs\Python\Python36-32\lib\site-packages\dronekit\__init__.py", line 1223, in listener
    raise APIException("mode (%s, %s) not available on mavlink definition" % (m.custom_mode, m.base_mode))
dronekit.APIException: mode (33554829, 0) not available on mavlink definition
ERROR:dronekit:Exception in message handler for HEARTBEAT
Traceback (most recent call last):
  File "C:\Users\munsterlander\AppData\Local\Programs\Python\Python36-32\lib\site-packages\dronekit\__init__.py", line 1531, in notify_message_listeners
    fn(self, name, msg)
  File "C:\Users\munsterlander\AppData\Local\Programs\Python\Python36-32\lib\site-packages\dronekit\__init__.py", line 1223, in listener
    raise APIException("mode (%s, %s) not available on mavlink definition" % (m.custom_mode, m.base_mode))
dronekit.APIException: mode (0, 0) not available on mavlink definition
ERROR:dronekit:Exception in message handler for HEARTBEAT

Edit: So I actually think this is connecting now and this is a python library issue.
Edit2: I just feel this has to be connecting and there is a library issue or something because I have tried Python 2 and 3 - same results - but if you change the port or protocol, you get different messages and this will keep dumping that message over and over again like a heartbeat, so it seems to me its connecting now and on to a different issue.
Edit3: Yup, I deem this a success because: https://github.com/dronekit/dronekit-python/issues/1024

So in short, I needed to specify udpout in the connection string and not just udp. Mavproxy was the ticket to discovering this. Thank you @Alvin

Ok, so tons of digging and going down deep the rabbit hole, lets me know that the issue is the ADSB carrier board or the firmware or whatever, does not play nice with PyMavlink or Dronekit (which wraps pymavlink). The Heartbeat can never be deciphered and basically throws this error: dronekit.APIException: mode (0, 4) not available on mavlink definition which in turn, if you go raw with the dump in Python with pymavlink yields this: <pymavlink.dialects.v10.ardupilotmega.MAVLink_heartbeat_message object at 0x0344CA70> which ultimately I have gathered that this board is not fully supported in the mavlink messages. I have tried all the suggestions to disable ADS-B but it doesn’t change the message format back. Now this is all a little weird to me as I suspect this is a firmware issue, so who knows the outcome.

Honestly, feeling really down about this all because we were so close but now we may have to change FC’s to try and get this working. Bummer.

The only change made on ADS-B carrier board is that ADS-B chip occupied serial 5 (console) port. There’s shouldn’t be any compatible issue just because of the board.

Are you using mavlink1 or mavlink2 as protocol?

I’ve tried mav1, mav2, and none. I rebooted each time. I did that on serial 2 (I think it was the one set for telem2) and serial 5. No luck on either of the settings.

Edit: I decided to go back to the shop tonight and try it one more time to make sure. Serial5_protocol was set to -1 and Serial2_protocol was set to 2 (I also tried 1). Both times, same error message.

Earlier when I dug into the code of Pymavlink and Dronekit, I could see where the heartbeat is being processed and I followed it all the way up to the dictionary that is loading. This is what is being called that throws the error:

    def _is_mode_available(self, custommode_code, basemode_code=0):
        try:
            if self._autopilot_type == mavutil.mavlink.MAV_AUTOPILOT_PX4:
                mode = mavutil.interpret_px4_mode(basemode_code, custommode_code)
                return mode in self._mode_mapping
            return custommode_code in self._mode_mapping_bynumber
        except:
            return False

And when you look at _mode_mapping_bynumber:

def mode_mapping_bynumber(mav_type):
    '''return dictionary mapping mode numbers to name, or None if unknown'''
    return AP_MAV_TYPE_MODE_MAP[mav_type] if mav_type in AP_MAV_TYPE_MODE_MAP else None

Which then needs:

AP_MAV_TYPE_MODE_MAP_DEFAULT = {
    # copter
    mavlink.MAV_TYPE_HELICOPTER:  mode_mapping_acm,
    mavlink.MAV_TYPE_TRICOPTER:   mode_mapping_acm,
    mavlink.MAV_TYPE_QUADROTOR:   mode_mapping_acm,
    mavlink.MAV_TYPE_HEXAROTOR:   mode_mapping_acm,
    mavlink.MAV_TYPE_OCTOROTOR:   mode_mapping_acm,
    mavlink.MAV_TYPE_DECAROTOR:   mode_mapping_acm,
    mavlink.MAV_TYPE_DODECAROTOR: mode_mapping_acm,
    mavlink.MAV_TYPE_COAXIAL:     mode_mapping_acm,
    # plane
    mavlink.MAV_TYPE_FIXED_WING: mode_mapping_apm,
    # rover
    mavlink.MAV_TYPE_GROUND_ROVER: mode_mapping_rover,
    # boat
    mavlink.MAV_TYPE_SURFACE_BOAT: mode_mapping_rover, # for the time being
    # tracker
    mavlink.MAV_TYPE_ANTENNA_TRACKER: mode_mapping_tracker,
    # sub
    mavlink.MAV_TYPE_SUBMARINE: mode_mapping_sub,
    # blimp
    mavlink.MAV_TYPE_AIRSHIP: mode_mapping_blimp,
}

And this is what I think is failing, because it is passing 0 from the error message, I believe it is returning HELICOPTER and not a quadcopter. Now, the the frame class is set to 1 (quad) and the board type is set to 3 (Cube).

So in short, all I am thinking is that the firmware is sending either the wrong data in the mav message or something isn’t mapped correctly. Either way, I have another pixhawk 2.4.8 board that does not have this issue running 4.1.1. So either there is a config issue or something is malformed. The end result though, is we have not been able to connect via HereLink or Sik radio via Python completely.

I tried to replicate it and successfully created the failures

image

At first, I tried mavproxy to verify if the network is connecting

mavproxy.py --master=udpout:192.168.1.103:14552

It works, so udp connection should be perfect.

Then I tried pymavlink

import time
from pymavlink import mavutil

master = mavutil.mavlink_connection("udpout:192.168.1.103:14552")

master.mav.ping_send(
    int(time.time() * 1e6), # Unix time in microseconds
    0, # Ping number
    0, # Request ping of all systems
    0 # Request ping of all components
)

master.wait_heartbeat()

while True:
    try:
        print(master.recv_match().to_dict())
    except:
        pass
    time.sleep(0.1)

It works too. The ping is necessary to get the heartbeat, otherwise it stuck forever.

After that I tried dronekit

connection_string = 'udpout:192.168.1.103:14552'

from dronekit import connect, VehicleMode

print("Connecting to vehicle on: %s" % (connection_string))
vehicle = connect(connection_string, wait_ready=True, source_system=1)

vehicle.wait_ready('autopilot_version')

print (" Last Heartbeat: %s" % vehicle.last_heartbeat)
print (" System status: %s" % vehicle.system_status.state)
print (" Mode: %s" % vehicle.mode.name)    # settable

vehicle.close()

print("Completed")

It doesn’t work.
Then I found this discussion suggesting that old version of Ardupilot used to work. So I loaded Arducopter 3.6.9 into the Cube and tried again.

Now it is definitely receiving messages from my Cube, but the errors spammed the communication.
These few lines are not appearing in Ardupilot 4.0.0. So maybe firmware version is also a factor. Maybe most of the message became unrecognizable for the dronekit. The discussion above also says that building dronekit from source will solve the problem.

By the way, I am using CubeBlack and the old standard carrier board. They are old enough and still having the same issue, so I don’t think the Orange or ADS-B carrier board cause the problem.

Ah, I didn’t know the ping part. Ok, I will try that again and it looks like it’s time to move on from drone kit and just stick to pymavlink.

@Alvin THANK YOU THANK YOU! It was just the ping. I must have completely missed that in the docs, but the script connects and dumps out the values now. Amazing and now we can move forward!