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

feat(inputs.mavlink): Add plugin #16221

Open
wants to merge 43 commits into
base: master
Choose a base branch
from

Conversation

chrisdalke
Copy link

@chrisdalke chrisdalke commented Nov 22, 2024

Summary

Add a Mavlink input plugin.

The mavlink plugin connects to a MavLink-compatible flight controller such as as ArduPilot or PX4. and translates all incoming messages into metrics.

The purpose of this plugin is to allow Telegraf to be used to ingest live flight metrics from unmanned systems (drones, planes, boats, etc.)

Telegraf is already often used on flight computers (eg a Raspberry Pi) to collect system metrics for drones and it would be valuable to extend this to also provide a convenient way to record flight telemetry.

TODO

  • gomavlib is currently on a fork to support reading serial ports on i386 and darwin. Will need to upstream the fix for this and move back to the main repo after merge, or before merge if the forked gomavlib is not acceptable

Checklist

  • No AI generated code was used in this PR

Related issues

@telegraf-tiger telegraf-tiger bot added the feat Improvement on an existing feature such as adding a new setting/mode to an existing plugin label Nov 22, 2024
plugins/inputs/mavlink/mavlink.go Outdated Show resolved Hide resolved
plugins/inputs/mavlink/mavlink.go Outdated Show resolved Hide resolved
plugins/inputs/mavlink/sample.conf Outdated Show resolved Hide resolved
plugins/inputs/mavlink/sample.conf Outdated Show resolved Hide resolved
plugins/inputs/mavlink/README.md Outdated Show resolved Hide resolved
plugins/inputs/mavlink/mavlink.go Outdated Show resolved Hide resolved
plugins/inputs/mavlink/mavlink_utils.go Outdated Show resolved Hide resolved
plugins/inputs/mavlink/mavlink_utils.go Outdated Show resolved Hide resolved
plugins/inputs/mavlink/mavlink.go Outdated Show resolved Hide resolved
plugins/inputs/mavlink/mavlink_utils.go Outdated Show resolved Hide resolved
Copy link
Contributor

@Hipska Hipska left a comment

Choose a reason for hiding this comment

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

Going in good direction!

plugins/inputs/mavlink/mavlink.go Outdated Show resolved Hide resolved
plugins/inputs/mavlink/mavlink_utils.go Outdated Show resolved Hide resolved
plugins/inputs/mavlink/mavlink_utils.go Outdated Show resolved Hide resolved
plugins/inputs/mavlink/mavlink_utils.go Outdated Show resolved Hide resolved
plugins/inputs/mavlink/mavlink_utils.go Outdated Show resolved Hide resolved
plugins/inputs/mavlink/mavlink.go Outdated Show resolved Hide resolved
plugins/inputs/mavlink/mavlink.go Outdated Show resolved Hide resolved
plugins/inputs/mavlink/sample.conf Outdated Show resolved Hide resolved
plugins/inputs/mavlink/mavlink_utils.go Outdated Show resolved Hide resolved
plugins/inputs/mavlink/mavlink_utils.go Outdated Show resolved Hide resolved
@chrisdalke chrisdalke marked this pull request as ready for review December 6, 2024 03:50
@srebhan srebhan self-assigned this Dec 9, 2024
Copy link
Member

@srebhan srebhan left a comment

Choose a reason for hiding this comment

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

@chrisdalke thanks for your contribution! Please check my comments in the code. Furthermore, I do have some general remarks

  1. I'm hesitant to merge plugins using forked one-man dependencies as experience shows that this is not maintainable on the long run. In your case I see two possibilities, the first being we hold-up the plugin until the upstream library merged your PR. This will likely take longer if possible at all.
    The second option is to base your plugin on the upstream library and limit the availablility of the plugin to the platforms supported (excluding i386 and darwin if I understand correctly). What do you think?
  2. Please keep the comments in the sample.conf file brief and intend the file with two spaces.
  3. Is there some way of mocking a Mavlink controller endpoint? E.g. using a minimal implementation mimicking some messages or a test-container/simulator?

Looking forward to your update!

