Hi @clyde, you have a knack for finding fascinating problems it seems 
After a bit of sleuthing:
MAVLink_message
objects have their _instances
attribute set to None
by default
- Your error line can only run if a message is received that has an instance field set (
msg._instance_field is not None
), and is of a type that’s been seen before in this set of messages
- Your error can only occur if
msg._instances is None
, which implies the previous time the message type was seen it had a None
value for its _instance_field
(so was added directly to the messages dictionary via the “simple” case, without bothering to set up an _instances
dictionary), but the current time it has a non-None
_instance_field
value which it then fails to put into the corresponding _instances
None
object which it expects to be a dictionary
This seems like a failure case that pymavlink could quite easily be robust to, but having a message that sometimes does and sometimes doesn’t have an instance field* specified is also very weird, and likely doesn’t make sense within the MAVLink specification.
*Note: I didn’t know what exactly “instance field” was referring to, but after looking through some of the message definitions it’s about what it sounds like - things like the “compass_id” field for compass messages, and the “name” field for NAMED_VALUE_FLOAT
messages so that it’s possible to distinguish between different instances covered by the same broad message type.
Beyond that, as far as I can tell the instance field is a class attribute, so I’m not sure how two messages of the same type could end up with different values for the _instance_field
attribute unless they’re not the same class (which could conceivably occur if a message gained an instance field in a more recent MAVLink version, since pymavlink dynamically changes the current MAVLink version depending on the messages it’s receiving/processing).
I tried finding messages that are in both v1.0 and v2.0 but have changed their instance field, and it turns out there are a couple of IMU messages that fit the bill:
from pymavlink.dialects.v10 import ardupilotmega as v10
from pymavlink.dialects.v20 import ardupilotmega as v20
v10_instance_fields = {msg_type: getattr(msg_class, 'instance_field', None)
for msg_type, msg_class in vars(v10).items()
if msg_type.startswith('MAVLink')}
v20_instance_fields = {msg_type: getattr(msg_class, 'instance_field', None)
for msg_type, msg_class in vars(v20).items()
if msg_type.startswith('MAVLink')}
for msg_type, old_instance_field in v10_instance_fields:
new_instance_field = v20_instance_fields[msg_type]
if old_instance_field != new_instance_field:
print(f'{msg_type} - v10: {old_instance_field}; v20: {new_instance_field}')
which yielded
MAVLink_raw_imu_message - v10: None; v20: id
MAVLink_highres_imu_message - v10: None; v20: id
I suspect you’re running into something like this, but it’s still not super clear to me why that would be happening, since generally the autopilot should be consistently sending messages from the same MAVLink version. I wonder if there’s a BlueOS service that’s accidentally using MAVLink 1.0…
Out of interest,
- Does turning off
--quiet
allow you to find out which message type it’s failing on?
- Are you able to upload one breaking and one ok tlog file?
I suspect the simplest fix for your issue would be changing the mavutil
mtype check to also check for _instances
, e.g.
if mtype not in messages or messages[mtype]._instances is None:
If it works and you submit that as a PR to pymavlink it’s probably worth including a comment above that line with some context, or at least linking to this discussion in the PR description 