Skip to content

Conversation

wes-public-apps
Copy link

I have put together a proposal to support dispersion payloads. (ie sprayers and spreaders) All of the relevant info can be found in the markdown files attached. Let me know if you have any questions!

@hamishwillee
Copy link
Collaborator

hamishwillee commented Feb 19, 2025

Thanks very much @wes-public-apps . I hope to look at this tomorrow.

Do you have a target flight stack/vehicle/ground station in mind? I ask because MAVLink can't merge protocols in "abstract" without a stakeholder that is willing to take it through to implementation.

Note also that the gimbal protocol may not be the right model to follow. Gimbals are complicated because they have to address so many use cases and mediate input from multiple possible sources. There also needs to potentially be a lot of them on a vehicle, and so on. Upshot it might be possible to do less.

@wes-public-apps
Copy link
Author

@hamishwillee I would like to target all MAVLink based autopilots eventually since I hope to make this standard widely adopted but I would be happy to start with PX4 realistically. I feel like most of the implementation work would be in a dispersion device controller itself, leaving the only PX4 implementation to be sending AUTOPILOT_STATE, integrating with missions, logging, and adding sim support. Id be open to adding the functionality for manual control to QGroundControl but since this protocol is specific to agriculture I imagined industry specific ground stations would implement the manual control. I only know of proprietary ground stations for agriculture at this time. For the dispersion device itself I was thinking about hosting an open source repo that contained a generic dispersion device controller that people could extend. I think that is OOS here since it does not fit into the existing open source structure but I am open to thoughts.

In regards to the PX4 implementation, I must say it would be stretching my skillset. I am happy to give it a shot worst case but I would prefer to be connected with someone who knows PX4 inside and out that would be willing to implement this spec. I can also reach out to my own network. So, yes I am willing to follow through with the implementation.

Co-authored-by: Hamish Willee <hamishwillee@gmail.com>
@wes-public-apps
Copy link
Author

@hamishwillee I went ahead and updated my proposal to incorporate your comments. There is a decent amount of refactoring but I overall think it yielded as simpler spec. Plus we always have the earlier commits to fall back on. I plan to attend the dev call tomorrow in case there are any questions.

Copy link

@julianoes julianoes left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A couple of comments but in general I think this is good!

@wes-public-apps
Copy link
Author

There is a gap here in that this protocol works with the operational model where nozzles are physically swapped out. This protocol should support atomizers which allow you to control droplet size as well. This could pretty easily be added by:

  1. adding an atomizer capability flag to info
  2. adding min/max droplet size hardware limits to info
  3. adding dispersion type spray atomizer
  4. add atomizer failure error + out of bounds droplet size request error
  5. add droplet size to status message
  6. update existing mavlink command or create a new command to set droplet size

DJI T50 demo

@hamishwillee
Copy link
Collaborator

@wes-public-apps I've tried to respond to all your comments. Sorry if I missed anything.

We discussed this in the mav call last night. Some thoughts:

  1. ArduPilot implements this sprayer https://ardupilot.org/copter/docs/sprayer.html - it is worth considering how you would integrate with this particular sprayer - confirm that your interface could provide the feature this does. Ditto for other popular sprayers.
  2. IN the "other options" section, I think it is worth explaining why we have chosen to have a dedicated message for the amount of fuel rather than reusing FUEL_STATUS - specifically, this is because if you have an autopilot-connected sprayer there is no way to tell that this fuel is associated with the sprayer rather than the autopilot, so this might count to cumulative flight time fuel, and warnings/actions in the case of low fuel. We might consider this if the FUEL status was extended somehow to make it possible to differentiate its purpose.

The next step is to see if we can get some more review from other stakeholders, in particular to answer questions around:

  1. Is the information output sufficient
  2. Are there other errors we need to provide.
  3. Are there any other control options that need to be specified.

From a MAVLink perspective we then need to get this into development.xml (either included as a separate file with WIP markup, or inserted directly) and agree what needs to happen in terms of implementation and testing for us to say that this is valid. Once that's done you go off and implement. After some time you come back and we either agree it works and merge move the messages into common.xml or you tell us that you have decided on some path, and they are removed.

That's very high level. Hopefully enough to get you going. Right now I am not sure we have finished our iteration.

@hamishwillee
Copy link
Collaborator

@auturgy Can you reach out to the ArduPilot dev community for people in the ag-spraying community we can get to confirm they are happy with this?

@wes-public-apps
Copy link
Author

I definitely want to note that this protocol currently has a strong bias for UAV systems. I am going to take some time to revisit that bias and update the protocol to make sure I do not design out ground based systems. That is a huge area where this could provide value as well. If there is anyone with experience in ground systems that perspective would be extremely valuable.

@wes-public-apps
Copy link
Author

The pull request has been updated to support ground systems as well as UAVs. The main reasons for doing so are that there is a massive market for ground based dispersion rigs, supported autopilots do technically have rover modes, the ground based technology gives some indication of potential aerial application technology to come, and this protocol can be a template for other common ground rig based standards such as ISOBUS.

