diff --git a/README.md b/README.md index bcd2402..9bea3b4 100644 --- a/README.md +++ b/README.md @@ -1,25 +1,23 @@ R2R - Minimal ROS2 Rust bindings ============= -Minimal bindings for ROS2 that does *not* require hooking in to the ROS2 build infrastructure, in contrast to . Message definitions are instead created by calling into the c introspection libraries to avoid the .msg/.idl pipeline. +Minimal bindings for ROS2 that does *not* require hooking in to the ROS2 build infrastructure. If you want a more ROS-oriented approach, see . In these bindings, convenience Rust types are created by calling into the c introspection libraries to circumvent the .msg/.idl pipeline. Another benefit of basing the code entirely on the exported shared libraries is that the native c types are still there when you need to trade convenience for performance. E.g. for looking into a large array of image data you can still get a pointer to the raw message. How to use ------------ -You need to source your ros installation before building/running. A couple of examples are included in examples/ +You need to source your ROS2 installation before building/running. A couple of examples are included in examples/ ``` . /opt/ros/dashing/setup.sh cargo build cargo run --example subscriber_with_thread ``` - -In order to avoid building everything, put the message types you need in msgs.txt. +In order to avoid building everything, put the message types you need in `msgs.txt` before building. (Or just `ros2 msg list > msgs.txt`). What works? -------- - Only tested with ROS2 Dashing - Simple publish/subscribe, see examples. - TODO ------------ - The code generation is currently just a big hack. Needs cleanup and refactoring. diff --git a/examples/publish_complex_msgs.rs b/examples/publish_complex_msgs.rs index 8225b7e..99c3c7b 100644 --- a/examples/publish_complex_msgs.rs +++ b/examples/publish_complex_msgs.rs @@ -25,11 +25,16 @@ fn main() -> Result<(), ()> { println!("JTP serialized as: {}", serialized); }; + let cb3 = move |raw_c:&WrappedNativeMsg| { + println!("Raw c data: {:?}", (*raw_c).positions); + }; + let sub1 = rcl_create_subscription(&mut node, "/hopp", Box::new(cb))?; let sub2 = rcl_create_subscription(&mut node, "/hej", Box::new(cb2))?; + let sub3 = rcl_create_subscription_native(&mut node, "/hej", Box::new(cb3))?; // TODO: group subscriptions in a "node" struct - let mut subst: Vec> = vec![Box::new(sub1), Box::new(sub2)]; + let mut subst: Vec> = vec![Box::new(sub1), Box::new(sub2), Box::new(sub3)]; // run for 10 seconds let mut count = 0; diff --git a/src/lib.rs b/src/lib.rs index eff3206..4a442c4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -94,6 +94,15 @@ where pub rcl_msg: WrappedNativeMsg, } +pub struct WrappedSubNative +where + T: WrappedTypesupport, +{ + pub rcl_handle: rcl_subscription_t, + pub callback: Box) -> ()>, + pub rcl_msg: WrappedNativeMsg, +} + impl Sub for WrappedSubT where T: WrappedTypesupport, @@ -113,6 +122,25 @@ where } } +impl Sub for WrappedSubNative +where + T: WrappedTypesupport, +{ + fn handle(&self) -> &rcl_subscription_t { + &self.rcl_handle + } + + fn rcl_msg(&mut self) -> *mut std::os::raw::c_void { + self.rcl_msg.void_ptr_mut() + } + + fn run_cb(&mut self) -> () { + // *dont't* copy native msg to rust type. + // e.g. if you for instance have large image data... + (self.callback)(&self.rcl_msg); + } +} + pub fn rcl_create_context() -> Result { let mut ctx = unsafe { rcl_get_zero_initialized_context() }; let isok = unsafe { @@ -248,6 +276,42 @@ where } } +pub fn rcl_create_subscription_native( + node: &mut rcl_node_t, + topic: &str, + callback: Box) -> ()>, +) -> Result, ()> +where + T: WrappedTypesupport, +{ + let mut subscription_handle = unsafe { rcl_get_zero_initialized_subscription() }; + let topic_c_string = CString::new(topic).unwrap(); + + let result = unsafe { + let mut subscription_options = rcl_subscription_get_default_options(); + subscription_options.qos = rmw_qos_profile_t::default(); + rcl_subscription_init( + &mut subscription_handle, + node, + T::get_ts(), + topic_c_string.as_ptr(), + &subscription_options, + ) + }; + if result == RCL_RET_OK as i32 { + let wrapped_sub = WrappedSubNative { + rcl_handle: subscription_handle, + rcl_msg: WrappedNativeMsg::::new(), + callback: callback, + }; + + Ok(wrapped_sub) + } else { + eprintln!("{}", result); + Err(()) + } +} + pub fn rcl_take_subst( ctx: &mut rcl_context_t, subs: &mut Vec>,