@@ -96,6 +96,8 @@ following works:
- github.com/caio/go-tdigest [MIT License](https://github.com/caio/go-tdigest/blob/master/LICENSE)
- github.com/cenkalti/backoff [MIT License](https://github.com/cenkalti/backoff/blob/master/LICENSE)
- github.com/cespare/xxhash [MIT License](https://github.com/cespare/xxhash/blob/master/LICENSE.txt)
- github.com/chrisdalke/go-serial [BSD 3-Clause License](https://github.com/chrisdalke/go-serial/blob/master/LICENSE)
Copy link
Member

Choose a reason for hiding this comment

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

Why not using the upstream bugst/serial instead of your fork?

Copy link
Author

Choose a reason for hiding this comment

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

Returning this to the upstream bugst/serial, there is still one more forked dependency gomavlib which I have a PR to try and fix platform support for.

In your case I see two possibilities, the first being we hold-up the plugin until the upstream library merged your PR. This will likely take longer if possible at all.
The second option is to base your plugin on the upstream library and limit the availablility of the plugin to the platforms supported (excluding i386 and darwin if I understand correctly). What do you think?

Hoping to get the upstream PR to gomavlib merged. The PR just changes the serial library to add wider platform support. I'd like this plugin to work on all platforms that Telegraf supports.

Copy link
Author

Choose a reason for hiding this comment

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

Fork is resolved now, all new libraries are pointing at their main repo.

Comment on lines 3 to 16
The `mavlink` plugin connects to a MavLink-compatible flight controller such as
[ArduPilot](https://ardupilot.org/) or [PX4](https://px4.io/). and translates
all incoming messages into metrics.

The purpose of this plugin is to allow Telegraf to be used to ingest live
flight metrics from unmanned systems (drones, planes, boats, etc.)

Warning: This input plugin potentially generates a large amount of data! Use
the configuration to limit the set of messages, or use another telegraf plugin
to filter the output.

This plugin currently uses the ArduPilot-specific Mavlink dialect. See the
[Mavlink docs](https://mavlink.io/en/messages/ardupilotmega.html) for more
info on dialects and the various messages that this plugin can receive.
Copy link
Member

Choose a reason for hiding this comment

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

Please use shortened links and add the metadata to this plugin

Suggested change
The `mavlink` plugin connects to a MavLink-compatible flight controller such as
[ArduPilot](https://ardupilot.org/) or [PX4](https://px4.io/). and translates
all incoming messages into metrics.
The purpose of this plugin is to allow Telegraf to be used to ingest live
flight metrics from unmanned systems (drones, planes, boats, etc.)
Warning: This input plugin potentially generates a large amount of data! Use
the configuration to limit the set of messages, or use another telegraf plugin
to filter the output.
This plugin currently uses the ArduPilot-specific Mavlink dialect. See the
[Mavlink docs](https://mavlink.io/en/messages/ardupilotmega.html) for more
info on dialects and the various messages that this plugin can receive.
This plugin collects metrics from [MavLink][mavlink]-compatible flight controllers
such as [ArduPilot][ardupilor] or [PX4][px4] to live ingest flight metrics from
unmanned systems (drones, planes, boats, etc.)
Currently the ArduPilot-specific Mavlink dialect is used, check the
[Mavlink documentation][mavlink_docs] for more details and the various
messages available.
> [!WARNING]
> This plugin potentially generates a large amount of data! Please use metric
> filters to limit the amount of metrics produced!
⭐ Telegraf v1.34.0
🏷️ iot
💻 all
[mavlink]: https://mavlink.io
[ardupilor]: https://ardupilot.org/
[px4]: https://px4.io/
[mavlink_docs]: https://mavlink.io/en/messages/ardupilotmega.html

@@ -0,0 +1,39 @@
# Read metrics from a Mavlink connection to a flight controller.
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
# Read metrics from a Mavlink connection to a flight controller.
# Read metrics from a Mavlink flight controller.

Comment on lines 3 to 19
## Flight controller URL. Must be a valid Mavlink connection string in one
## of the following formats:
##
## - Serial port: serial://<device name>:<baud rate>
## eg: "serial:///dev/ttyACM0:57600"
##
## - TCP client: tcp://<target ip or hostname>:<port>
## eg: "tcp://192.168.1.12:14550"
##
## - UDP client: udp://<target ip or hostname>:<port>
## eg: "udp://192.168.1.12:14550"
##
## - UDP server: udp://:<listen port>
## eg: "udp://:14540"
##
## The meaning of each of these modes is documented by
## https://mavsdk.mavlink.io/v1.4/en/cpp/guide/connections.html.
Copy link
Member

Choose a reason for hiding this comment

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

How about shortening this?

Suggested change
## Flight controller URL. Must be a valid Mavlink connection string in one
## of the following formats:
##
## - Serial port: serial://<device name>:<baud rate>
## eg: "serial:///dev/ttyACM0:57600"
##
## - TCP client: tcp://<target ip or hostname>:<port>
## eg: "tcp://192.168.1.12:14550"
##
## - UDP client: udp://<target ip or hostname>:<port>
## eg: "udp://192.168.1.12:14550"
##
## - UDP server: udp://:<listen port>
## eg: "udp://:14540"
##
## The meaning of each of these modes is documented by
## https://mavsdk.mavlink.io/v1.4/en/cpp/guide/connections.html.
## Flight controller URL supporting serial port, UDP and TCP connections.
## The modes are documented at
## https://mavsdk.mavlink.io/v1.4/en/cpp/guide/connections.html.
##
## Examples:
## - Serial port: serial:///dev/ttyACM0:57600
## - TCP client: tcp://192.168.1.12:14550
## - UDP client: udp://192.168.1.12:14550
## - UDP server: udp://:14540

##
## The meaning of each of these modes is documented by
## https://mavsdk.mavlink.io/v1.4/en/cpp/guide/connections.html.
fcu_url = "udp://:14540"
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
fcu_url = "udp://:14540"
url = "udp://:14540"

Comment on lines +92 to +97

case *gomavlib.EventChannelOpen:
s.Log.Debugf("Mavlink channel opened")

case *gomavlib.EventChannelClose:
s.Log.Debugf("Mavlink channel closed")
Copy link
Member

Choose a reason for hiding this comment

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

Why do we need those? Should we do something about it if the channel is opened/closed?

Copy link
Author

Choose a reason for hiding this comment

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

These messages indicate that the Mavlink connection has started/stopped, which is separate from the Mavlink client initializing its background thread.

There's nothing Telegraf can do in this case but it helps the user debug the Mavlink setup which can be difficult. One example of where this could occur is if you had two TCP client connections with the same system_id one would get kicked off. Another example is a flaky USB port.

Without these messages it's hard to tell the difference between (1) Mavlink is not connected vs (2) Robot has a problem and is not broadcasting messages

return nil
}

func (s *Mavlink) Gather(_ telegraf.Accumulator) error {
Copy link
Member

Choose a reason for hiding this comment

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

Please remove unused receivers and variables.

Suggested change
func (s *Mavlink) Gather(_ telegraf.Accumulator) error {
func (*Mavlink) Gather(telegraf.Accumulator) error {

Comment on lines 116 to 120
FcuURL: "udp://:14540",
MessageFilter: make([]string, 0),
SystemID: 254,
StreamRequestEnable: true,
StreamRequestFrequency: 4,
Copy link
Member

Choose a reason for hiding this comment

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

This should be moved to Init except for StreamRequestEnable and SystemID (if zero is a valid id).

Comment on lines 8 to 13
"github.com/chrisdalke/gomavlib/v3"
"github.com/chrisdalke/gomavlib/v3/pkg/dialects/ardupilotmega"
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/internal"
"github.com/influxdata/telegraf/internal/choice"
"github.com/influxdata/telegraf/plugins/inputs"
Copy link
Member

Choose a reason for hiding this comment

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

Please split the internal and 3rd party packages by an empty line

Suggested change
"github.com/chrisdalke/gomavlib/v3"
"github.com/chrisdalke/gomavlib/v3/pkg/dialects/ardupilotmega"
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/internal"
"github.com/influxdata/telegraf/internal/choice"
"github.com/influxdata/telegraf/plugins/inputs"
"github.com/chrisdalke/gomavlib/v3"
"github.com/chrisdalke/gomavlib/v3/pkg/dialects/ardupilotmega"
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/internal"
"github.com/influxdata/telegraf/internal/choice"
"github.com/influxdata/telegraf/plugins/inputs"

}

_, err := ParseMavlinkEndpointConfig(testConfig.FcuURL)
require.Equal(t, "could not parse fcu_url ftp://not-a-valid-fcu-url", err.Error())
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
require.Equal(t, "could not parse fcu_url ftp://not-a-valid-fcu-url", err.Error())
require.ErrorContains(t, err, "could not parse fcu_url")

@srebhan srebhan added new plugin plugin/input 1. Request for new input plugins 2. Issues/PRs that are related to input plugins labels Dec 11, 2024
@srebhan srebhan changed the title feat(inputs): Add Mavlink input plugin feat(inputs.mavlink): Add plugin Dec 11, 2024
@telegraf-tiger
Copy link
Contributor

@chrisdalke
Copy link
Author

3. Is there some way of mocking a Mavlink controller endpoint? E.g. using a minimal implementation mimicking some messages or a test-container/simulator?

I can prepare an ArduPilot container which will output data over UDP -- Is there a reference to how you'd like this setup to match other plugins?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feat Improvement on an existing feature such as adding a new setting/mode to an existing plugin new plugin plugin/input 1. Request for new input plugins 2. Issues/PRs that are related to input plugins
Projects
None yet
Development

Successfully merging this pull request may close these issues.

feat(inputs): Add Mavlink input plugin
4 participants