@hamishwillee
Copy link
Collaborator

hamishwillee commented Mar 5, 2025

The pull request has been updated to support ground systems as well as UAVs.

Makes perfect sense to support this case. The sprayer shouldn't care particularly where it is mounted.

<param index="7">Empty</param>
</entry>
<entry value="30012" name="MAV_CMD_DO_SET_DISPERSION_LOCK" hasLocation="false" isDestination="false">
<param index="2" label="Device ID" enum="MAV_COMPONENT">Component ID of dispersion device to address, 0 for all dispersion device components. Send command multiple times for more than one device (but not all devices).</param>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I'm being dim. What is a subcomponent?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are setting this here so we can address a target dispersion device component in a mission?

Copy link

@flocked-agriculture flocked-agriculture Mar 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I made a lot of changes in the last update to support ground rigs which means there is a lot of new stuff to parse. I added this note to the 0020-disperison-payload.md:

This protocol should at a minimum support the capability of existing systems and then project into the future a little bit to be a timely, durable, and valuable solution. So, this protocol is designed to support a system with multiple dispersion devices and multiple subcomponents on that device. For the sake of this design, we consider a dispersion device to be a system containing one chemical mix and the infrastructure to deliver that to a field. The dipsersion device must have one gateway compute node that is responsible for communicating over a MAVLink interface. In the most simple form, a disperison device could be a microprocessor, tank, esc, motor, and spreader wheel that needs rate assigned at specific GPS locations but it can take on a more complex form factor for large ground based spray systems. These might have multiple feeder tanks with n number of subcomponents allowing independent control of subcomponent droplet size and flow rate to support many powerful features such as spot spraying and turn compenstation.

I also added this to the microservice which might be helpful:

Key Terms:

Term Description >
Dispersion Device A system containing one chemical mixture and the infrastructure to deliver that to a field
Dispersion Component (aka Subcomponent) A discrete unit of the dispersion device that has independent dispersion rate control. Depending on the hardware configuration, there could be no subcomponents, all the way to a subcomponent per nozzle for independent nozzle control.

In summary I found that with ground rigs, it is common to have ground rigs with up to like 150 nozzles and each nozzle can each independently be controlled. If it is not per nozzle then they do boom sections, maybe a group of 4 nozzles. Typically one tank feeds all of the system but either a valve or motor controls flow rate at the subcomponent level with its own flow rate or pressure sensor. So a dispersion device's stats is the summation of all subcomponents. I built this protocol for the worst case scenario, a ground rig with multiple dispersion devices and each device having multiple subcomponents for independent nozzle control. A subcomponent represents an isolated control unit (from a software perspective) that take a target disperison rate and it uses what it has (ie valve, motor, rate sensors, etc) to ensure it delivers on that target.

1. ~~Is a dispersion manager needed? I genuinely believe the source should not matter. Anything should be able to send a request and it get processed in the order it is received. The only time any prioritization should occur is manual triggers vs automated. No this could be handled through a manager but it is pretty easy implement with just the deivce using the MANUAL vs AUTO request type. I also expect there to be multiple possible viable sources for manual on/off live at any given moment. All should be immediately respected. I feel like the overhead with a manager only allowign two control sources could make this over complicated.~~
1. Am I missing any critical workflows or test cases? Ie Debug level motor controller and motor information (deemed out of scope, should be a separate protocol for general motor controller and motor information)
1. should we encourage using something like the parameter protocol rather than a command message for configuration?
1. ~~should we encourage using something like the parameter protocol rather than a command message for configuration?~~
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Parameters are explicitly internal. That means that you can't define param_do_whatever on multiple flight stacks. The implication is that you'll tend to use thing for params that really only matter on the implementation - such as which output is mapped to which dohicky on your device.

If you'll have two flight stacks that want to set the same things, then you probably can't use params, or at least not directly.

A model used for cameras was to separate out the simple things that all cameras do into a core set of commands - zoom, capture image, pan, etc. Then a camera that supports more things can export a camera definition file that references parameters - the UI is generated from this file. I'm not advocating, since it's a lot more work. I guess I'm saying we don't have to invent everything now if we can work out an reasonable extension mechanism - and address 90% of the use cases in MAVLink messages.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting. I meant this as the dispersion device has its own internal parameter set and parameter protocol server. The parameter protocol would be used to assign values to the device and not the autopilot. My vision for this would not require any autopilot modification. This was also more for convenience than necessity. In most cases, a manufacturer can set a device's parameters, sell that device and it will just work indefinitely. Only in cases where the owner might need more flexibility with nozzle swapping and the system does not have feedback sensors, or they require nozzle repositioning, would they need to modify parameters. I figured that it would be convenient to connect QGC or another util to the component and write the params.

I may be making some assumptions about the mavlink architecture but I think this should work.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So what you are describing could work, but again, I'd try and reserve this for stuff that is more or less static.

