Compare commits
2 Commits
56acba5dd5
...
455ea630ec
| Author | SHA1 | Date |
|---|---|---|
|
|
455ea630ec | |
|
|
aa180c5b15 |
|
|
@ -14,7 +14,7 @@ These bindings are being written organically when things are needed by me and ot
|
||||||
How to use
|
How to use
|
||||||
--------------------
|
--------------------
|
||||||
1. Make sure you have libclang installed. (e.g. libclang-dev on ubuntu)
|
1. Make sure you have libclang installed. (e.g. libclang-dev on ubuntu)
|
||||||
2. Depend on this package in Cargo.toml: `r2r = "0.9.4"`
|
2. Depend on this package in Cargo.toml: `r2r = "0.9.5"`
|
||||||
3. You need to source your ROS2 installation before building/running.
|
3. You need to source your ROS2 installation before building/running.
|
||||||
4. The bindings will rebuild automatically if/when you source your workspace(s).
|
4. The bindings will rebuild automatically if/when you source your workspace(s).
|
||||||
5. If you make changes to existing message types, run `cargo clean -p r2r_msg_gen` to force recompilation of the rust message types on the next build.
|
5. If you make changes to existing message types, run `cargo clean -p r2r_msg_gen` to force recompilation of the rust message types on the next build.
|
||||||
|
|
@ -47,6 +47,10 @@ Changelog
|
||||||
--------------------
|
--------------------
|
||||||
#### [Unreleased]
|
#### [Unreleased]
|
||||||
|
|
||||||
|
#### [0.9.5] - 2025-04-22
|
||||||
|
- Add `/set_parameters_atomically` <https://github.com/sequenceplanner/r2r/pull/120>, <https://github.com/sequenceplanner/r2r/pull/121>. Fixes `ros2 param ...` on Jazzy.
|
||||||
|
- Update bindgen 0.63.0 -> 0.71.1 <https://github.com/sequenceplanner/r2r/pull/116>. (Issues may persist until next bindgen version, see PR).
|
||||||
|
|
||||||
#### [0.9.4] - 2024-11-21
|
#### [0.9.4] - 2024-11-21
|
||||||
- Fix cargo syntax for older rust versions < 1.77 <https://github.com/sequenceplanner/r2r/commit/74ad4410c79b1be7e42eb1822a291639e3c40ec4>
|
- Fix cargo syntax for older rust versions < 1.77 <https://github.com/sequenceplanner/r2r/commit/74ad4410c79b1be7e42eb1822a291639e3c40ec4>
|
||||||
- Fix message generation for WChar idl type <https://github.com/sequenceplanner/r2r/commit/94db799db282c8b1e0222f1699e6a6420b5fd544>
|
- Fix message generation for WChar idl type <https://github.com/sequenceplanner/r2r/commit/94db799db282c8b1e0222f1699e6a6420b5fd544>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "r2r"
|
name = "r2r"
|
||||||
version = "0.9.4"
|
version = "0.9.5"
|
||||||
authors = ["Martin Dahl <martin.dahl@gmail.com>"]
|
authors = ["Martin Dahl <martin.dahl@gmail.com>"]
|
||||||
description = "Easy to use, runtime-agnostic, async rust bindings for ROS2."
|
description = "Easy to use, runtime-agnostic, async rust bindings for ROS2."
|
||||||
license = "MIT AND Apache-2.0"
|
license = "MIT AND Apache-2.0"
|
||||||
|
|
@ -18,11 +18,11 @@ serde = { version = "1.0.147", features = ["derive"] }
|
||||||
serde_json = "1.0.89"
|
serde_json = "1.0.89"
|
||||||
thiserror = "1.0.37"
|
thiserror = "1.0.37"
|
||||||
lazy_static = "1.4.0"
|
lazy_static = "1.4.0"
|
||||||
r2r_common = { path = "../r2r_common", version = "0.9.4" }
|
r2r_common = { path = "../r2r_common", version = "0.9.5" }
|
||||||
r2r_rcl = { path = "../r2r_rcl", version = "0.9.4" }
|
r2r_rcl = { path = "../r2r_rcl", version = "0.9.5" }
|
||||||
r2r_msg_gen = { path = "../r2r_msg_gen", version = "0.9.4" }
|
r2r_msg_gen = { path = "../r2r_msg_gen", version = "0.9.5" }
|
||||||
r2r_actions = { path = "../r2r_actions", version = "0.9.4" }
|
r2r_actions = { path = "../r2r_actions", version = "0.9.5" }
|
||||||
r2r_macros = { path = "../r2r_macros", version = "0.9.4" }
|
r2r_macros = { path = "../r2r_macros", version = "0.9.5" }
|
||||||
uuid = { version = "1.2.2", features = ["serde", "v4"] }
|
uuid = { version = "1.2.2", features = ["serde", "v4"] }
|
||||||
futures = "0.3.25"
|
futures = "0.3.25"
|
||||||
log = "0.4.18"
|
log = "0.4.18"
|
||||||
|
|
@ -38,8 +38,8 @@ cdr = "0.2.4"
|
||||||
criterion = "0.5.1"
|
criterion = "0.5.1"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
r2r_common = { path = "../r2r_common", version = "0.9.4" }
|
r2r_common = { path = "../r2r_common", version = "0.9.5" }
|
||||||
r2r_msg_gen = { path = "../r2r_msg_gen", version = "0.9.4" }
|
r2r_msg_gen = { path = "../r2r_msg_gen", version = "0.9.5" }
|
||||||
rayon = "1.7.0"
|
rayon = "1.7.0"
|
||||||
force-send-sync = "1.0.0"
|
force-send-sync = "1.0.0"
|
||||||
quote = "1.0.28"
|
quote = "1.0.28"
|
||||||
|
|
|
||||||
|
|
@ -283,9 +283,13 @@ impl Node {
|
||||||
.register_parameters("", None, &mut self.params.lock().unwrap())?;
|
.register_parameters("", None, &mut self.params.lock().unwrap())?;
|
||||||
}
|
}
|
||||||
let mut handlers: Vec<std::pin::Pin<Box<dyn Future<Output = ()> + Send>>> = Vec::new();
|
let mut handlers: Vec<std::pin::Pin<Box<dyn Future<Output = ()> + Send>>> = Vec::new();
|
||||||
let (mut event_tx, event_rx) = mpsc::channel::<(String, ParameterValue)>(10);
|
|
||||||
|
let (mut set_event_tx, event_rx) = mpsc::channel::<(String, ParameterValue)>(10);
|
||||||
|
let mut set_atomically_event_tx = set_event_tx.clone();
|
||||||
|
|
||||||
let node_name = self.name()?;
|
let node_name = self.name()?;
|
||||||
|
|
||||||
|
// rcl_interfaces/srv/SetParameters
|
||||||
let set_params_request_stream = self
|
let set_params_request_stream = self
|
||||||
.create_service::<rcl_interfaces::srv::SetParameters::Service>(
|
.create_service::<rcl_interfaces::srv::SetParameters::Service>(
|
||||||
&format!("{}/set_parameters", node_name),
|
&format!("{}/set_parameters", node_name),
|
||||||
|
|
@ -335,7 +339,7 @@ impl Node {
|
||||||
};
|
};
|
||||||
// if the value changed, send out new value on parameter event stream
|
// if the value changed, send out new value on parameter event stream
|
||||||
if changed && r.successful {
|
if changed && r.successful {
|
||||||
if let Err(e) = event_tx.try_send((p.name.clone(), val)) {
|
if let Err(e) = set_event_tx.try_send((p.name.clone(), val)) {
|
||||||
log::debug!("Warning: could not send parameter event ({}).", e);
|
log::debug!("Warning: could not send parameter event ({}).", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -449,6 +453,82 @@ impl Node {
|
||||||
|
|
||||||
handlers.push(Box::pin(get_param_types_future));
|
handlers.push(Box::pin(get_param_types_future));
|
||||||
|
|
||||||
|
// rcl_interfaces/srv/SetParametersAtomically
|
||||||
|
let set_params_atomically_request_stream =
|
||||||
|
self.create_service::<rcl_interfaces::srv::SetParametersAtomically::Service>(
|
||||||
|
&format!("{}/set_parameters_atomically", node_name),
|
||||||
|
QosProfile::default(),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let params = self.params.clone();
|
||||||
|
let params_struct_clone = params_struct.clone();
|
||||||
|
let set_params_atomically_future = set_params_atomically_request_stream.for_each(
|
||||||
|
move |req: ServiceRequest<rcl_interfaces::srv::SetParametersAtomically::Service>| {
|
||||||
|
let mut result = rcl_interfaces::srv::SetParametersAtomically::Response::default();
|
||||||
|
result.result.successful = true;
|
||||||
|
if let Some(ps) = ¶ms_struct_clone {
|
||||||
|
for p in &req.message.parameters {
|
||||||
|
let val = ParameterValue::from_parameter_value_msg(p.value.clone());
|
||||||
|
if let Err(e) = ps.lock().unwrap().check_parameter(&p.name, &val) {
|
||||||
|
result.result.successful = false;
|
||||||
|
result.result.reason = format!("Can't set parameter {}: {}", p.name, e);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if result.result.successful {
|
||||||
|
// Since we checked them above now we assume these will be set ok...
|
||||||
|
for p in &req.message.parameters {
|
||||||
|
let val = ParameterValue::from_parameter_value_msg(p.value.clone());
|
||||||
|
let changed = params
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.get(&p.name)
|
||||||
|
.map(|v| v.value != val)
|
||||||
|
.unwrap_or(true); // changed=true if new
|
||||||
|
let r = if let Some(ps) = ¶ms_struct_clone {
|
||||||
|
// Update parameter structure
|
||||||
|
let result = ps.lock().unwrap().set_parameter(&p.name, &val);
|
||||||
|
if result.is_ok() {
|
||||||
|
// Also update Node::params
|
||||||
|
params
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.entry(p.name.clone())
|
||||||
|
.and_modify(|p| p.value = val.clone());
|
||||||
|
}
|
||||||
|
rcl_interfaces::msg::SetParametersResult {
|
||||||
|
successful: result.is_ok(),
|
||||||
|
reason: result.err().map_or("".into(), |e| e.to_string()),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// No parameter structure - update only Node::params
|
||||||
|
params
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.entry(p.name.clone())
|
||||||
|
.and_modify(|p| p.value = val.clone())
|
||||||
|
.or_insert(Parameter::new(val.clone()));
|
||||||
|
rcl_interfaces::msg::SetParametersResult {
|
||||||
|
successful: true,
|
||||||
|
reason: "".into(),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// if the value changed, send out new value on parameter event stream
|
||||||
|
if changed && r.successful {
|
||||||
|
if let Err(e) = set_atomically_event_tx.try_send((p.name.clone(), val)) {
|
||||||
|
log::debug!("Warning: could not send parameter event ({}).", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
req.respond(result)
|
||||||
|
.expect("could not send reply to set parameter request");
|
||||||
|
future::ready(())
|
||||||
|
},
|
||||||
|
);
|
||||||
|
handlers.push(Box::pin(set_params_atomically_future));
|
||||||
|
|
||||||
#[cfg(r2r__rosgraph_msgs__msg__Clock)]
|
#[cfg(r2r__rosgraph_msgs__msg__Clock)]
|
||||||
{
|
{
|
||||||
// create TimeSource based on value of use_sim_time parameter
|
// create TimeSource based on value of use_sim_time parameter
|
||||||
|
|
|
||||||
|
|
@ -308,6 +308,7 @@ pub trait RosParams {
|
||||||
) -> Result<()>;
|
) -> Result<()>;
|
||||||
fn get_parameter(&mut self, param_name: &str) -> Result<ParameterValue>;
|
fn get_parameter(&mut self, param_name: &str) -> Result<ParameterValue>;
|
||||||
fn set_parameter(&mut self, param_name: &str, param_val: &ParameterValue) -> Result<()>;
|
fn set_parameter(&mut self, param_name: &str, param_val: &ParameterValue) -> Result<()>;
|
||||||
|
fn check_parameter(&self, param_name: &str, param_val: &ParameterValue) -> Result<()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implementation of RosParams for primitive types, i.e. leaf parameters
|
// Implementation of RosParams for primitive types, i.e. leaf parameters
|
||||||
|
|
@ -360,6 +361,26 @@ macro_rules! impl_ros_params {
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_parameter(
|
||||||
|
&self, param_name: &str, param_val: &ParameterValue,
|
||||||
|
) -> Result<()> {
|
||||||
|
if param_name != "" {
|
||||||
|
return Err(Error::InvalidParameterName {
|
||||||
|
name: param_name.to_owned(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
match param_val {
|
||||||
|
$param_value_type(val) => {
|
||||||
|
let _: Self = $from_param_conv(val)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
_ => Err(Error::InvalidParameterType {
|
||||||
|
name: "".to_string(), // will be completed by callers who know the name
|
||||||
|
ty: std::stringify!($param_value_type),
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "r2r_actions"
|
name = "r2r_actions"
|
||||||
version = "0.9.4"
|
version = "0.9.5"
|
||||||
authors = ["Martin Dahl <martin.dahl@gmail.com>"]
|
authors = ["Martin Dahl <martin.dahl@gmail.com>"]
|
||||||
description = "Internal dependency to the r2r crate."
|
description = "Internal dependency to the r2r crate."
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
|
@ -11,12 +11,12 @@ repository = "https://github.com/sequenceplanner/r2r"
|
||||||
documentation = "https://docs.rs/r2r/latest/r2r"
|
documentation = "https://docs.rs/r2r/latest/r2r"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
r2r_rcl = { path = "../r2r_rcl", version = "0.9.4" }
|
r2r_rcl = { path = "../r2r_rcl", version = "0.9.5" }
|
||||||
r2r_msg_gen = { path = "../r2r_msg_gen", version = "0.9.4" }
|
r2r_msg_gen = { path = "../r2r_msg_gen", version = "0.9.5" }
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
bindgen = "0.71.1"
|
bindgen = "0.71.1"
|
||||||
r2r_common = { path = "../r2r_common", version = "0.9.4" }
|
r2r_common = { path = "../r2r_common", version = "0.9.5" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
save-bindgen = ["r2r_rcl/save-bindgen", "r2r_msg_gen/save-bindgen"]
|
save-bindgen = ["r2r_rcl/save-bindgen", "r2r_msg_gen/save-bindgen"]
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
#
|
#
|
||||||
# For r2r 0.9.4
|
# For r2r 0.9.5
|
||||||
#
|
#
|
||||||
# cmake code for simple colcon integration.
|
# cmake code for simple colcon integration.
|
||||||
# See https://github.com/m-dahl/r2r_minimal_node/
|
# See https://github.com/m-dahl/r2r_minimal_node/
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "r2r_common"
|
name = "r2r_common"
|
||||||
version = "0.9.4"
|
version = "0.9.5"
|
||||||
authors = ["Martin Dahl <martin.dahl@gmail.com>"]
|
authors = ["Martin Dahl <martin.dahl@gmail.com>"]
|
||||||
description = "Minimal ros2 bindings."
|
description = "Minimal ros2 bindings."
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "r2r_macros"
|
name = "r2r_macros"
|
||||||
version = "0.9.4"
|
version = "0.9.5"
|
||||||
authors = ["Martin Dahl <martin.dahl@gmail.com>"]
|
authors = ["Martin Dahl <martin.dahl@gmail.com>"]
|
||||||
description = "Minimal ros2 bindings."
|
description = "Minimal ros2 bindings."
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,8 @@ pub fn derive_r2r_params(input: proc_macro::TokenStream) -> proc_macro::TokenStr
|
||||||
let get_param_matches = param_matches_for(quote!(get_parameter(suffix)), &input.data);
|
let get_param_matches = param_matches_for(quote!(get_parameter(suffix)), &input.data);
|
||||||
let set_param_matches =
|
let set_param_matches =
|
||||||
param_matches_for(quote!(set_parameter(suffix, param_val)), &input.data);
|
param_matches_for(quote!(set_parameter(suffix, param_val)), &input.data);
|
||||||
|
let check_param_matches =
|
||||||
|
param_matches_for(quote!(check_parameter(suffix, param_val)), &input.data);
|
||||||
|
|
||||||
let expanded = quote! {
|
let expanded = quote! {
|
||||||
// The generated impl.
|
// The generated impl.
|
||||||
|
|
@ -64,6 +66,20 @@ pub fn derive_r2r_params(input: proc_macro::TokenStream) -> proc_macro::TokenStr
|
||||||
};
|
};
|
||||||
result.map_err(|e| e.update_param_name(¶m_name))
|
result.map_err(|e| e.update_param_name(¶m_name))
|
||||||
}
|
}
|
||||||
|
fn check_parameter(&self, param_name: &str, param_val: &::r2r::ParameterValue) -> ::r2r::Result<()>
|
||||||
|
{
|
||||||
|
let (prefix, suffix) = match param_name.split_once('.') {
|
||||||
|
None => (param_name, ""),
|
||||||
|
Some((prefix, suffix)) => (prefix, suffix)
|
||||||
|
};
|
||||||
|
let result = match prefix {
|
||||||
|
#check_param_matches
|
||||||
|
_ => Err(::r2r::Error::InvalidParameterName {
|
||||||
|
name: "".into(),
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
result.map_err(|e| e.update_param_name(¶m_name))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "r2r_msg_gen"
|
name = "r2r_msg_gen"
|
||||||
version = "0.9.4"
|
version = "0.9.5"
|
||||||
authors = ["Martin Dahl <martin.dahl@gmail.com>"]
|
authors = ["Martin Dahl <martin.dahl@gmail.com>"]
|
||||||
description = "Internal dependency to the r2r crate."
|
description = "Internal dependency to the r2r crate."
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
|
@ -11,8 +11,8 @@ repository = "https://github.com/sequenceplanner/r2r"
|
||||||
documentation = "https://docs.rs/r2r/latest/r2r"
|
documentation = "https://docs.rs/r2r/latest/r2r"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
r2r_rcl = { path = "../r2r_rcl", version = "0.9.4" }
|
r2r_rcl = { path = "../r2r_rcl", version = "0.9.5" }
|
||||||
r2r_common = { path = "../r2r_common", version = "0.9.4" }
|
r2r_common = { path = "../r2r_common", version = "0.9.5" }
|
||||||
phf = { version = "0.11.1", features = ["macros"] }
|
phf = { version = "0.11.1", features = ["macros"] }
|
||||||
quote = "1.0.28"
|
quote = "1.0.28"
|
||||||
proc-macro2 = "1.0.60"
|
proc-macro2 = "1.0.60"
|
||||||
|
|
@ -22,8 +22,8 @@ rayon = "1.7.0"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
bindgen = "0.71.1"
|
bindgen = "0.71.1"
|
||||||
r2r_rcl = { path = "../r2r_rcl", version = "0.9.4" }
|
r2r_rcl = { path = "../r2r_rcl", version = "0.9.5" }
|
||||||
r2r_common = { path = "../r2r_common", version = "0.9.4" }
|
r2r_common = { path = "../r2r_common", version = "0.9.5" }
|
||||||
quote = "1.0.28"
|
quote = "1.0.28"
|
||||||
syn = { version = "2.0.18", features = ["full"] }
|
syn = { version = "2.0.18", features = ["full"] }
|
||||||
rayon = "1.7.0"
|
rayon = "1.7.0"
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "r2r_rcl"
|
name = "r2r_rcl"
|
||||||
version = "0.9.4"
|
version = "0.9.5"
|
||||||
authors = ["Martin Dahl <martin.dahl@gmail.com>"]
|
authors = ["Martin Dahl <martin.dahl@gmail.com>"]
|
||||||
description = "Internal dependency to the r2r crate."
|
description = "Internal dependency to the r2r crate."
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
|
@ -16,7 +16,7 @@ widestring = "1.0.2"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
bindgen = "0.71.1"
|
bindgen = "0.71.1"
|
||||||
r2r_common = { path = "../r2r_common", version = "0.9.4" }
|
r2r_common = { path = "../r2r_common", version = "0.9.5" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
save-bindgen = []
|
save-bindgen = []
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue