Skip to content

Commit

Permalink
Merge pull request #191 from RosLibRust/topic-provider-improvements
Browse files Browse the repository at this point in the history
Topic provider improvements
  • Loading branch information
Carter12s authored Dec 2, 2024
2 parents 074f0d5 + 33d157f commit 46f1b67
Show file tree
Hide file tree
Showing 15 changed files with 409 additions and 105 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed

- ROS1 Node Handle's advertise() now requires a latching argument
- RosBridge ClientHandle [call_service()] is now templated on the service type instead of on both the request and response type.
This is to bring it in line with the ROS1 API.
- RosBridge ClientHandle::Publisher publish() now takes a reference to the message instead of taking ownership.
This is to bring it in line with the ROS1 API.
- The RosServiceType trait used by codegen now requires 'static + Send + Sync this will not affect any generated types, but custom types may have issue.

## 0.10.2 - August 3rd, 2024

Expand Down
2 changes: 1 addition & 1 deletion roslibrust/examples/basic_publisher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ async fn main() -> Result<(), anyhow::Error> {
loop {
let msg = std_msgs::Header::default();
info!("About to publish");
let result = publisher.publish(msg).await;
let result = publisher.publish(&msg).await;
match result {
Ok(()) => {
info!("Published msg!");
Expand Down
2 changes: 1 addition & 1 deletion roslibrust/examples/calling_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ async fn main() -> Result<(), anyhow::Error> {
let client = ClientHandle::new("ws://localhost:9090").await?;

let result = client
.call_service::<(), rosapi::GetTimeResponse>("/rosapi/get_time", ())
.call_service::<rosapi::GetTime>("/rosapi/get_time", rosapi::GetTimeRequest {})
.await
.expect("Error while calling get_time service");

Expand Down
14 changes: 14 additions & 0 deletions roslibrust/examples/generic_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ async fn main() {
name: String,
}

// Basic example of a node that publishes and subscribes to itself
impl<T: TopicProvider> MyNode<T> {
async fn run(self) {
let publisher = self
Expand All @@ -37,6 +38,19 @@ async fn main() {
.await
.unwrap();

let mut subscriber = self
.ros
.subscribe::<std_msgs::String>("/chatter")
.await
.unwrap();

tokio::spawn(async move {
loop {
let msg = subscriber.next().await.unwrap();
println!("Got message: {}", msg.data);
}
});

loop {
let msg = std_msgs::String {
data: format!("Hello world from {}", self.name),
Expand Down
94 changes: 94 additions & 0 deletions roslibrust/examples/generic_client_services.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
//! Purpose of this example is to show how the ServiceProvider trait can be use
//! to create code that is generic of which communication backend it will use.
#[cfg(feature = "topic_provider")]
#[tokio::main]
async fn main() {
simple_logger::SimpleLogger::new()
.with_level(log::LevelFilter::Debug)
.without_timestamps() // required for running wsl2
.init()
.unwrap();

use roslibrust::topic_provider::*;

roslibrust_codegen_macro::find_and_generate_ros_messages!(
"assets/ros1_common_interfaces/ros_comm_msgs/std_srvs"
);
// TopicProvider cannot be an "Object Safe Trait" due to its generic parameters
// This means we can't do:

// Which specific TopicProvider you are going to use must be known at
// compile time! We can use features to build multiple copies of our
// executable with different backends. Or mix and match within a
// single application. The critical part is to make TopicProvider a
// generic type on you Node.

struct MyNode<T: ServiceProvider + 'static> {
ros: T,
}

// Basic example of a node that publishes and subscribes to itself
impl<T: ServiceProvider> MyNode<T> {
fn handle_service(
_request: std_srvs::SetBoolRequest,
) -> Result<std_srvs::SetBoolResponse, Box<dyn std::error::Error + Send + Sync>> {
// Not actually doing anything here just example
// Note: if we did want to set a bool, we'd probably want to use Arc<Mutex<bool>>
Ok(std_srvs::SetBoolResponse {
success: true,
message: "You set my bool!".to_string(),
})
}

async fn run(self) {
let _handle = self
.ros
.advertise_service::<std_srvs::SetBool, _>("/my_set_bool", Self::handle_service)
.await
.unwrap();

let client = self
.ros
.service_client::<std_srvs::SetBool>("/my_set_bool")
.await
.unwrap();

loop {
tokio::time::sleep(std::time::Duration::from_millis(500)).await;
println!("sleeping");

client
.call(&std_srvs::SetBoolRequest { data: true })
.await
.unwrap();
}
}
}

// create a rosbridge handle and start node
let ros = roslibrust::ClientHandle::new("ws://localhost:9090")
.await
.unwrap();
let node = MyNode { ros };
tokio::spawn(async move { node.run().await });

// create a ros1 handle and start node
let ros = roslibrust::ros1::NodeHandle::new("http://localhost:11311", "/my_node")
.await
.unwrap();
let node = MyNode { ros };
tokio::spawn(async move { node.run().await });

loop {
tokio::time::sleep(std::time::Duration::from_millis(500)).await;
println!("sleeping");
}

// With this executable running
// RUST_LOG=debug cargo run --features ros1,topic_provider --example generic_client_services
// You should see log output from both nodes
}

#[cfg(not(feature = "topic_provider"))]
fn main() {}
2 changes: 1 addition & 1 deletion roslibrust/examples/ros1_ros2_bridge_example.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ async fn main() -> Result<(), anyhow::Error> {
};

// and re-publish it!
publisher.publish(converted_msg).await?;
publisher.publish(&converted_msg).await?;
info!("Message successfully sent to ros2!");
}
}
Expand Down
45 changes: 24 additions & 21 deletions roslibrust/src/rosapi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,13 +100,13 @@ trait RosApi {
impl RosApi for ClientHandle {
/// Get the current time
async fn get_time(&self) -> RosLibRustResult<rosapi::GetTimeResponse> {
self.call_service("/rosapi/get_time", rosapi::GetTimeRequest {})
self.call_service::<rosapi::GetTime>("/rosapi/get_time", rosapi::GetTimeRequest {})
.await
}

/// Get the list of topics active
async fn topics(&self) -> RosLibRustResult<rosapi::TopicsResponse> {
self.call_service("/rosapi/topics", rosapi::TopicsRequest {})
self.call_service::<rosapi::Topics>("/rosapi/topics", rosapi::TopicsRequest {})
.await
}

Expand All @@ -115,7 +115,7 @@ impl RosApi for ClientHandle {
&self,
topic: impl Into<String> + Send,
) -> RosLibRustResult<rosapi::TopicTypeResponse> {
self.call_service(
self.call_service::<rosapi::TopicType>(
"/rosapi/topic_type",
rosapi::TopicTypeRequest {
topic: topic.into(),
Expand All @@ -129,7 +129,7 @@ impl RosApi for ClientHandle {
&self,
topic_type: impl Into<String> + Send,
) -> RosLibRustResult<rosapi::TopicsForTypeResponse> {
self.call_service(
self.call_service::<rosapi::TopicsForType>(
"/rosapi/topics_for_type",
rosapi::TopicsForTypeRequest {
r#type: topic_type.into(),
Expand All @@ -140,7 +140,7 @@ impl RosApi for ClientHandle {

/// Returns list of nodes active in a system
async fn get_nodes(&self) -> RosLibRustResult<rosapi::NodesResponse> {
self.call_service("/rosapi/nodes", rosapi::NodesRequest {})
self.call_service::<rosapi::Nodes>("/rosapi/nodes", rosapi::NodesRequest {})
.await
}

Expand All @@ -150,7 +150,7 @@ impl RosApi for ClientHandle {
&self,
node: impl Into<String> + Send,
) -> RosLibRustResult<rosapi::NodeDetailsResponse> {
self.call_service(
self.call_service::<rosapi::NodeDetails>(
"/rosapi/node_details",
rosapi::NodeDetailsRequest { node: node.into() },
)
Expand All @@ -162,7 +162,7 @@ impl RosApi for ClientHandle {
&self,
service: impl Into<String> + Send,
) -> RosLibRustResult<rosapi::ServiceNodeResponse> {
self.call_service(
self.call_service::<rosapi::ServiceNode>(
"/rosapi/service_node",
rosapi::ServiceNodeRequest {
service: service.into(),
Expand All @@ -178,7 +178,7 @@ impl RosApi for ClientHandle {
param_name: impl Into<String> + Send,
param_value: impl Into<String> + Send,
) -> RosLibRustResult<rosapi::SetParamResponse> {
self.call_service(
self.call_service::<rosapi::SetParam>(
"/rosapi/set_param",
rosapi::SetParamRequest {
name: param_name.into(),
Expand All @@ -194,7 +194,7 @@ impl RosApi for ClientHandle {
&self,
param_name: impl Into<String> + Send,
) -> RosLibRustResult<rosapi::GetParamResponse> {
self.call_service(
self.call_service::<rosapi::GetParam>(
"/rosapi/get_param",
rosapi::GetParamRequest {
name: param_name.into(),
Expand All @@ -206,16 +206,19 @@ impl RosApi for ClientHandle {

/// Gets the list of currently known parameters.
async fn get_param_names(&self) -> RosLibRustResult<rosapi::GetParamNamesResponse> {
self.call_service("/rosapi/get_param_names", rosapi::GetParamNamesRequest {})
.await
self.call_service::<rosapi::GetParamNames>(
"/rosapi/get_param_names",
rosapi::GetParamNamesRequest {},
)
.await
}

/// Checks whether the given parameter is defined.
async fn has_param(
&self,
param: impl Into<String> + Send,
) -> RosLibRustResult<rosapi::HasParamResponse> {
self.call_service(
self.call_service::<rosapi::HasParam>(
"/rosapi/has_param",
rosapi::HasParamRequest { name: param.into() },
)
Expand All @@ -227,7 +230,7 @@ impl RosApi for ClientHandle {
&self,
name: impl Into<String> + Send,
) -> RosLibRustResult<rosapi::DeleteParamResponse> {
self.call_service(
self.call_service::<rosapi::DeleteParam>(
"/rosapi/delete_param",
rosapi::DeleteParamRequest { name: name.into() },
)
Expand All @@ -239,7 +242,7 @@ impl RosApi for ClientHandle {
&self,
message_name: impl Into<String> + Send,
) -> RosLibRustResult<rosapi::MessageDetailsResponse> {
self.call_service(
self.call_service::<rosapi::MessageDetails>(
"/rosapi/message_details",
rosapi::MessageDetailsRequest {
r#type: message_name.into(),
Expand All @@ -253,7 +256,7 @@ impl RosApi for ClientHandle {
&self,
topic: impl Into<String> + Send,
) -> RosLibRustResult<rosapi::PublishersResponse> {
self.call_service(
self.call_service::<rosapi::Publishers>(
"/rosapi/publishers",
rosapi::PublishersRequest {
topic: topic.into(),
Expand All @@ -267,7 +270,7 @@ impl RosApi for ClientHandle {
&self,
service: impl Into<String> + Send,
) -> RosLibRustResult<rosapi::ServiceHostResponse> {
self.call_service(
self.call_service::<rosapi::ServiceHost>(
"/rosapi/service_host",
rosapi::ServiceHostRequest {
service: service.into(),
Expand All @@ -281,7 +284,7 @@ impl RosApi for ClientHandle {
&self,
service_type: impl Into<String> + Send,
) -> RosLibRustResult<rosapi::ServiceProvidersResponse> {
self.call_service(
self.call_service::<rosapi::ServiceProviders>(
"/rosapi/service_providers",
rosapi::ServiceProvidersRequest {
service: service_type.into(),
Expand All @@ -295,7 +298,7 @@ impl RosApi for ClientHandle {
&self,
service_type: impl Into<String> + Send,
) -> RosLibRustResult<rosapi::ServiceRequestDetailsResponse> {
self.call_service(
self.call_service::<rosapi::ServiceRequestDetails>(
"/rosapi/service_request_details",
rosapi::ServiceRequestDetailsRequest {
r#type: service_type.into(),
Expand All @@ -309,7 +312,7 @@ impl RosApi for ClientHandle {
&self,
service_type: impl Into<String> + Send,
) -> RosLibRustResult<rosapi::ServiceRequestDetailsResponse> {
self.call_service(
self.call_service::<rosapi::ServiceRequestDetails>(
"/rosapi/service_response_details",
rosapi::ServiceRequestDetailsRequest {
r#type: service_type.into(),
Expand All @@ -323,7 +326,7 @@ impl RosApi for ClientHandle {
&self,
service_name: impl Into<String> + Send,
) -> RosLibRustResult<rosapi::ServiceTypeResponse> {
self.call_service(
self.call_service::<rosapi::ServiceType>(
"/rosapi/service_type",
rosapi::ServiceTypeRequest {
service: service_name.into(),
Expand All @@ -334,7 +337,7 @@ impl RosApi for ClientHandle {

/// Get the list of services active on the system
async fn get_services(&self) -> RosLibRustResult<rosapi::ServicesResponse> {
self.call_service("/rosapi/services", rosapi::ServicesRequest {})
self.call_service::<rosapi::Services>("/rosapi/services", rosapi::ServicesRequest {})
.await
}

Expand Down
Loading

0 comments on commit 46f1b67

Please sign in to comment.