The concerns with parameters is that to MAVLink what gets sent is an id and a value. In order for something that uses the parameters to make any sense of it you need to provide metadata - such as this information in PX4 https://docs.px4.io/main/en/advanced_config/parameter_reference.html#battery-calibration

You need some way to deploy that to your ground stations and keep it in sync - though I guess if it never changes and is the same for all devices you could have a plain list somewhere. ArduPilot provides this kind of metadata to QGC in a file. PX4 has dynamic mechanisms - component metadata - for sharing the file (this might be a good approach for you).
And of course the camera stuff similarly allows a dynamic UI approach.

@wes-public-apps
Copy link
Author

wes-public-apps commented Mar 5, 2025

@hamishwillee I removed the messages.md and dispersion.xml. I was going crazy keeping them all in sync. I have been moving forward with prototyping in the background. I forked the mavlink repo and created a pull request on that fork with the desired changes to minimal and common. I would like to reference that for message definition content to reduce the number of files I need to touch and allow me to prototype off of it.

@wes-public-apps
Copy link
Author

Switching focus to implementation. Theoretical iteration will only get us so far so I am looking to create an example implementation hosted by Flocked. I expect such an implementation to result in changes to this spec.

The tentative roadmap for pushing this through can be found here.

Comment on lines 180 to 236
#### Log File Format

This log file should be a binary file with a maximum size limit dictated by the underlying device compute system. On log file creation, the file header as specified below should be written. After the header is the mavlink message definitions. The mavlink message definitions are to be written in the format of a single entry as noted below by writing the entire XML file representation as an entry payload. After the header, any number of entries can be added. This file can contain any data. Each entry into the file will have a header and payload.

It is expected that endianness match the mavlink spec for [pack format](https://mavlink.io/en/guide/serialization.html#packet_format) (little-endian).

The file structure has the following sections:

1. Header
1. Mavlink Definitions
1. Entries

File Header (30 bytes)

| Field | Type | Description |
| :------------- | :------- | :------------------------------------------------------------------------------------------------------- |
| uuid | char[16] | A unique identifier for this log file. |
| timestamp_us | uint64_t | Unix timestamp that notes when logging started in microseconds. |
| format_version | uint32_t | Version number for this file format. |
| flags | uint16_t | Set of flags to allow for various format changes. 0 means none of the flags apply. See FLAGS enum below. |

FLAGS Enum

| Value | Name | Description |
| :---- | :-------------- | :-------------------------------------------------------------- |
| 1 | MAVLINK_ONLY | Flag indicating this file only contains packed mavlink content. |
| 2 | NOT_TIMESTAMPED | Flag indicating each entity has a timestamp |

Mavlink Message Definitions (44 bytes without payload)

| Field | Type | Description |
| :---------------- | :------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------- |
| mav_version_major | uint32_t | MAVLink protocol major version. |
| mav_version_minor | uint32_t | MAVLink protocol minor version. |
| mav_dialect | char[32] | [mavlink message dialect](https://mavlink.io/en/messages/) being used. |
| size | uint32_t | Size of the following payload in bytes. 0 if definition xml file is not retrievable. |
| payload | N/A | This payload is the utf-8 encoding of the xml file definition for the mavlink messages being used during this logging process. This payload can be empty. |

Entries (0-11 bytes without payload)

As many entries as there are room to write can be appended to the file content post mavlink definitions. Each entry could have up to the following structure. Each field in the following structure is optional as determined by the flags listed above.

| Field | Type | Description |
| :----------- | :------- | :------------------------------------------------------------------------------------------------------------------------------------------------ |
| type | uint8_t | This indicates the payload type. See ENTRY_TYPE enum below. This field is NOT present if the MAVLINK_ONLY flag is set. |
| timestamp_us | uint64_t | Unix timestamp in microseconds for which this corresponding payload was acted upon. This field is NOT present if the NOT_TIMESTAMPED flag is set. |
| size | uint16_t | Size of the entry in bytes without the header. This field is NOT present if the MAVLINK_ONLY flag is set. |
| payload | N/A | Any bytes content. |

ENTRY_TYPE Enum

| Value | Name | Description |
| :---- | :------ | :--------------------------- |
| 0 | RAW | Catch all for raw bytes data |
| 1 | MAVLINK | Entry is a mavlink message |
| 2 | TEXT | Entry is UTF-8 encoded text |

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this has basically turned into reinventing tlog and rlog. This has some optimization but they may or may not be worth it. This should be replaced with a link to documentation on tlog and rlog.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure! If there is such documentation :-)

@hamishwillee
Copy link
Collaborator

Note, discovered this in ardupilot dialect. MAV_CMD_DO_SPRAYER. Should be easy enough to "do what it does". Point is that if possible you can't reuse the name or id number, unless you can do so in a compatible way that won't break existing consumers.

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

Successfully merging this pull request may close these issues.

4 participants