From bad860269dd290e437f5c67be8acbb2bd75b3ff9 Mon Sep 17 00:00:00 2001 From: Hamish Willee Date: Wed, 4 Jun 2025 17:11:42 +1000 Subject: [PATCH 1/2] Methodical uorb documentation --- docs/en/middleware/uorb.md | 100 +++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/docs/en/middleware/uorb.md b/docs/en/middleware/uorb.md index ebd6a592df9d..fd3108830ec2 100644 --- a/docs/en/middleware/uorb.md +++ b/docs/en/middleware/uorb.md @@ -74,6 +74,106 @@ By default this message definition will be compiled to a single topic with an id This is the simplest form of a message. See the existing [`msg`](../msg_docs/index.md) files for other examples of how messages are defined. +### Fields + +Messages define one or more fields, which are the message variables that are written and read by publishers and subscribers, respectively. + +A typical field might look like this: + +```sh +float64 lat # [deg] Latitude (WGS84). +``` + +Each field minimally has a _type_ followed by a _name_, and should also have a _comment_ with optional _metadata_ and a comment +The format is as shown: + +```sh + # [metadata] +``` + +- `type`: + - A primitive data type: `bool`, `char`, `uint8`, `uint32`, `uint64`, `int8`, `int16`, `int32`, `float32` and `float64`. + - Another UORB message name, when creating complex types using [nested messages](#nested-messages). +- `name` + - Any message-unique string. + By convention use lower case `underline_snake_case`. +- `metadata` + - Provides information about the field, such as units and allowed values. + - `[]` + - The units inside square brackets (note, no delineator). For example `[m]` or `[deg]`. + Typical units include: `m`, `deg`, `m/s`, `rad`, `rad/s`, and so on. + - `[@enum ]` + - An enum name (or space-separated names) that indicate sets of allowed constant values. + Enums are not specifically defined in the file, but all constants that share the enum prefix listed can be used in the field. + - `[@range , ]` + - The allowed range of the field. Either the lower or upper value can be omitted to indicate an unbounded value. + For example `[@range 0, 3]`, `[@range 5.3, ]` + - `[@invalid ]` + - The value to set the field to indicate that the value is unknown. The description is optional. +- `description` + - A terse description of the purpose of the field and allowed values. + Take care to include any information that can't be inferred from the name! + The description is a sentence: use capital first letter and terminate in a full stop. + It should all be on one line. + +#### Array Fields + +A array field defines multiple variables in an array, where all values have the same type. +The number of elements are given using square brackets after the type. +Array fields are otherwise defined (and documented) in the same way as other fields. + +For example: + +```sh +int32[12] raw_data # ADC channel raw value, accept negative value. +``` + +#### Mandatory fields + +All message definitions **must** include following fields: + +- `uint64_t timestamp` + - This should be filled in when publishing the associated topic(s). + It is needed in order for the logger to be able to record UORB topics. + +### Constants and Enums + +A message may define any number of constants. +These define predefined values for fields, such as indicators of states, and flag values. + +For example, here are two constants for indicating battery warnings. + +```sh +uint8 WARNING_NONE = 0 # No battery low voltage warning active. +uint8 WARNING_LOW = 1 # Warning of low voltage. +``` + +A constant is a field with a value. +It has a _type_ followed by a _name_, and should also have a _comment_ with a description. +Unlike fields, there are no "array constants" and there is no need for metatdata. + +The format is as shown: + +```sh + = # +``` + +- `type`: + - Must match the `type` in the field with which it is to be used. +- `name` + - An message-unique string which is by convention upper-cased and uses `underline_snake_case`. + - Constant names that can be used with a field should share the same prefix where possible and should indicate the value's purpose. +- `description` + - A terse description of the purpose of the constant. + The description is a sentence: use capital first letter and terminate in a full stop. + It should all be on one line. + +An enum is a set of enumerated constants that can be used as values to assign a particular field. +UORB has no formal syntax to define enums, but they are effectively defined by convention. +Constants that share similar purposes should be grouped together in the message, and given the same prefix. +This prefix is the enum name, and is referenced in the field documentation using the `[@enum <>]` metadata. +A field can specify multiple enum values in its metadata, so you don't have to name unlike constants together to suit the field. + ### Multi-Topic Messages Sometimes it is useful to use the same message definition for multiple topics. From d4d3f8e79720d3cc9c2c93a8f14e9eec3aa3d570 Mon Sep 17 00:00:00 2001 From: Hamish Willee Date: Thu, 12 Jun 2025 18:31:37 +1000 Subject: [PATCH 2/2] Improve intro, I hope --- docs/en/middleware/uorb.md | 210 ++++++++++++++++++++++++++++--------- 1 file changed, 160 insertions(+), 50 deletions(-) diff --git a/docs/en/middleware/uorb.md b/docs/en/middleware/uorb.md index fd3108830ec2..90703559d7d1 100644 --- a/docs/en/middleware/uorb.md +++ b/docs/en/middleware/uorb.md @@ -1,11 +1,35 @@ # uORB Messaging +The Micro Object Request Broker (uORB) is PX4s low-latency asynchronous `publish()` / `subscribe()` messaging API for inter-thread/inter-process communication. +It allows the different modules of the system to communicate effectively, while still being loosely coupled, and hence easily replaced. + ## Introduction -The uORB is an asynchronous `publish()` / `subscribe()` messaging API used for inter-thread/inter-process communication. +PX4 modules communicate using uORB _topics_. +A topic represents a communication channel for sending _messages_ between a publisher module and one or more subscriber modules. +A module that is interested in receiving messages can subscribe to a topic and use it to check for, and read, new messages. +A module that wants to send messages to a particular topic (and hence all subscribers) must _advertise_ that it is going to do so, and can then _publish_ messages when it has new data. + +A topic behaves like a queue to which publishers write, and from which subscribers read. +By default he queue can only buffer a single message, which may be overwritten if the publisher writes new message data before subscribers can read it. +The [queue size may be increased](#uorb-buffer-length-orb-queue-length) in the rare cases when subscribers really need to receive every message. + +A message is a discrete sample of data that can be published/subscribed via a topic. +The message fields, the constants that can be used with those fields, and the topic(s) to which the message can be published/subscribed are defined in a uORB message definition file. + +By default a single topic is automatically created for each message definition file, which is created by `underscore_snake_casing` the (CamelCase) message definition file name. +For example, topic `battery_status` is automatically created for the `BatteryStatus.msg`. +This is generally what you want if the message is always about the same kind of data (batteries in this case) and so all the subscribers will be interested in the same messages. + +Sometimes the same message structure can be used to represent data from different kinds of sources, which will have different sets of interested publishers and subscribers. +In this case the topics need to be explicitly declared. +For example the [VehicleGlobalPosition.msg](../msg_docs/VehicleGlobalPosition.md) can be used for sending messages about global position from an estimator, GNSS, or an external source: the fields are the same, but the source and subscribers of the data may be different. + +uORB also provides a mechanism to publish multiple independent instances of the same topic. +This is useful, for example, if the system has several sensors of the same type. uORB is implemented in the [`uorb` module](../modules/modules_communication.md#uorb). -It is started automatically (with `uorb start`) early in the PX4 boot sequence, as many applications depend on it. +The module is started automatically (with `uorb start`) early in the PX4 boot sequence, as many applications depend on it. Unit tests can be started with `uorb_tests`. This document explains how to add uORB message definitions and their corresponding topic(s), how to use reference a topic in code, and how to view topics as they change in PX4. @@ -42,20 +66,20 @@ In code you refer to the topic using its id, which in this example would be: `OR ## Message Definitions -The message definition should start with a descriptive _comment_ that outlines its purpose (a comment starts with the `#` symbol and goes to the end of the line). +Every message should start with a [message description](#message-description) that outlines its purpose (a comment starts with the `#` symbol and goes to the end of the line). The message will then define one or more fields, which are defined with a _type_, such as `bool`, `uint8`, and `float32`, followed by a _name_. By convention, each field is followed by a descriptive _comment_, which is any text from the `#` symbol to the end of the line. -::: warning -All message definitions **must** include the `uint64_t timestamp` field, and this should be filled in when publishing the associated topic(s). -This field is needed in order for the logger to be able to record UORB topics. -::: - ::: info All _versioned_ messages definitions must include the `uint32 MESSAGE_VERSION` field. For more information, refer to the [Message Versioning](#message-versioning) section. ::: +::: warning +All message definitions **must** include the `uint64_t timestamp` field, and this should be filled in when publishing the associated topic(s). +This field is needed in order for the logger to be able to record UORB topics. +::: + For example the [VelocityLimits](../msg_docs/VelocityLimits.md) message definition shown below has a descriptive comment, followed by a number of fields, which each have a comment. ```text @@ -74,9 +98,45 @@ By default this message definition will be compiled to a single topic with an id This is the simplest form of a message. See the existing [`msg`](../msg_docs/index.md) files for other examples of how messages are defined. +#### Message Description + +Every message should start with a [comment](#comments) block that describes the message (one or more of lines that all start with `#`). +The first comment line is mandatory and provides the short description. +This may be followed by an empty comment line and then a optional long description. + +```text +# Short description +# +# Long(er) description for the message +# that can be multiline +``` + +The short description should provide a succinct explanation for the purpose of the message. +Minimally it may just mirror the message name. +For example, [`BatteryStatus`](../msg_docs/BatteryStatus.md) has the short description `Battery status`. + +The long description should provide any additional context required to understand what how the message is used. +It might explain who are the publishers and who are the expected consumers, such as MAVLink or the logging system. +It might also cover whether the message is only used for a particular frame type or mode. + +Both short and long descriptions may be multi-line. +The long description may also include empty comment lines (the short description cannot, because the first empty comment delineates the short and long description). +A terminating full stop can be omitted from single line comments and from the final line. + +The block ends at the first non-comment line, such as an empty line, field, or constant. +Any subsequent comment lines are considered "internal comments". + +### Comments + +Comments are text provided for explanation or documentation purposes. +Any text after a `#` character is a comment (with the exception of lines that [start with `# TOPIC`](#multi-topic-message)). + +PX4 uses structured comments for message, field, and constant descriptions. +Other comments are internal. + ### Fields -Messages define one or more fields, which are the message variables that are written and read by publishers and subscribers, respectively. +Messages define one or more fields, which are the variables that are written and read by publishers and subscribers, respectively. A typical field might look like this: @@ -84,7 +144,7 @@ A typical field might look like this: float64 lat # [deg] Latitude (WGS84). ``` -Each field minimally has a _type_ followed by a _name_, and should also have a _comment_ with optional _metadata_ and a comment +Each field has a _type_ followed by a _name_, and should also have a _comment_ The format is as shown: ```sh @@ -97,24 +157,30 @@ The format is as shown: - `name` - Any message-unique string. By convention use lower case `underline_snake_case`. -- `metadata` - - Provides information about the field, such as units and allowed values. + +The comment must all be on the same line as the field, and should consist of optional metadata and a description: + +- `metadata` (Optional) + - Information about the field units and allowed values: - `[]` - - The units inside square brackets (note, no delineator). For example `[m]` or `[deg]`. + - The unit of measurement inside square brackets (note, no `@` delineator indicates a unit). + For example `[m]` or `[deg]`. Typical units include: `m`, `deg`, `m/s`, `rad`, `rad/s`, and so on. - - `[@enum ]` - - An enum name (or space-separated names) that indicate sets of allowed constant values. - Enums are not specifically defined in the file, but all constants that share the enum prefix listed can be used in the field. - - `[@range , ]` - - The allowed range of the field. Either the lower or upper value can be omitted to indicate an unbounded value. - For example `[@range 0, 3]`, `[@range 5.3, ]` + - `[@enum ]` + - The `enum_name` gives the prefix of constant values in the message that can be assigned to the field. + Note that in UORB "enums" are a naming convention: they are not explicitly declared. + Multiple enum names indicate a possible error in the field design. + - `[@range , ]` + - The allowed range of the field, specified as a `lower_value` and/or an `upper_value`. + Either value can be omitted to indicate an unbounded upper or lower value. + For example `[@range 0, 3]`, `[@range 5.3, ]`, `[@range , 3]`. - `[@invalid ]` - - The value to set the field to indicate that the value is unknown. The description is optional. + - The `value` to set the field to indicate that the field doesn't contain valid data. + The `description` is optional, and might be used to indicate the conditions under which data is invalid. - `description` - - A terse description of the purpose of the field and allowed values. - Take care to include any information that can't be inferred from the name! - The description is a sentence: use capital first letter and terminate in a full stop. - It should all be on one line. + - A concise description of the purpose of the field and allowed values, and including any important information that can't be inferred from the name! + Use a capital first letter, and omit the full stop if the description is a single sentence. + Multiple sentences may also omit the final full stop. #### Array Fields @@ -128,29 +194,34 @@ For example: int32[12] raw_data # ADC channel raw value, accept negative value. ``` -#### Mandatory fields +#### Mandatory Fields All message definitions **must** include following fields: - `uint64_t timestamp` - This should be filled in when publishing the associated topic(s). It is needed in order for the logger to be able to record UORB topics. + - The comment should be `# [us] Time since system start`. + +### Constants -### Constants and Enums +Constants specify a mapping between a name and a value. -A message may define any number of constants. -These define predefined values for fields, such as indicators of states, and flag values. +These are mainly used to predefine useful values that you might need to use for a particular field, such as a state or flag values. +Often these are grouped together as [enums](#enums). +There are also a small number of [metadata constants](#metadata-constants) that are used by the build infrastructure. -For example, here are two constants for indicating battery warnings. +For example, here are a number of constants for indicating battery warnings. ```sh -uint8 WARNING_NONE = 0 # No battery low voltage warning active. -uint8 WARNING_LOW = 1 # Warning of low voltage. +uint8 WARNING_NONE = 0 # No battery low voltage warning active +uint8 WARNING_LOW = 1 # Low voltage warning ``` -A constant is a field with a value. -It has a _type_ followed by a _name_, and should also have a _comment_ with a description. -Unlike fields, there are no "array constants" and there is no need for metatdata. +Constants are specified as a field assigned with a value. +The field part has a _type_, which must match the type of the field they are to be used with, followed by a _name_. +They should also have a _comment_ with a description. +By convention they are defined immediately below the field with which they can used. The format is as shown: @@ -159,31 +230,70 @@ The format is as shown: ``` - `type`: - - Must match the `type` in the field with which it is to be used. + - Must match the `type` of the field with which it is to be used. - `name` - - An message-unique string which is by convention upper-cased and uses `underline_snake_case`. - - Constant names that can be used with a field should share the same prefix where possible and should indicate the value's purpose. + - The name of the constant. + This must be message-unique and is by convention `ALL_UPPER_CASE_UNDERLINE_SNAKE_CASE` + - Constant names that can be used with a field should share the same prefix and should indicate the value's purpose. + +The comment must all be on the same line as the field. +Note that this is much like the field description (but there is no metadata): + - `description` - A terse description of the purpose of the constant. - The description is a sentence: use capital first letter and terminate in a full stop. - It should all be on one line. + Use a capital first letter, and omit the full stop if the description is a single sentence. + Multiple sentences may also omit the final full stop. + +#### Enums + +Enums are groups/sets of enumerated constants that can be used as values for a particular field. -An enum is a set of enumerated constants that can be used as values to assign a particular field. -UORB has no formal syntax to define enums, but they are effectively defined by convention. -Constants that share similar purposes should be grouped together in the message, and given the same prefix. -This prefix is the enum name, and is referenced in the field documentation using the `[@enum <>]` metadata. -A field can specify multiple enum values in its metadata, so you don't have to name unlike constants together to suit the field. +UORB does not define a formal syntax for enums. +Instead we use a prefix naming convention to indicate all the constants that are part of the same enum. +The constants in the enum should be declared immediately after the field in which they are used, and for parsing convenience, the prefix is listed in the field using `@enum` metadata. -### Multi-Topic Messages +For example, here is the definition of the `warning` field and some of the `WARNING` enum values that can be used with it: + +```sh +uint8 warning # [@enum WARNING] Current battery warning +uint8 WARNING_NONE = 0 # No battery low voltage warning active +uint8 WARNING_LOW = 1 # Low voltage warning +uint8 WARNING_CRITICAL = 2 # Critical voltage, return / abort immediately +... +``` + +#### Metadata Constants + +A number of constants provide information that is used by the PX4 build system to configure how the message may be used, such as the version and length of the message. +If relevant, these should appear near the top of the file, immediately after the [Message Description](#message-description). + +The allowed constants are: + +- `ORB_QUEUE_LENGTH` - Sets the [uORB Buffer Length](#uorb-buffer-length-orb-queue-length), which is used in rare cases where a subscriber needs all values that are set for a field, rather than just the most recent sample. +- `MESSAGE_VERSION` - Sets the version number of a versioned message. + This is used as part of the infrastructure to maintain compatibility between PX4 and ROS 2 versions compiled against different message definitions. + For more information see [Message Versioning](#message-versioning) + +#### Multi-Topic Messages (`# TOPICS`) {#multi-topic-messages} + +By default a single topic is automatically created for each message definition file, which is created by `underscore_snake_casing` the (CamelCase) message definition file name. +For example, topic `battery_status` is automatically created for the `BatteryStatus.msg`. +This is generally what you want if the message is always about the same kind of data (batteries in this case) and so all the subscribers will be interested in the same messages. Sometimes it is useful to use the same message definition for multiple topics. -This can be specified at the end of the message using a line prefixed with `# TOPICS `, followed by space-separated topic ids. -For example, the [ActuatorOutputs](../msg_docs/ActuatorOutputs.md) message definition is used to define the topic ids as shown: +In this case the topics need to be explicitly declared. +You can do this by adding one or more lines to the end of the message prefixed with `# TOPICS`, followed by space-separated topic ids. + +For example, the [VehicleGlobalPosition.msg](../msg_docs/VehicleGlobalPosition.md) message definition is used to define the topic ids as shown: ```text -# TOPICS actuator_outputs actuator_outputs_sim actuator_outputs_debug +# TOPICS vehicle_global_position vehicle_global_position_groundtruth external_ins_global_position +# TOPICS estimator_global_position +# TOPICS aux_global_position ``` +Note that multiple topics are useful in this case because the likely subscribers for the different sources of global position are likely to be different. + ### Nested Messages Message definitions can be nested within other messages to create complex data structures. @@ -195,7 +305,7 @@ To nest a message, simply include the nested message type in the parent message # # This are the three next waypoints (or just the next two or one). -uint64 timestamp # [us] Time since system start. +uint64 timestamp # [us] Time since system start PositionSetpoint previous PositionSetpoint current @@ -233,7 +343,7 @@ As there are external tools using uORB messages from log files, such as [Flight This is to ensure that removed fields (or messages) are not re-added in future. - In case of a semantic change (e.g. the unit changes from degrees to radians), the field must be renamed as well and the previous one marked as deprecated as above. -## Message Versioning +## Message Versioning (MESSAGE_VERSION) {#message-versioning}