ros2_client/
parameters.rs

1//! Rust-like representation of ROS2 Parameters
2//!
3//! Parameters are key-value paris that can be set in application code, on the
4//! command line (not yet implemented), from environment variables (not
5//! implemented), or remotely.
6//!
7//! Paramters can be queried and set remotely using e.g. the `ros2 param` or
8//! `rqt` tools from ROS 2. This only works for [`Node`](crate::Node)s that have
9//! enabled Parameter Services and are running a `Spinner`.
10
11/// Named parameter
12#[derive(Debug, Clone)]
13pub struct Parameter {
14  pub name: String,
15  pub value: ParameterValue,
16}
17
18/// Rust-like representation of ROS2
19/// [ParameterValue](https://github.com/ros2/rcl_interfaces/blob/master/rcl_interfaces/msg/ParameterValue.msg)
20#[derive(Debug, Clone)]
21pub enum ParameterValue {
22  NotSet,
23  Boolean(bool),
24  Integer(i64),
25  Double(f64),
26  String(String),
27  ByteArray(Vec<u8>),
28  BooleanArray(Vec<bool>),
29  IntegerArray(Vec<i64>),
30  DoubleArray(Vec<f64>),
31  StringArray(Vec<String>),
32}
33
34/// List of Parameter types supported by ROS 2.
35/// <https://github.com/ros2/rcl_interfaces/blob/humble/rcl_interfaces/msg/ParameterType.msg>
36pub enum ParameterType {
37  NotSet = 0,
38  Bool = 1,
39  Integer = 2,
40  Double = 3,
41  String = 4,
42  ByteArray = 5,
43  BoolArray = 6,
44  IntegerArray = 7,
45  DoubleArray = 8,
46  StringArray = 9,
47}
48
49impl ParameterValue {
50  // https://github.com/ros2/rcl_interfaces/blob/rolling/rcl_interfaces/msg/ParameterType.msg
51  pub fn to_parameter_type(&self) -> ParameterType {
52    match self {
53      ParameterValue::NotSet => ParameterType::NotSet,
54      ParameterValue::Boolean(_) => ParameterType::Bool,
55      ParameterValue::Integer(_) => ParameterType::Integer,
56      ParameterValue::Double(_d) => ParameterType::Double,
57      ParameterValue::String(_s) => ParameterType::String,
58      ParameterValue::ByteArray(_a) => ParameterType::ByteArray,
59      ParameterValue::BooleanArray(_a) => ParameterType::BoolArray,
60      ParameterValue::IntegerArray(_a) => ParameterType::IntegerArray,
61      ParameterValue::DoubleArray(_a) => ParameterType::DoubleArray,
62      ParameterValue::StringArray(_a) => ParameterType::StringArray,
63    }
64  }
65
66  pub fn to_parameter_type_raw(p: &ParameterValue) -> u8 {
67    Self::to_parameter_type(p) as u8
68  }
69}
70
71impl From<raw::Parameter> for Parameter {
72  fn from(rp: raw::Parameter) -> Self {
73    Parameter {
74      name: rp.name,
75      value: rp.value.into(),
76    }
77  }
78}
79
80impl From<raw::ParameterValue> for ParameterValue {
81  fn from(rpv: raw::ParameterValue) -> ParameterValue {
82    match rpv.ptype {
83      raw::ParameterType::NOT_SET => ParameterValue::NotSet,
84      raw::ParameterType::BOOL => ParameterValue::Boolean(rpv.boolean_value),
85      raw::ParameterType::INTEGER => ParameterValue::Integer(rpv.int_value),
86      raw::ParameterType::DOUBLE => ParameterValue::Double(rpv.double_value),
87      raw::ParameterType::STRING => ParameterValue::String(rpv.string_value),
88
89      raw::ParameterType::BYTE_ARRAY => ParameterValue::ByteArray(rpv.byte_array),
90      raw::ParameterType::BOOL_ARRAY => ParameterValue::BooleanArray(rpv.bool_array),
91      raw::ParameterType::INTEGER_ARRAY => ParameterValue::IntegerArray(rpv.int_array),
92      raw::ParameterType::DOUBLE_ARRAY => ParameterValue::DoubleArray(rpv.double_array),
93      raw::ParameterType::STRING_ARRAY => ParameterValue::StringArray(rpv.string_array),
94
95      _ =>
96      // This may be an unspecified case.
97      // TODO: Do something better, at least log a warning.
98      {
99        ParameterValue::NotSet
100      }
101    }
102  }
103}
104
105impl From<Parameter> for raw::Parameter {
106  fn from(p: Parameter) -> raw::Parameter {
107    raw::Parameter {
108      name: p.name,
109      value: p.value.into(),
110    }
111  }
112}
113
114impl From<ParameterValue> for raw::ParameterValue {
115  fn from(p: ParameterValue) -> raw::ParameterValue {
116    let mut value = raw::ParameterValue {
117      ptype: raw::ParameterType::NOT_SET,
118      boolean_value: false,
119      int_value: 0,
120      double_value: 0.0,
121      string_value: String::new(),
122      byte_array: Vec::new(),
123      int_array: Vec::new(),
124      bool_array: Vec::new(),
125      double_array: Vec::new(),
126      string_array: Vec::new(),
127    };
128    match p {
129      ParameterValue::NotSet => (), // already there
130      ParameterValue::Boolean(b) => {
131        value.ptype = raw::ParameterType::BOOL;
132        value.boolean_value = b;
133      }
134      ParameterValue::Integer(i) => {
135        value.ptype = raw::ParameterType::INTEGER;
136        value.int_value = i;
137      }
138      ParameterValue::Double(d) => {
139        value.ptype = raw::ParameterType::DOUBLE;
140        value.double_value = d;
141      }
142      ParameterValue::String(s) => {
143        value.ptype = raw::ParameterType::STRING;
144        value.string_value = s;
145      }
146      ParameterValue::ByteArray(a) => {
147        value.ptype = raw::ParameterType::BYTE_ARRAY;
148        value.byte_array = a;
149      }
150      ParameterValue::BooleanArray(a) => {
151        value.ptype = raw::ParameterType::BOOL_ARRAY;
152        value.bool_array = a;
153      }
154      ParameterValue::IntegerArray(a) => {
155        value.ptype = raw::ParameterType::INTEGER_ARRAY;
156        value.int_array = a;
157      }
158      ParameterValue::DoubleArray(a) => {
159        value.ptype = raw::ParameterType::DOUBLE_ARRAY;
160        value.double_array = a;
161      }
162      ParameterValue::StringArray(a) => {
163        value.ptype = raw::ParameterType::STRING_ARRAY;
164        value.string_array = a;
165      }
166    }
167    value
168  }
169} // impl From
170
171/// Result from attempt to set a Parameter value (remotely).
172pub type SetParametersResult = Result<(), String>;
173
174impl From<SetParametersResult> for raw::SetParametersResult {
175  fn from(s: SetParametersResult) -> raw::SetParametersResult {
176    match s {
177      Ok(_) => raw::SetParametersResult {
178        successful: true,
179        reason: "".to_string(),
180      },
181      Err(reason) => raw::SetParametersResult {
182        successful: false,
183        reason,
184      },
185    }
186  }
187}
188
189/// Documentation and constraints for a [`Parameter`]
190pub struct ParameterDescriptor {
191  pub name: String,
192  pub param_type: ParameterType, // ParameterType.msg defines enum
193  pub description: String,       /* Description of the parameter, visible from
194                                  * introspection tools. */
195  pub additional_constraints: String, /* Plain English description of additional constraints
196                                       * which cannot be expressed.. */
197  pub read_only: bool, // If 'true' then the value cannot change after it has been initialized.
198  pub dynamic_typing: bool, // If true, the parameter is allowed to change type.
199  pub range: NumericRange,
200}
201
202impl ParameterDescriptor {
203  pub fn unknown(name: &str) -> Self {
204    ParameterDescriptor {
205      name: name.to_string(),
206      param_type: ParameterType::NotSet,
207      description: "unknown parameter".to_string(),
208      additional_constraints: "".to_string(),
209      read_only: true,
210      dynamic_typing: false,
211      range: NumericRange::NotSpecified,
212    }
213  }
214
215  pub fn from_value(name: &str, value: &ParameterValue) -> Self {
216    ParameterDescriptor {
217      name: name.to_string(),
218      param_type: value.to_parameter_type(),
219      description: "(description missing, not implemented)".to_string(),
220      additional_constraints: "".to_string(),
221      read_only: false,
222      dynamic_typing: false,
223      range: NumericRange::NotSpecified,
224    }
225  }
226}
227
228/// Optional Limits for a numeric [`Parameter`]
229pub enum NumericRange {
230  NotSpecified,
231  IntegerRange {
232    from_value: i64,
233    to_value: i64,
234    step: i64,
235  },
236  FloatingPointRange {
237    from_value: f64,
238    to_value: f64,
239    step: f64,
240  },
241}
242
243impl From<ParameterDescriptor> for raw::ParameterDescriptor {
244  fn from(p: ParameterDescriptor) -> raw::ParameterDescriptor {
245    let (integer_range, floating_point_range) = match p.range {
246      NumericRange::NotSpecified => (vec![], vec![]),
247
248      NumericRange::IntegerRange {
249        from_value,
250        to_value,
251        step,
252      } => (
253        vec![raw::IntegerRange {
254          from_value,
255          to_value,
256          step,
257        }],
258        vec![],
259      ),
260
261      NumericRange::FloatingPointRange {
262        from_value,
263        to_value,
264        step,
265      } => (
266        vec![],
267        vec![raw::FloatingPointRange {
268          from_value,
269          to_value,
270          step,
271        }],
272      ),
273    };
274
275    raw::ParameterDescriptor {
276      name: p.name,
277      r#type: p.param_type as u8,
278      description: p.description,
279      additional_constraints: p.additional_constraints,
280      read_only: p.read_only,
281      dynamic_typing: p.dynamic_typing,
282      integer_range,
283      floating_point_range,
284    }
285  }
286}
287
288/// Raw, ROS2-compatible Parameters for sending over the wire.
289/// Not for use in a Rust application.
290pub mod raw {
291  use rustdds::*;
292  use serde::{Deserialize, Serialize};
293
294  /// ROS2 [ParameterEvent](https://github.com/ros2/rcl_interfaces/blob/master/rcl_interfaces/msg/ParameterEvent.msg)
295  #[derive(Debug, Clone, Serialize, Deserialize)]
296  pub struct ParameterEvent {
297    pub timestamp: Timestamp,
298    // fully qualified path
299    pub node: String,
300    pub new_parameters: Vec<Parameter>,
301    pub changed_parameters: Vec<Parameter>,
302    pub deleted_parameters: Vec<Parameter>,
303  }
304
305  /// [Parameter](https://github.com/ros2/rcl_interfaces/blob/master/rcl_interfaces/msg/Parameter.msg)
306  #[derive(Debug, Clone, Serialize, Deserialize)]
307  pub struct Parameter {
308    pub name: String,
309    pub value: ParameterValue,
310  }
311
312  /// [ParameterValue](https://github.com/ros2/rcl_interfaces/blob/master/rcl_interfaces/msg/ParameterValue.msg)
313  #[derive(Debug, Clone, Serialize, Deserialize)]
314  pub struct ParameterValue {
315    pub ptype: u8,
316    pub boolean_value: bool,
317    pub int_value: i64,
318    pub double_value: f64,
319    pub string_value: String,
320    pub byte_array: Vec<u8>,
321    pub bool_array: Vec<bool>,
322    pub int_array: Vec<i64>,
323    pub double_array: Vec<f64>,
324    pub string_array: Vec<String>,
325  }
326
327  /// ROS2 defines this as an empty .msg
328  /// [ParameterType](https://github.com/ros2/rcl_interfaces/blob/master/rcl_interfaces/msg/ParameterType.msg)
329  pub struct ParameterType {}
330
331  impl ParameterType {
332    pub const NOT_SET: u8 = 0;
333
334    pub const BOOL: u8 = 1;
335    pub const INTEGER: u8 = 2;
336    pub const DOUBLE: u8 = 3;
337    pub const STRING: u8 = 4;
338    pub const BYTE_ARRAY: u8 = 5;
339    pub const BOOL_ARRAY: u8 = 6;
340    pub const INTEGER_ARRAY: u8 = 7;
341    pub const DOUBLE_ARRAY: u8 = 8;
342    pub const STRING_ARRAY: u8 = 9;
343  }
344
345  /// [SetParameersResult](https://github.com/ros2/rcl_interfaces/blob/rolling/rcl_interfaces/msg/SetParametersResult.msg)
346  #[derive(Debug, Clone, Serialize, Deserialize)]
347  pub struct SetParametersResult {
348    pub successful: bool,
349    pub reason: String,
350  }
351
352  /// [ParameterDescriptor](https://github.com/ros2/rcl_interfaces/blob/humble/rcl_interfaces/msg/ParameterDescriptor.msg)
353  #[derive(Debug, Clone, Serialize, Deserialize)]
354  pub struct ParameterDescriptor {
355    pub name: String,
356    pub r#type: u8, // ParameterType.msg defines enum
357    pub description: String, /* Description of the parameter, visible from
358                     * introspection tools. */
359    pub additional_constraints: String, /* Plain English description of additional constraints
360                                         * which cannot be expressed.. */
361    pub read_only: bool, // If 'true' then the value cannot change after it has been initialized.
362    pub dynamic_typing: bool, // If true, the parameter is allowed to change type.
363    pub floating_point_range: Vec<FloatingPointRange>,
364    pub integer_range: Vec<IntegerRange>,
365  }
366
367  /// [IntegerRange](https://github.com/ros2/rcl_interfaces/blob/humble/rcl_interfaces/msg/IntegerRange.msg)
368  #[derive(Debug, Clone, Serialize, Deserialize)]
369  pub struct IntegerRange {
370    pub from_value: i64,
371    pub to_value: i64,
372    pub step: i64,
373  }
374
375  /// [FloatingPointRange](https://github.com/ros2/rcl_interfaces/blob/humble/rcl_interfaces/msg/FloatingPointRange.msg)
376  #[derive(Debug, Clone, Serialize, Deserialize)]
377  pub struct FloatingPointRange {
378    pub from_value: f64,
379    pub to_value: f64,
380    pub step: f64,
381  }
382}