{"id":13632509,"url":"https://github.com/adnanademovic/rosrust","last_synced_at":"2025-05-14T01:09:28.659Z","repository":{"id":9733849,"uuid":"63151214","full_name":"adnanademovic/rosrust","owner":"adnanademovic","description":"Pure Rust implementation of a ROS client library","archived":false,"fork":false,"pushed_at":"2023-08-07T15:09:20.000Z","size":1147,"stargazers_count":700,"open_issues_count":43,"forks_count":73,"subscribers_count":22,"default_branch":"master","last_synced_at":"2024-04-25T22:00:27.057Z","etag":null,"topics":["client-library","ros","rust"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/adnanademovic.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2016-07-12T11:05:32.000Z","updated_at":"2024-04-15T02:31:05.000Z","dependencies_parsed_at":"2023-10-20T16:21:25.559Z","dependency_job_id":null,"html_url":"https://github.com/adnanademovic/rosrust","commit_stats":{"total_commits":609,"total_committers":19,"mean_commits":32.05263157894737,"dds":"0.10016420361247946","last_synced_commit":"00fe62491ea76ae6908bac7b79eb1bf25fc6f64e"},"previous_names":[],"tags_count":19,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adnanademovic%2Frosrust","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adnanademovic%2Frosrust/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adnanademovic%2Frosrust/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adnanademovic%2Frosrust/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/adnanademovic","download_url":"https://codeload.github.com/adnanademovic/rosrust/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248388354,"owners_count":21095374,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["client-library","ros","rust"],"created_at":"2024-08-01T22:03:05.218Z","updated_at":"2025-04-11T11:47:28.504Z","avatar_url":"https://github.com/adnanademovic.png","language":"Rust","funding_links":[],"categories":["Rust","Robot Operating System"],"sub_categories":[],"readme":"# rosrust\n\n[![MIT Licensed](https://img.shields.io/crates/l/rosrust.svg?maxAge=3600)](./LICENSE)\n[![Crates.io](https://img.shields.io/crates/v/rosrust.svg?maxAge=3600)](https://crates.io/crates/rosrust)\n[![Build Status](https://travis-ci.org/adnanademovic/rosrust.svg?branch=master)](https://travis-ci.org/adnanademovic/rosrust)\n\n**rosrust** is a pure Rust implementation of a [ROS](http://www.ros.org/) client library.\n\n## Usage\n\nFor all the key features, it is enough to depend on the crate itself. It's highly recommended to depend on `rosrust_msg` as well, as it provides bindings for message generation.\n\nThe following dependencies are recommended to use the crate:\n\n```toml\n[dependencies]\nrosrust = \"0.9\"\nrosrust_msg = \"0.1\"\n```\n\nIf using Rust 2015 edition, just depend on the library with macro usage, using:\n\n```rust\n#[macro_use]\nextern crate rosrust;\n```\n\nExamples are written using Rust 2018, as it's the expected edition to use now.\n\n## Implementation\n\n**rosrust** is almost there with implementing all features of a ROS Client Library by fulfilling [ROS requirements for implementing client libraries](http://wiki.ros.org/Implementing%20Client%20Libraries) which are given in a more detailed form in the [technical overview](http://wiki.ros.org/ROS/Technical%20Overview).\n\nMostly the missing features are related to extra tooling, like `sensor_msgs/PointCloud2` and `sensor_msgs/Image` encoding/decoding, TF tree handling, and other things that are external libraries in `roscpp` and `rospy` as well.\n\nThe API is very close to the desired final look.\n\nIntegration with [catkin](http://www.ros.org/wiki/catkin) will be handled once a satisfying set of features has been implemented.\n\n## Examples\n\nThe API is close to reaching its final form.\n\nThere are multiple examples in the [examples folder](https://github.com/adnanademovic/rosrust/tree/master/examples/examples). The publisher/subscriber and service/client examples are designed to closely imitate the `roscpp` tutorial.\n\n## Features\n\n### Message Generation\n\nMessage generation can be done automatically by depending on `rosrust_msg`, or manually using `rosrust::rosmsg_include`.\n\nThe preferred way is automatic, as it allows interop between dependencies that use messages and your crate.\n\nIf you do not have ROS installed, then the message generation utilizes the `ROSRUST_MSG_PATH` environment variable, which is a colon separated list of directories to search.\nThese directories should have the structure `\u003cROSRUST_MSG_PATH\u003e/\u003canything\u003e/\u003cpackage\u003e/msg/\u003cmessage\u003e` or `\u003cROSRUST_MSG_PATH\u003e/\u003canything\u003e/\u003cpackage\u003e/srv/\u003cservice\u003e`. \n\n#### Automatic\n\nFor automatic message generation just depend on `rosrust_msg`, with the version specified at the top of this document.\n\nAfter that you'll be able to generate a `sensor_msgs/Imu` message object by using `rosrust_msg::sensor_msgs::Imu::default()`. All fields are always public, so you can initialize structures as literals.\n\n#### Manual\n\nMessage generation is done at build time. If you have ROS installed and sourced in your shell session, you will not need to do any extra setup for this to work.\n\nTo generate messages, create a module for messages. Using something like a `msg.rs` file in your project root results in importing similar to `roscpp` and `rospy`. The file only needs one line:\n\n```rust\n// If you wanted\n// * messages: std_msgs/String, sensor_msgs/Imu\n// * services: roscpp_tutorials/TwoInts\n// * and all the message types used by them, like geometry_msgs/Vector3\nrosrust::rosmsg_include!(std_msgs/String,sensor_msgs/Imu,roscpp_tutorials/TwoInts);\n```\n\nJust add this file to your project and you're done.\n\nIf you have put this in a `src/msg.rs` file, this will include all the generated structures, and add them to the `msg` namespace. Thus, to create a new `sensor_msgs/Imu`, you call `msg::sensor_msgs::Imu::default()`. All fields are always public, so you can initialize structures as literals.\n\n### Publishing to Topic\n\nIf we wanted to publish a defined message (let's use `std_msgs/String`) to topic `chatter` ten times a second, we can do it in the following way.\n\n```rust\nfn main() {\n    // Initialize node\n    rosrust::init(\"talker\");\n\n    // Create publisher\n    let chatter_pub = rosrust::publish(\"chatter\", 100).unwrap();\n\n    let mut count = 0;\n\n    // Create object that maintains 10Hz between sleep requests\n    let rate = rosrust::rate(10.0);\n\n    // Breaks when a shutdown signal is sent\n    while rosrust::is_ok() {\n        // Create string message\n        let mut msg = rosrust_msg::std_msgs::String::default();\n        msg.data = format!(\"hello world {}\", count);\n\n        // Send string message to topic via publisher\n        chatter_pub.send(msg).unwrap();\n\n        // Sleep to maintain 10Hz rate\n        rate.sleep();\n\n        count += 1;\n    }\n}\n```\n\n### Subscribing to Topic\n\nIf we wanted to subscribe to an `std_msgs/UInt64` topic `some_topic`, we just declare a callback. An alternative extra interface with iterators is being considered, but for now this is the only option.\n\nThe constructor creates an object, which represents the subscriber lifetime.\nUpon the destruction of this object, the topic is unsubscribed as well.\n\n```rust\nfn main() {\n    // Initialize node\n    rosrust::init(\"listener\");\n\n    // Create subscriber\n    // The subscriber is stopped when the returned object is destroyed\n    let _subscriber_raii = rosrust::subscribe(\"chatter\", 100, |v: rosrust_msg::std_msgs::UInt64| {\n        // Callback for handling received messages\n        rosrust::ros_info!(\"Received: {}\", v.data);\n    }).unwrap();\n\n    // Block the thread until a shutdown signal is received\n    rosrust::spin();\n}\n```\n\n### Creating a Service\n\nCreating a service is the easiest out of all the options. Just define a callback for each request. Let's use the `roscpp_tutorials/AddTwoInts` service on the topic `/add_two_ints`.\n\n```rust\nfn main() {\n    // Initialize node\n    rosrust::init(\"add_two_ints_server\");\n\n    // Create service\n    // The service is stopped when the returned object is destroyed\n    let _service_raii =\n        rosrust::service::\u003crosrust_msg::roscpp_tutorials::TwoInts, _\u003e(\"add_two_ints\", move |req| {\n            // Callback for handling requests\n            let sum = req.a + req.b;\n\n            // Log each request\n            rosrust::ros_info!(\"{} + {} = {}\", req.a, req.b, sum);\n\n            Ok(rosrust_msg::roscpp_tutorials::TwoIntsRes { sum })\n        }).unwrap();\n\n    // Block the thread until a shutdown signal is received\n    rosrust::spin();\n}\n\n```\n\n### Creating a Client\n\nClients can handle requests synchronously and asynchronously. The sync method behaves like a function, while the async approach is via reading data afterwards. The async consumes the passed parameter, since we're passing the parameter between threads. It's more common for users to pass and drop a parameter, so this being the default prevents needless cloning.\n\nLet's call requests from the `AddTwoInts` service on the topic `/add_two_ints`.\nThe numbers shall be provided as command line arguments.\n\nWe're also depending on `env_logger` here to log `ros_info` messages to the standard output.\n\n```rust\nuse std::{env, time};\n\nfn main() {\n    env_logger::init();\n\n    // Fetch args that are not meant for rosrust\n    let args: Vec\u003c_\u003e = rosrust::args();\n\n    if args.len() != 3 {\n        eprintln!(\"usage: client X Y\");\n        return;\n    }\n\n    let a = args[1].parse::\u003ci64\u003e().unwrap();\n    let b = args[2].parse::\u003ci64\u003e().unwrap();\n\n    // Initialize node\n    rosrust::init(\"add_two_ints_client\");\n\n    // Wait ten seconds for the service to appear\n    rosrust::wait_for_service(\"add_two_ints\", Some(time::Duration::from_secs(10))).unwrap();\n\n    // Create client for the service\n    let client = rosrust::client::\u003crosrust_msg::roscpp_tutorials::TwoInts\u003e(\"add_two_ints\").unwrap();\n\n    // Synchronous call that blocks the thread until a response is received\n    ros_info!(\n        \"{} + {} = {}\",\n        a,\n        b,\n        client\n            .req(\u0026rosrust_msg::roscpp_tutorials::TwoIntsReq { a, b })\n            .unwrap()\n            .unwrap()\n            .sum\n    );\n\n    // Asynchronous call that can be resolved later on\n    let retval = client.req_async(rosrust_msg::roscpp_tutorials::TwoIntsReq { a, b });\n    rosrust::ros_info!(\"{} + {} = {}\", a, b, retval.read().unwrap().unwrap().sum);\n}\n\n```\n\n### Parameters\n\nThere are a lot of methods provided, so we'll just give a taste of all of them here. Get requests return results, so you can use `unwrap_or` to handle defaults.\n\nWe're also depending on `env_logger` here to log `ros_info` messages to the standard output.\n\n```rust\nfn main() {\n    env_logger::init();\n\n    // Initialize node\n    rosrust::init(\"param_test\");\n\n    // Create parameter, go through all methods, and delete it\n    let param = rosrust::param(\"~foo\").unwrap();\n    rosrust::ros_info!(\"Handling ~foo:\");\n    rosrust::ros_info!(\"Exists? {:?}\", param.exists()); // false\n    param.set(\u002642u64).unwrap();\n    rosrust::ros_info!(\"Get: {:?}\", param.get::\u003cu64\u003e().unwrap());\n    rosrust::ros_info!(\"Get raw: {:?}\", param.get_raw().unwrap());\n    rosrust::ros_info!(\"Search: {:?}\", param.search().unwrap());\n    rosrust::ros_info!(\"Exists? {}\", param.exists().unwrap());\n    param.delete().unwrap();\n    rosrust::ros_info!(\"Get {:?}\", param.get::\u003cu64\u003e().unwrap_err());\n    rosrust::ros_info!(\"Get with default: {:?}\", param.get::\u003cu64\u003e().unwrap_or(44u64));\n    rosrust::ros_info!(\"Exists? {}\", param.exists().unwrap());\n}\n```\n\n### Logging\n\nLogging is provided through macros `ros_debug!()`, `ros_info!()`, `ros_warn!()`, `ros_error!()`, `ros_fatal!()`.\n\nThrottled logging options ara available too.\n\n### Command Line Remaps\n\nSimilar to `rospy` and `roscpp`, you can use the command line to remap topics and private parameters. Private parameters should be provided in a YAML format.\n\nFor more information, look at the [official wiki](http://wiki.ros.org/Remapping%20Arguments), since the attempt was to 100% immitate this interface.\n\nYou can get a vector of the leftover command line argument strings with `rosrust::args()`, allowing easy argument parsing. This includes the first argument, the application name.\n\n## License\n\n**rosrust** is distributed under the MIT license.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fadnanademovic%2Frosrust","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fadnanademovic%2Frosrust","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fadnanademovic%2Frosrust/lists"}