Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using COMPONENT_INFORMATION to obtain vehicle metadata #1346

Closed
DonLakeFlyer opened this issue Apr 18, 2020 · 61 comments
Closed

Using COMPONENT_INFORMATION to obtain vehicle metadata #1346

DonLakeFlyer opened this issue Apr 18, 2020 · 61 comments

Comments

@DonLakeFlyer
Copy link
Contributor

DonLakeFlyer commented Apr 18, 2020

This is the higher level proposal related to #1339 for how you get the various pieces of metadata which a GCS needs from a connected vehicle. I've also included my proposed spec for the parameter metadata json format.

Vehicle metadata request protocol

  • GCS sends MAV_CMD_REQUEST_MESSAGE.param1 = COMPONENT_INFORMATION MAV_CMD_REQUEST_MESSAGE.param2 = COMP_METADATA_TYPE_VERSION to the vehicle
  • If comp_metadata_uid is not already cached GCS does ftp download from specified vehicle uri.
  • GCS sends MAV_CMD_REQUEST_MESSAGE.param1 = ... for each optional metadata it wants. Including the cache dance semantics.

MAV_CMD_REQUEST_MESSAGE

Notes:

  • I think param2-6 should all be "The use of this parameter (if any), must be defined in the requested message. By default assumed not used (0).".
  • I don't think it makes sense for param2 to be "Index id (if appropriate). The use of this parameter (if any), must be defined in the requested message.".

COMPONENT_INFORMATION

Notes:

  • The removal of all fields other than what is needed to download metadata files. The fields that were previously include here are now part of the COMP_METADATA_TYPE_VERSION type metadata file spec.
  • The type of requested metadata is specified in MAV_CMD_REQUEST_MESSAGE.param2
Type Field Description
uint32_t time_boot_ms Timestamp (time since system boot)
uint32_t comp_metadata_type The type of metadata returned (COMP_METADATA_TYPE).
uint32_t comp_metadata_uid Unique uid for this metadata which a gcs can use for created cached metadata and understanding whether it's cache it up to date or whether it needs to download new data.
char[140] component_metadata_uri Component definition URI. If prefix mavlinkftp:\\ file is downloaded from vehicle over mavlink ftp protocol. If prefix http[s]:\\ file is downloaded over internet. Files are json format. They can end in .gz to indicate file is in gzip format.
uint32_t comp_translation_uid Unique uid for the translation file associated with the metadata.
char[140] component_translation_uri The translations for strings within the metadata file. If null the either do not exist or may be included in the metadata file itself. The translations specified here supercede any which may be in the metadata file itself. The uri format is the same as component_metadata_uri . Files are in Json Translation spec format.
MAV_CMD_REQUEST_MESSAGE.param1 specifies requested COMP_METADATA_TYPE.

COMP_METADATA_TYPE (enum)

Support for COMP_METADATA_TYPE_VERSION is required all other types are optional.

Value Field Name Description
0 COMP_METADATA_TYPE_VERSION Required: Version information which also includes information on other optional supported COMP_METADATA_TYPE's. Must be supported. Only downloadable from vehicle.
1 COMP_METADATA_TYPE_PARAMETER Parameter meta data.
2 COMP_METADATA_TYPE_COMMANDS Command meta data. Supported commands and so forth.
... COMP_METADATA_TYPE_... ...

Metadata file formats

Notes:

  • I did my best on the regex pattern matching. I'm sure I screwed some of them up, but I think they are close enough to show intent.

COMP_METADATA_TYPE_VERSION

Notes:

  • This specifies the list of supporteds optional COMP_METADATA_TYPE information.
  • It also includes the information which was removed from the current mavlink COMPONENT_INFORMATION spec.
{
    "$id": "https://mavlink.io/comp_version.schema.json",
    "$schema": "http://json-schema.org/draft-07/schema",
    "description": "...",
    "type": "object",
    
    "properties": {
        "version": {
            "description": "Version number for the format of this file."
            "type": "integer",
            "minimum": 1
        },
        "vendorName": {
            "type": "string",
            "description": "Name of the component vendor."
        },
        "modelName": {
            "type": "string",
            "description": "Name of the component model."
            },
        "firmwareVersion": {
            "type": "string",
            "pattern": "^\d+\.\d+\.\d+(\.\d+)?$"
            "description": "major.minor.patch.dev format"
        },
        "hardwareVersion": {
            "type": "string",
            "pattern": "^\d+\.\d+\.\d+(\.\d+)?$"
            "description": "major.minor.patch.dev format"
        },
        "supportedCompMetadataTypes": {
            "type": "array",
            "description": "Which ```COMP_METADATA_TYPE``` specs are supported.",
            "items": {
                "type": "integer"
            }
        }
    }
} 

COMP_METADATA_TYPE_PARAMETER

