Sending and recieving heartbeats to BlueROV from surface computer using pymavlink

Generally our first support response when someone has issues with software that’s older than the latest stable version is to ask them to update so we have an understood baseline to work from.

That post (which was also made in 2017) is specifically referring to updating to ArduSub 3.5. ROVs bought later than June 2017 would already be on ArduSub 3.5 or later, so they don’t need to update to ArduSub 3.5. That’s unrelated to the new releases we’ve made since then, including various bug fixes, improvements, and new features :slight_smile:

I’m not sure why you’re unable to access wifi, but there have been a few different issues with that for previous versions of Companion. Yes, I’d recommend you manually flash 0.0.29 onto your Companion SD card using our Installing Companion instructions :slight_smile:

Once that’s complete you’ll then need to:

  1. Connect Companion to wifi (should hopefully now be possible)
  2. Update Companion to 0.0.30 from the System page (should be quite a quick update; we haven’t built an image for 0.0.30 because 0.0.31 is planned for release very soon, but it fixes an external issue that stops ArduSub firmwares from downloading so is required)
  3. Update your ArduSub firmware to the latest Stable (4.0.3)

Your Actual Issue

While I would still recommend you upgrade your software, your actual issue here is the time.sleep(.2) call. Pymavlink is just receiving the mavlink messages that mavproxy sends (i.e. it’s not requesting anything), and attitude messages are generally sent faster than the 5Hz that you’re getting+printing messages at. That means your computer is collecting messages faster than you’re processing them, and each time you request the next one it gives you the oldest one it’s got (which leads to the large (and growing) delay between when you move the ROV vs when those moves show up in the printed values).

There are multiple ways of dealing with that, but the main principle is making sure you read the values faster than they’re arriving, so your program doesn’t fall behind. Likely the most intended way (including how the pymavlink developers would probably want heartbeats to be handled) is with periodic events that only trigger at their desired frequency:

from pymavlink import mavutil
import time

# --out udpout:192.168.2.1:14660 in http://192.168.2.2:2770/mavproxy list
master = mavutil.mavlink_connection('udpin:0.0.0.0:14660')
# ensure valid connection
master.wait_heartbeat()

heartbeat = mavutil.periodic_event(1) # 1 Hz heartbeat
display = mavutil.periodic_event(5) # 5 Hz output (every 0.2 seconds)

start = time.time()
duration = 160 # seconds

while time.time() - start < duration:
    if heartbeat.trigger():
        master.mav.heartbeat_send(
            mavutil.mavlink.MAV_TYPE_GCS,
            mavutil.mavlink.MAV_AUTOPILOT_INVALID,
            0,0,0)
    
    # read messages every iteration (to not fall behind)
    att = master.recv_match(type='ATTITUDE', blocking=True)
    
    if display.trigger():
        print(att.roll, att.pitch, att.yaw)

I would note that while having the heartbeat in a separate thread can definitely be convenient, it’s not recommended as the default approach in the mavlink docs, and is also the main issue that’s been raised with my mavactive.py proposal. The reasoning behind that is almost certainly that threads make debugging harder, and could in theory allow regular heartbeats to continue when the vehicle/controller is not in fact still ok/healthy.

I personally think that should be an individual choice (e.g. if you’re comfortable with threads and understand the potential pitfalls you could choose to use them when it’s appropriate), but I agree that threads aren’t perfect for heartbeats “in general”, and should be used carefully (if at all).