Mavlink code in python won't work properly when QGC is not running

Hello,

I have an issue when trying to run code in python. More specifically, the code is running properly when QGC is running but if i close it there are some commands that do not work properly.

I have repetedly tested and siplified to the below code in order to understand the issue:

1. from time import sleep
2. from pymavlink import mavutil

3. master = mavutil.mavlink_connection('udpin:0.0.0.0:10000')
4. boot_time = time.time()

5. print("Waiting heartbeat...")
6. master.wait_heartbeat()
7. print("-- Heartbeat received --")

8. master.arducopter_arm()
9. sleep(0.5)
10. master.arducopter_arm()
11. print("Waiting arm confirmation...")
12. master.motors_armed_wait()
13. print("-- ARMED --")

14. #send_rc(*[1500]*6)
15. #sleep(4)
16. send_rc(forward=1600)
17. sleep(2)
18. send_rc(*[1500]*6)
19. sleep(4)
20. send_rc(forward=1600)
21. sleep(2)
22. send_rc(*[1500]*6)

23. master.arducopter_disarm()
24. print("Waiting disarm confirmation...")
25. master.motors_disarmed_wait()
26. sleep(0.2)
27. print("-- DISARMED --")

28. master.close()
29. print("disconnected")

If i run this code simultaneously with QGC it works just fine. But with QGC closed the code doesn’t work.
I figured out that the issue happens when I stop all the channels and then sleep for more than 2 seconds.
eg. If I change the duration of sleep() in line 19 to 2 seconds instead of 4 the programm will run properly (even with QGC closed). But with sleep(4) the line 20 will be excecuted (I can see the printed channels) without turning the motors on.

eg.2. If I uncomment lines 14-15 the motors will never work with QGC closed. But it will work when QGC is running.

The function send_rc() is given below:

def send_rc(rcin1=65535, rcin2=65535, rcin3=65535, rcin4=65535,
            rcin5=65535, rcin6=65535, rcin7=65535, rcin8=65535,
            rcin9=65535, rcin10=65535, rcin11=65535, rcin12=65535,
            rcin13=65535, rcin14=65535, rcin15=65535, rcin16=65535,
            rcin17=65535, rcin18=65535,
            pitch=None, roll=None, heave=None, yaw=None, forward=None,
            lateral=None, camera_pan=None, camera_tilt=None, lights1=None,
            lights2=None, video_switch=None):

    # Creates a tuple of commands for each channel
    # with MAX_INT ignores the channel change
    rc_channel_values = (
        pitch        or rcin1,
        roll         or rcin2,
        heave     or rcin3,
        yaw          or rcin4,
        forward      or rcin5,
        lateral      or rcin6,
        camera_pan   or rcin7,
        camera_tilt  or rcin8,
        lights1      or rcin9,
        lights2      or rcin10,
        video_switch or rcin11,
        rcin12, rcin13, rcin14, rcin15, rcin16, rcin17, rcin18
    )

    print(rc_channel_values)
    master.mav.rc_channels_override_send(
        *(master.target_system,  # target_system
            master.target_component),
        *rc_channel_values
    )

I really don’t know why the code doesn’t work when I stop all the channels for more than 2 seconds and then try to send speed to one of them.

I have RPi3 and Px4 configuration. I also own the new navigator+rpi4 but I haven’t tested this code with it yet.

Thank you for your time,
Marios

Hi @Marios,

Our documentation is currently in a transition to a new system, with some revisions while transferring. The revised Pymavlink docs should make this kind of thing more obvious, but the general ArduSub and BlueOS documentation are higher priority so are being completed first.

Eliot,

Are there currently any best practices laid out for trying to control a BlueROV through Pymavlink? My team has run into a similar issue where we wait for a data response from the Ping360 while running the ROV. This is done synchronously with the movement commands, so if the Ping360 times out, the ROV disarms and we have to completely reset.

We thought about a janky work around using a separate thread in the main application to send a heartbeat at 1Hz, but that seems unwieldy.

The current pymavlink documentation and example sections I’m aware of are

I wouldn’t really class any of those as examples of best practices at the moment, which is part of why I’m planning to revise our examples documentation when I transfer it over - good practice full program examples seem like they would be beneficial. It is somewhat unhelpful that ArduPilot’s examples maintain backwards compatibility with quite old versions of Python, which means newer Python features are only covered in external examples.

I’ve got a reasonably extensive example which takes that approach, but there are some notes at the bottom about why that’s not necessarily recommended, and an alternative (synchronous) approach.

@patrickelectric has also made an example using asyncio. I expect asyncio is likely the best approach for the main thread of more complex MAVLink-based programs going forwards.

1 Like

Thank you for your immidiate response. That was the problem.

I added the following code (just for testing) in a thread and it worked:

def heartbeat_repeat():
    while True: 
        master.mav.heartbeat_send(mavutil.mavlink.MAV_TYPE_GCS,
                                  mavutil.mavlink.MAV_AUTOPILOT_INVALID, 0, 0, 0)

        print("heartbeat sent")
        time.sleep(0.8)

Looking forward for the revised Pymavlink docs. Btw the new navigator is really handy.

Best Regards,
Marios

2 Likes