Notes:

  • It the specified "units" are one of the mavlink spec know unit types (which I'm not sure is defined elsewhere yet) then a GCS can transformat the value from say "meters" to "ft" as needed.
  • For the "type" field I have only listed the type specified in MAV_TYPE. But now is the time to extend to provide additional information beyond that simplest of info. This should follow what is happening with respect to defining additional COMMAND_LONG parameter metadata.
{
    "$id": "https://mavlink.io/comp_version.schema.json",
    "$schema": "http://json-schema.org/draft-07/schema",
    "description": "Parameter MetaData",
    "type": "object",
    
    "properties": {
        "version": {
            "description": "Version number for the format of this file."
            "type": "integer",
            "minimum": 1
        },
        "uid": {
            "description": "Unique id for this metadata. Same as ```COMPONENT_INFORMATION. comp_metadata_uid```."
            "type": "integer"
        },
        "scope": {
            "description": "Scope to which this metadata applies. Firmware: Any vehicle running this same vehicles firmware type. VehicleGroup: Any vehicle running this same firmware and this vehicles group type (Fixed Wing, Multi-Rotor, VTOL, Rover). VehicleType: Any vehicle match this vehicles firmware type and specific vehicle type. Vehicle: Only applies to this specific vehicle."
            "type": "string",
            "enum": ["Firmware", "VehicleGroup", "VehicleType", "Vehicle" ]
        },
        "parameters": {
           "type": "array",
                       
            "properties": {
                "name": {
                    "description": "Parameter Name.",
                    "type": "string",
                    "pattern": "^[a-zA-Z0-9_]{1,16}$"
                },
                "type": {
                    "description": "Parameter type.",
                    "type": "string",
                    "enum": ["Uint8", "Int8", "Uint16", "Int16", "Uint32", "Int32", "Float" ]
        },
                "shortDescription": {
                    "description": "Short user facing description/name for parameter. Used in UI intead of internal parameter name.",
                    "type": "string"
                },
                "longDescription": {
                    "description": "Long user facing documentation of how the parameters works."
                    "type": "string"
                },
                "units": {
                    "description": "Units for parameter value."
                    "type": "string"
                },
                "defaultValue": {
                    "description": "Default value for parameter.",
                    "type": "number"
                },
                "decimalPlaces": {
                    "description": "Number of decimal places to show for user facing display.",
                    "type": "integer",
                    "minimum": 0
                },
                "min": {
                    "description": "Minimum valid value",
                    "type": "number"
                },
                "max": {
                    "description": "Maximum valid value",
                    "type": "number"
                },
                "increment": {
                    "description": "Increment to use for user facing UI which increments a value",
                    "type": "number"
                },
                "rebootRequired": {
                    "description": "true: Vehicle must be rebooted if this value is changed",
                    "type": "boolean"
                },
                "group": {
                    "description": "User readable name for a group of parameters which are commonly modified together. For example a GCS can shows params in a hierarchical display based on group ",
                    "type": "string"
                },
                "category": {
                    "description": "User readable name for a 'type" of parameter. For example 'Developer', 'System', or 'Advanced'.",
                    "type": "string"
                },
                "volatile": {
                    "description": "Value is volatile. Should be included in creation of a CRC over param values for example.",
                    "type": "boolean"
                },
                "values": {
                    "description": "Array of values and textual descriptions for use by GCS ui.",
                    "type": "array",
                    "properties": {
                        "value": {
                            "type": "double"
                        },
                        "description": {
                            "type": "string"
                        },
                    }
                },
            },
            "required": ["name", "type"],
            "additionalProperties": false
        }
        "additionalProperties": false
    }

Json Translations Format

String translations for a metadata file can either be included directly in the metadata file, be in a standalone file or in both places. If in both places, the external translations supercede the internal transations. If they are included directly in a metadata file that file would have a top level "translations" object which follows this spec.

A case where it is better the include them in both places is for long strings. For example the longDescription key in a parameter metadata file can contain quite a long string. You don't want to have to duplicate that long string in all the translations.original instances. Instead you do the following:

Instead of putting the actual long description for the parameter in the metadata you put a unique string which help to describes the string context:
"longDescription": "MAV_SYS_ID-longDescription"

Within the parameter metadata file there is a "translations" section for "en_US" locale which translates from the unique string to the real english description:

"translations" : {
    {
        "original":     "MAV_SYS_ID-longDescription",
        "translation":  "The MAVLink Mode defines the set of streamed messages (for example the vehicle's attitude) and their sending rates."
    }
}

And then the standalone translations file also uses the "MAV_SYS_ID-longDescription" reference as the "original" string for it's translations. But the person doing the translations can still go back to the english text to base there translation on. This also prevents needing to update the translations when the english version of the string changes. Which begs the question as to whether this mechanism should always be used.

{
    "$id":          "https://mavlink.io/comp_version.schema.json",
    "$schema":      "http://json-schema.org/draft-07/schema",
    "description":  "String Translations",
    "type":         "object",
    
    "properties": {
        "version": {
            "description":  "Version number for the format of this file."
            "type":         "integer",
            "minimum":      1
        },
        "uid": {
            "description":  "Unique id for this metadata. Same as ```COMPONENT_INFORMATION.comp_tranlsation_uid```."
            "type":         "integer"
        },
        "localizations": {
           "type": "array",
            "locals": {
                "type": "array",
                "properties": {
                    "name": {
                        "description":  "locale name: de_DE, en_US, ...",
                        "type":         "string"
                    },
                "keyScope": {
                    "description":  "List of keys for which these translations apply to. Example: shortDescription,longDescription."
                    "type":         "string"
                },
                "translations": {
                    "description":  "String translations",
                    "type":         "array"
                    "properties": {
                        "original": {
                        "description":  "Original string",
                        "type":         "string"
                    },
                    {
                        "translated": {
                        "description":  "Translated string",
                        "type":         "string"
                    },
                },
            },
        }
    }
@dagar dagar assigned dagar and unassigned dagar Apr 18, 2020
@hamishwillee
Copy link
Collaborator

Don, thanks - really appreciate you taking the lead. We need you!

Re "Vehicle metadata request protocol"

In the dev call we suggested that we might have just one hash and always query the whole file. The argument was that this is a pre-arm/non-flying query, so bandwidth consumption etc isn't relevant. However I don't think that is correct - this query gets made when the GCS connects, so it could happen when flying or any time. @auturgy @julianoes Did I misunderstand?

My thinking is that giving it the GCS the choice to query parts of the file is more flexible - and nothing stops us from giving it an option to query everything?

Re MAV_CMD_REQUEST_MESSAGE notes -

This doesn't break anything, except that if we do this we would need to update each message that takes an index to specify the field for the index. That's one reason this exists - to minimise the churn on other docs to support the use case.

To me this looks better.

Re COMPONENT_INFORMATION

Depends on what is agreed above.

Some points though:

  • component_metadata_uri is currently assuming XML not Json. Probably not too late to change but OllieW already working on this.
  • time_boot_ms - @julianoes Do you know why we thought we would need this?
  • comp_metadata_uid if this just a hash of the file for the type? If so we should call it that. Also explain how it is calculated.

Re COMP_METADATA_TYPE (enum)

FYI only, we're currently working on first type bing "supported_mission_commands"

Other ideas:

  • metadata about "parameters used for standard things" - e.g. many autopilots use completely equivalent parameters for battery settings, but you can't guess at those. We should standardise the interfaces, but another option is to perhaps to simply identify what those parameters are called.
  • metadata about missions as previously discussed - e.g. default cruise speed.
  • Does it make sense to have metadata about metadata? For example, currently we have 32 bits reserved for indicating types of metadata - is that enough? What about 64? Can we just say that you can query for additional metadata types by using COMP_METADATA_TYPE_METADATA_LIST?

Re COMP_METADATA_TYPE_VERSION

  • Some duplication with what is returned in COMPONENT_INFORMATION. Is that useful?
    -e.g. Why supportedCompMetadataTypes when you have the COMPONENT_INFORMATION.capability_flags
    • One benefit of this might be to provide metadata about metadata in the file. At the moment the capability_flags allows 32 bits, which might not be enough. We could set one bit in COMPONENT_INFORMATION.capability_flags to indicate - other metadata fields are supported, but you need to read the file to get them.

Re COMP_METADATA_TYPE_PARAMETER

How do we currently get metadata, and why is this better?

My concerns are size of info on firmware needed for this, and making sure that we can support translation.

@DonLakeFlyer
Copy link
Contributor Author

The argument was that this is a pre-arm/non-flying query, so bandwidth consumption etc isn't relevant.

I don't see it as having much to do with bandwidth consumption. In fact if the vehicle is flying I would contend you want to skip doing this all-together possibly. I see it having to do with the amount of time it takes from connect to the vehicle being ready for use. The bigger the download is the slower that will be. I'm not going to want to download a pile of stuff over a SiK radio unless I really need to. Also by creating only a single entity you are increasing the likelihood of needing a re-download. Even if one smaller bit of it changes you then still need to change everything. I'd expect some of this stuff will be more stable than other parts and not change much.

All of that said it can certainly work as a single entity.

  • component_metadata_uri is currently assuming XML not Json. Probably not too late to change but OllieW already working on this.

Lorenz's mission command proposal is json so I went with that. In general I find json much easier to deal with though in code, also the the json schema stuff seems pretty straightforward as well.

FYI only, we're currently working on first type bing "supported_mission_commands"

I would contend that parameter meta is just as important since it already exists whereas "supported mission commands" does not exist in anyplace other than gcs code.

  • Some duplication with what is returned in COMPONENT_INFORMATION. Is that useful?

There is no duplication with my reworked COMPONENT_INFORMATION. My definition above is a completed replacement for the existing WIP defiuniction of COMPONENT_INFORMATION.

COMP_METADATA_TYPE_PARAMETER -How do we currently get metadata, and why is this better?

There is no mavlink spec as to how to get parameter metadata. It's all firmware specific. PX4 has a format for it and ArduPilot has a different format for it. Where you get it and how you use it in a GCS is different for each firmware. There is no mechanism for example to deal with a vehicle which has new firmware on it which may need new parameter metadata. You just hope for two things:

  1. You are running a GCS which maybe already knows about this firmware and hence has the metadata for it compiled in.
  2. You flashed a newer PX4 firmware onto a vehicle using the same computer that you are flying with. In which case it would have been cached. But totally fragile and non-generic.

@hamishwillee
Copy link
Collaborator

hamishwillee commented Apr 20, 2020

Thanks @DonLakeFlyer - lots of things I didn't know.. Do you think you might be able to attend a meeting specifically to lock all this down - ideally the MAVLink call, but if not, another?

A few thoughts:

  1. Defining a common parameter metadata format clearly makes sense then,.
    • I still feel it needs to address translation and size of firmware issues to hold the info. ie. quite reasonably if this is huge and only of interest to a GCS you might want it on an HTTPS server not mavFTP, but still want the rest on the vehicle.
    • Can the metadata change on reboot? What I'm considering is whether the metadata itself (e.g. description, type) might be separately stored, but the state of the metatdata - this set of params are valid - could be on the vehicle.
  2. I don't know if we can change to JSON. I think probably yes at this point. We don't want to force people to chop and change. It is XML only because this copies the camera definition file format.
  3. The question about what metadata is in the message and what is in the file is a good one. For the camera API the separation was based around "info that is common to every system is in the message, so that someone can set up a basic system without having to support mavftp etc". Not sure there is any such info for a component - ie. what might you need to know about every component even if they did not support definition file download

@DonLakeFlyer
Copy link
Contributor Author

Do you think you might be able to attend a meeting specifically to lock all this down - ideally the MAVLink call, but if not, another?

Sure, just give me a time and how. to connect.

@DonLakeFlyer
Copy link
Contributor Author

2. I don't know if we can change to JSON.

There is no reason why both JSON and XML can be supported. My opinion would be for new things which don't currently exist json is a better choice.

@DonLakeFlyer
Copy link
Contributor Author

  1. Defining a common parameter metadata format clearly makes sense then

Also I should have said that my proposal is essentially the data QGC stores for parameter meta data which was designed to support both current PX4 and ArduPilot metadata implementations.

@julianoes
Copy link
Collaborator

@DonLakeFlyer thanks!

Component definition URI. If prefix ftp:\ file is downloaded from vehicle. If prefix http[s]:\ file is downloaded over internet. Files are json format.

I would use mavlinkftp:// not to confuse it with "real" FTP, or mftp:// if it needs to be that short.

They can end in .zip to indicate file must be unzipped prior to use.

I would not use a .zip archive but just compress the file stream with gzip, so it becomes .json.gz.

I'm not going to want to download a pile of stuff over a SiK radio unless I really need to. Also by creating only a single entity you are increasing the likelihood of needing a re-download. Even if one smaller bit of it changes you then still need to change everything. I'd expect some of this stuff will be more stable than other parts and not change much.

Makes sense, I agree.

However, while we're talking about file size, we should consider localization which is currently possible for the camera definition file but not addressed here yet. In the ideal case where a couple of languages have been added this causes the file to blow up quite a bit (see example). Therefore, we could consider stripping unused languages before sending it if the request contains the favored language.

@DonLakeFlyer
Copy link
Contributor Author

I updated to switch to mavlinkftp:// and to gzip compression.

However, while we're talking about file size, we should consider localization which is currently possible for the camera definition file but not addressed here yet.

There currently is a ton of un-loced json in QGC already, so it needs support for that anyway. The same thing would work in json since it's just a simple string matching table. Is there tooling around loc support for xml camera files? Or is it just people editing the file directly to add the loc strings?

@julianoes
Copy link
Collaborator

Is there tooling around loc support for xml camera files? Or is it just people editing the file directly to add the loc strings?

Yes that was just directly edited by Yuneec.

@DonLakeFlyer
Copy link
Contributor Author

Ok, I'll add loc to the json spec. I need it anyway for QGC so might as well get around to finally doing it!

@hamishwillee
Copy link
Collaborator

@julianoes @DonLakeFlyer The loc issue may actually make it necessary that we allow different definitions to be queried in different requests. Because we may wish to host localisations on the Internet and not mavftp.

It would be good if we can find a scheme to specify that we want to find out what individual localisations of parameter (or other) metadata are available and query them separately.

@DonLakeFlyer
Copy link
Contributor Author

The loc issue may actually make it necessary that we allow different definitions to be queried in different requests.

Got it. I'll work something up.

@DonLakeFlyer
Copy link
Contributor Author

DonLakeFlyer commented Apr 30, 2020

I've updated the spec:

  • Includes section which describes a json translations schema. This is very similar to the camera spec loc stuff. But it differs slightly in it's ability to not need to duplicate long strings. And that same mechansim if used means you don't need to redo the translations if the english version of the string changes.
  • Updated the COMPONENT_INFORMATION message to return information on translations associated with the metadata.

@DonLakeFlyer
Copy link
Contributor Author

My latest update is missing the ability the request a specific language for the loc files. Which is likely needed to reduce download sizes. I'll work on something for that.

@DonLakeFlyer
Copy link
Contributor Author

Hold off on commenting on the Json localization support. I'm doing some more research to see how we can do this in a way that would allow us to translate these files in crowdin.

@julianoes
Copy link
Collaborator

"parameters": {
       "type": "array",

@DonLakeFlyer what was your thought behind using an array for the params rather than a dict/map with the param_name as the index?

@DonLakeFlyer
Copy link
Contributor Author

what was your thought behind using an array for the params rather than a dict/map with the param_name as the index?

Not quite sure either what the question is or how to answer. There isn't such a thing as a dict/map in json? You only have objects, arrays and values.

@julianoes
Copy link
Collaborator

julianoes commented May 26, 2020

COMP_METADATA_TYPE_COMMANDS

@hamishwillee: Here is a suggestion for a schema for commands:

{
    "$id": "https://mavlink.io/comp_commands.schema.json",
    "$schema": "http://json-schema.org/draft-07/schema",
    "description": "Describing command and mission item support",
    "type": "object",
    "properties": {
        "supportedMissionItems": {
            "type": "object",
            "description": "Whether command is supported as part of a mission.",
            "properties": {
                "supportedParams": {
                    "type": "integer",
                    "description": "bitmask of 7 params, param 1 is LSB"
                }
            }
        },
        "supportedDirectCommands": {
            "type": "object",
            "description": "Whether command is supported as direct command.",
            "properties": {
                "supportedParams": {
                    "type": "integer",
                    "description": "bitmask of 7 params, param 1 is LSB"
                }
            },
        }
    }
}

Example:

{
    "supportedMissionItems": {
        "21": {
            "supportedParams": 8
        },
        "22": {
            "supportedParams": 8
        }
    },
    "supportedDirectCommands": {
        "23": {
            "supportedParams": 8
        },
        "22": {
            "supportedParams": 8
        }
    }
}

@DonLakeFlyer
Copy link
Contributor Author

Ok, understood. I think that ends up being a little more complex to traverse and write decoding code for it. I don't see it being quite as readable as well. Since it requires an extra level of indentation. If there some benefit to doing it that way?

@hamishwillee
Copy link
Collaborator

hamishwillee commented May 26, 2020

@julianoes

  1. Typo "supporteDirectCommands" in schema
  2. Does "supportedParams" mean "is supported and has exactly the same meaning as spec", or "is used on this platform to do something"?
    • I.e if I use uses a reserved param in my flight stack, do I mark it as supported or not?
      -if I use a supported param, but for something other than the spec definition, do I mark it as supported?
      My feeling is the answer is no. "supported" means supported according to the spec.
  3. supportedDirectCommands needs to capture mode-specific behaviour. Some commands will work in any mode as commands, others will not. For example offboard mode only responds in PX4 to the positional commands.
  4. IMO worth separating the direct commands and mission items into separate schema. You might reasonably want to query them separately, and I think they will be quite different.
  5. Should we take the opportunity to specify what messages these commands can/cannot be sent in? I tend to think that is NOT for here - but the cmd definition (if at all).

Propose supportedDirectCommands something like below, where "all_modes" lists commands supported in all modes, and then you separately list what is supported in other modes that are not in "all_modes" list.

    "supportedDirectCommands": {
        "all_modes": {  //List the ones supported by all. 
            "23": {
                "supportedParams": 8
            },
            "22": {
                "supportedParams": 8
            }
         },
       "offboard": { //List the ones supported by offboard that are no in all. 
            "33": {
                "supportedParams": 1
            },
       }

    }

The other way to do this would be to include modes inside the message. Chose not to do that because if doesn't work if we ever have cases where the supported params depend on the mode.

@julianoes
Copy link
Collaborator

julianoes commented May 27, 2020

@DonLakeFlyer right, sorry dict/map was confusing. What I meant is just the normal object structure.

So instead of:

parameters: [
    {
        'name': "RTL_RETURN_ALT",
        'description': "RTL return altitude above home",
        ...
    },
    {
        'name' "RTL_DESCEND_ALT",
        'description': RTLT descend altitude above home",
        ...
    }
]

it would be:

parameters: 
'RTL_RETURN_ALT': {
    'description': "RTL return altitude above home",
    ...
},
`RTL_DESCEND_ALT`: {
    'description': RTL descend altitude above home",
    ...
}

I would think that's easier to query because you can do:

parameters['RTL_RETURN_ALT'].description`

and don't need to loop through the array:

param.description for param in parameters if param == 'RTL_RETURN_ALT'

Anyway, if you disagree, I'm fine with both.

@julianoes
Copy link
Collaborator

@hamishwillee

  1. Thanks, fixed.

  2. "supported" means supported according to the spec. ✔️

  3. For example offboard mode only responds in PX4 to the positional commands.

    I don't understand what that means. Commands can still be denied in some modes but they are still supported as such (or not). And mixing this with flight modes is opening a huge can of worms.

  4. I'm fine splitting it up but I don't think the schema should necessarily be different.

  5. I wonder if it shouldn't be done in the xml instead because it should not depend on the autopilot, I'd say.

@DonLakeFlyer
Copy link
Contributor Author

I would think that's easier to query because you can do

If you kept the items in a json object internally that would be correct. But for example with QGC that never happens with any json. The json is traversed and the data is stuffed into other various internal data structures and the json objects are thrown away. With that parsing arrays are easier to deal with than some sort of key type object map thing. I think that leads to odd looking json structure. In reality it's a 50/50 thing. Either way works since it's just data. But I do think readability of simple arrays is better, and less code to parse. It also lets you type and validate with schema better the key values (if they exist) I think since they don't need to be strings. They can be any type. Like ints for command ids.

@DonLakeFlyer
Copy link
Contributor Author

@julianoes I documented how QGC deal with all the command idiosyncrasies here: https://github.com/mavlink/qgc-dev-guide/blob/master/en/plan/MissionCommandTree.md. Some of that should come from mavlink command spec .xml file. But I think some needs to come from the command supported stuff. For example the concept of paramRemove which tells QGC not to show that params for the command. Which is essentially your "supportedParams" info. I haven't gone back to look at all of what QGC needs with respect to what else may be needed in the command supported metadata.

Also with respect to "supportedParams". I think the way QGC lists the params to remove as a list is way better from a human readable standpoint. Trying to think through bitmasks in your head is painful.

@hamishwillee
Copy link
Collaborator

Also with respect to "supportedParams". I think the way QGC lists the params to remove as a list is way better from a human readable standpoint. Trying to think through bitmasks in your head is painful.

@DonLakeFlyer FWIW

  • I prefer supportedParams over removedParams.
  • Isn't the content is supposed to be created and consumed by software (not humans)? If Human readability is needed then I agree with a list approach; otherwise I'd tend to using the bitmask value as much less computationally difficult to parse.

@julianoes Thanks.

Does "supportedParams" mean "is supported and has exactly the same meaning as spec", or "is used on this platform to do something"?

"supported" means supported according to the spec. ✔️

We will need to capture that in final docs.

supportedDirectCommands needs to capture mode-specific behaviour. Some commands will work in any mode as commands, others will not. For example offboard mode only responds in PX4 to the positional commands.

I don't understand what that means. Commands can still be denied in some modes but they are still supported as such (or not). And mixing this with flight modes is opening a huge can of worms.

The more information you can provide the UI the better it can control UI presentation (at the cost of complexity). Knowing this would certainly aid testing, but not sure how interesting it would be to a GUI app. My gut feeling is that if we built it then it will get used. It may be a little harder for a flight stack to generate the list though.

@DonLakeFlyer Do you have an opinion on how useful would it be to GCS to know that a particular command is supported (or not) in a particular mode for an "unknown UI"? Are the any things that you only present if you know they are available in a mode?

IMO worth separating the direct commands and mission items into separate schema. You might reasonably want to query them separately, and I think they will be quite different.

I'm fine splitting it up but I don't think the schema should necessarily be different.

Partially I just want to get a definition in, and I think we can do that more easily for missions. We can afford to iterate a little longer though.

Should we take the opportunity to specify what messages these commands can/cannot be sent in? I tend to think that is NOT for here - but the cmd definition (if at all).

I wonder if it shouldn't be done in the xml instead because it should not depend on the autopilot, I'd say.

Agreed.

@DonLakeFlyer
Copy link
Contributor Author

DonLakeFlyer commented May 28, 2020

  • I prefer supportedParams over removedParams.

Not suggesting a change like that. Just suggesting to list the supported param indices instead of a bitmask.

  • Isn't the content is supposed to be created and consumed by software (not humans)?

An important point of Json and/or xml for that matter is to make the format human readable. That makes things easier to debug. Especially if these json files are going to be cached locally. That also provides a place where you can go and look at the contents of the file to check things. Instead of needing to crank up a debugger and step through the loading to gather more esoteric bits of information which is hidden behind computer friendly but not user friendly format. That is why if you look at the spec for the MAV_COMMAND info json in QGC you'll find things like command ids as ints, but also the standard is to include the command name as a string. That what you can scan the file and understand what you are looking at. If all you have is "16" for example, what command is that? It's included in the QGC command json spec as "MAV_CMD_NAV_WAYPOINT" as the rawName field. Which is super useful. QGC uses a ton of these json formats for internal metadata. And the fact that they are easily human readable has made my life easier with debugging for years now. This is the main reason I don't like the "dict" format as opposed to a simpler "array" format. To me it makes it harder to scan the content visually with your eyes.

@DonLakeFlyer
Copy link
Contributor Author

DonLakeFlyer commented Jul 1, 2020

Also now that I have most of this working for real 70 chars for an http uri is useless. So you need to do a bitly or something to get a short url. The real question though is whether 70 chars is also useless for a mavlinkftp location on the vehicle? I don't know the answer to that. Firmware folks will need to chime in.

@DonLakeFlyer
Copy link
Contributor Author

DonLakeFlyer commented Jul 1, 2020

Also on the uid's which are in COMPONENT_INFORMATION I'm thinking the scoping of the "uniqueness" of those ids is scoped to firmware type. So a PX4 Firmware uid which is the same as an ArduPilot firmware uid does not indicate they are the same. But it also means that for the same firmware, uids for one vehicle type and another uid for a different vehicle type refers to the same metadata if the uids are the same. This specs out the semantics of how you can cache these.

@hamishwillee
Copy link
Collaborator

hamishwillee commented Jul 2, 2020

@DonLakeFlyer Thanks.

Also now that I have most of this working for real 70 chars for an http uri is useless. So you need to do a bitly or something to get a short url. The real question though is whether 70 chars is also useless for a mavlinkftp location on the vehicle? I don't know the answer to that. Firmware folks will need to chime in.

It gets worse - there is some pull to put the version info back into the message itself COMPONENT_INFORMATION. This perhaps indicates that there is value in a separate COMPONENT_METADATA message.

Some ideas?

  • Pull out the translation Id. Make translation uris or whatever one thing you can query as data. That gives us at least 70 more chars but means that we have to query twice.
  • ?

@hamishwillee
Copy link
Collaborator

Also on the uid's which are in COMPONENT_INFORMATION I'm thinking the scoping of the "uniqueness" of those ids is scoped to firmware type. So a PX4 Firmware uid which is the same as an ArduPilot firmware uid does not indicate they are the same. But it also means that for the same firmware, uids for one vehicle type and another uid for a different vehicle type refers to the same metadata if the uids are the same. This specs out the semantics of how you can cache these.

I understand that you mean uids are unique across vehicles in a flight stack, but not across flight stacks. But which UIDs are you talking about?

@DonLakeFlyer
Copy link
Contributor Author

But which UIDs are you talking about?

COMPONENT_INFORMATION. comp_metadata_uid, COMPONENT_INFORMATION. comp_translation_uid

there is some pull to put the version info back into the message itself

You either buy into the versioned json metadata concept, or you spend the rest of your life with COMPONENT_INFORMATION_1, and then COMPONENT_INFORMATION_2 and on and on (and on) as new things come up and become "important". Being somewhere in the middle of the two doesn't make a huge amount of sense to me. That said, likely not possible to discuss in text thread. I would suggest, let me finish an end to end implementation to find all the other problems we don't know about yet given the current thing. And then we can come back and discuss v0.2.

@hamishwillee
Copy link
Collaborator

I understand that you mean uids are unique across vehicles in a flight stack, but not across flight stacks. But which UIDs are you talking about?

COMPONENT_INFORMATION. comp_metadata_uid, COMPONENT_INFORMATION. comp_translation_uid

The whole point is that a GCS should not need to know about the component in order to us the information. I'd be more fine with things differing by vehicle type than by flight stack.

Of course that is ideology. So we would need to talk specific cases.

@DonLakeFlyer
Copy link
Contributor Author

Also on the uid's which are in COMPONENT_INFORMATION I'm thinking the scoping of the "uniqueness" of those ids is scoped to firmware type. So a PX4 Firmware uid which is the same as an ArduPilot firmware uid does not indicate they are the same. But it also means that for the same firmware, uids for one vehicle type and another uid for a different vehicle type refers to the same metadata if the uids are the same. This specs out the semantics of how you can cache these.

Now that I've gotten further into the implementation I'm realizing this is wrong. That only works for metadata associated with the MAV_COMP_ID_AUTOPILOT1 component. For random other components it's trickier since the main firmware isn't necessarily in control of those. Those may need to take into account vendor and model names to know the scoping where those uids are unique.

The whole point is that a GCS should not need to know about the component in order to us the information.

Don't know what you mean by that. The GCS doesn't need to know anything more than what comes to it from COMPONENT_INFORMATION data.

@auturgy
Copy link
Collaborator

auturgy commented Jul 2, 2020 via email

@DonLakeFlyer
Copy link
Contributor Author

DonLakeFlyer commented Jul 2, 2020

One option would be to make the uids non-opaque. And instead use say a crc32 on the file as unique identifier. Then the uniqueness scope would be global. And it would be simple to cache these things in a GCS.

@DonLakeFlyer
Copy link
Contributor Author

You can see an example of Json parameter meta which I use in my test harness here: https://github.com/mavlink/qgroundcontrol/blob/master/src/comm/MockLink.Parameter.MetaData.json

@hamishwillee
Copy link
Collaborator

One option would be to make the uids non-opaque. And instead use say a crc32 on the file as unique identifier. Then the uniqueness scope would be global. And it would be simple to cache these things in a GCS.

That makes sense to me. What would be the argument against?

@hamishwillee
Copy link
Collaborator

You can see an example of Json parameter meta which I use in my test harness here: https://github.com/mavlink/qgroundcontrol/blob/master/src/comm/MockLink.Parameter.MetaData.json

How would you validate this? Ie we have a key "type" that is also a keyword.

{
  "type": "object",
  "properties": {
    "version": { "type": "number" },
    "uid": { "type": "number" },
    "scope": { "type": "string" },
    "parameters": {
      "type": "array",
      "items": {
        "type": "object",
        "name": { "type": "string" },
>>>>>>
        "category": { "type": "string" }, 
        "shortDescription": { "type": "string" },           
        "longDescription": { "type": "string" },                
        "units": { "type": "string" },              
        "defaultValue": { "type": "number" },   
        "decimalPlaces": { "type": "number" }, 
        "minValue": { "type": "number" },           
        "minValue": { "type": "number" }                 
      }
     }  
   }
}

Also, is the above OK (other than type)? i.e. are any of those values in a known set - e.g. units can only be certain types, etc?

@DonLakeFlyer
Copy link
Contributor Author

Ie we have a key "type" that is also a keyword.

The schema definition is wrong. There is a "properties" definition missing under "parameters". I'll fix that.

"units" can be any string but if you want conversions (metes->feet, ...) to work then you should use one of the mavlink supported types which I believe is spec'ed with the mavlink command spec someplace.

@DonLakeFlyer
Copy link
Contributor Author

@hamishwillee Wait, where did you pull that schema from? It isn't what is posted. What is posted above is correct:

        "parameters": {
               "type": "array",
                           
                "properties": {
                    "name": {
                        "description": "Parameter Name.",
                        "type": "string",
                        "pattern": "^[a-zA-Z0-9_]{1,16}$"
                    },
                    "type": {
                        "description": "Parameter type.",
                        "type": "string",
                        "enum": ["Uint8", "Int8", "Uint16", "Int16", "Uint32", "Int32", "Float" ]
            },
                    "shortDescription": {
                        "description": "Short user facing description/name for parameter. Used in UI intead of internal parameter name.",
                        "type": "string"
                    },
                    "longDescription": {
                        "description": "Long user facing documentation of how the parameters works."
                        "type": "string"
                    },

@hamishwillee
Copy link
Collaborator

@DonLakeFlyer Thanks. I missed your schema and was trying to work out what it might look like.

But, your schema above appears to be broken when tested in https://www.jsonschemavalidator.net/
It is missing some commas, and uses a type "double" that does not appear to be supported.

What I want to do here is put the schema along with some examples under mavlink/mavlink.
Would it be reasonable in your opinion to have subfolder for this:

/component_metadata/schema
/component_metadata/test_json

@hamishwillee
Copy link
Collaborator

@DonLakeFlyer Can you help me fix that schema above?

Also, would this metadata system also cover PARAM_EXT? (ie. it should).

@DonLakeFlyer
Copy link
Contributor Author

I'll fixed up the schema and put together a pull to stuff them in the places you talk about above.

Also, would this metadata system also cover PARAM_EXT? (ie. it should).

I assume so. I don't know much about that though.

@LorenzMeier
Copy link
Member

We discussed this on the dev call today and would love to move this forward.

@DonLakeFlyer
Copy link
Contributor Author

I'm closing this issue. I'll create a new one to resolve the remaining issues with the COMPONENT_INFORMATION message.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants