Remove the need for msgs.txt

This commit is contained in:
Martin Dahl 2019-10-08 16:43:36 +02:00
parent 7a423a8504
commit 15c9bb3674
6 changed files with 94 additions and 42 deletions

View File

@ -5,23 +5,28 @@ Minimal bindings for ROS2 that does *not* require hooking in to the ROS2 build i
How to use
------------
You need to source your ROS2 installation before building/running. A couple of examples are included in examples/
1. Depend on this package: r2r = { git = "https://github.com/sequenceplanner/r2r" }.
2. You need to source your ROS2 installation before building/running.
3. The bindings will rebuild automatically if/when you source your workspaces.
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` before building. (Or just `ros2 msg list > msgs.txt` if you want everything).
What works?
--------
- Only tested with ROS2 Dashing
- Simple publish/subscribe, see examples.
- Up to date with ROS2 Dashing
- Building Rust types
- Publish/subscribe
TODO
------------
- The code generation is currently just a big hack. Needs cleanup and refactoring.
- Implement error handling. Now all methods just return Err(()).
- Expose more of the RCL.
- Expose more of the RCL.
- Services and action types are currently ignored.
- QoS settings etc.

View File

@ -6,8 +6,11 @@ use std::io::Write;
use std::path::PathBuf;
fn main() {
let msgs_str = read_file("./msgs.txt").expect("You need to create msgs.txt");
let msgs_list = parse_msgs(&msgs_str);
println!("cargo:rerun-if-env-changed=AMENT_PREFIX_PATH");
let msgs = get_all_ros_msgs();
let msgs_list = parse_msgs(&msgs);
let msgs = as_map(&msgs_list);
let mut codegen = String::new();

View File

@ -1,4 +1,8 @@
use std::collections::HashMap;
use std::env;
use std::fs::{self, File};
use std::io::{self, Read};
use std::path::PathBuf;
#[derive(Debug)]
pub struct RosMsg {
@ -7,8 +11,72 @@ pub struct RosMsg {
pub name: String, // e.g. "String"
}
pub fn parse_msgs(msgs: &str) -> Vec<RosMsg> {
let v: Vec<Vec<&str>> = msgs.lines().map(|l| l.split("/").into_iter().take(3).collect()).collect();
// TODO: actions and srv are similiar
pub fn get_all_ros_msgs() -> Vec<String> {
let resource_index_subfolder = "share/ament_index/resource_index";
let resource_type = "rosidl_interfaces";
let ament_prefix_var_name = "AMENT_PREFIX_PATH";
let ament_prefix_var = env::var(ament_prefix_var_name).expect("Source your ROS!");
let mut msgs: Vec<String> = Vec::new();
for ament_prefix_path in ament_prefix_var.split(":") {
// println!("prefix: {}", ament_prefix_path);
let path = PathBuf::from(ament_prefix_path);
let path = path.join(resource_index_subfolder);
let path = path.join(resource_type);
if let Ok(paths) = fs::read_dir(path) {
for path in paths {
// println!("PATH Name: {}", path.unwrap().path().display());
let path = path.unwrap().path();
let path2 = path.clone();
let file_name = path2.file_name().unwrap();
// println!("Messages for: {:?}", file_name);
if let Ok(mut file) = File::open(path) {
let mut s = String::new();
file.read_to_string(&mut s).unwrap();
let lines = s.lines();
lines.for_each(|l| {
if l.starts_with("msg/") && (l.ends_with(".idl") || l.ends_with(".msg")) {
if let Some(file_name_str) = file_name.to_str() {
let substr = &l[4..l.len()-4];
let msg_name = format!("{}/msg/{}", file_name_str, substr);
msgs.push(msg_name);
}
}
});
}
}
}
}
msgs.sort();
msgs.dedup();
return msgs;
}
#[test]
fn test_msg_list() {
let msgs = get_all_ros_msgs();
for m in &msgs {
println!("{}", m);
}
assert!(msgs.contains(&"std_msgs/msg/String".to_string()));
assert!(msgs.contains(&"builtin_interfaces/msg/Time".to_string()));
}
pub fn parse_msgs(msgs: &Vec<String>) -> Vec<RosMsg> {
let v: Vec<Vec<&str>> = msgs.iter().map(|l| l.split("/").into_iter().take(3).collect()).collect();
v.iter().filter(|v|v.len() == 3).
map(|v| RosMsg { module: v[0].into(), prefix: v[1].into(), name: v[2].into()}).collect()
@ -23,16 +91,6 @@ pub fn as_map(included_msgs: &[RosMsg]) -> HashMap<&str, HashMap<&str, Vec<&str>
msgs
}
use std::io::{self, Read};
use std::fs::File;
pub fn read_file(filename: &str) -> io::Result<String> {
let mut file = File::open(filename)?;
let mut s = String::new();
file.read_to_string(&mut s)?;
Ok(s)
}
#[cfg(test)]
mod tests {
use super::*;
@ -65,10 +123,9 @@ std_msgs/msg/String
assert_eq!(map.get("std_msgs").unwrap().get("msg").unwrap()[0], "Bool");
assert_eq!(map.get("std_msgs").unwrap().get("msg").unwrap()[1], "String");
}
}
}

View File

@ -8,9 +8,9 @@ use std::path::PathBuf;
use common::*;
fn main() {
println!("cargo:rerun-if-changed=../msgs.txt");
println!("cargo:rerun-if-env-changed=AMENT_PREFIX_PATH");
let msgs = read_file("../msgs.txt").expect("You need to create msgs.txt");
let msgs = get_all_ros_msgs();
let msg_list = parse_msgs(&msgs);
let msg_map = as_map(&msg_list);

View File

@ -1,15 +0,0 @@
builtin_interfaces/msg/Duration
builtin_interfaces/msg/Time
geometry_msgs/msg/Vector3
geometry_msgs/msg/AccelWithCovariance
geometry_msgs/msg/Accel
std_msgs/msg/String
std_msgs/msg/Bool
std_msgs/msg/Int32
std_msgs/msg/UInt32
std_msgs/msg/Header
trajectory_msgs/msg/JointTrajectory
trajectory_msgs/msg/JointTrajectoryPoint
shape_msgs/msg/SolidPrimitive

View File

@ -4,6 +4,8 @@ use std::env;
use std::path::PathBuf;
fn main() {
println!("cargo:rerun-if-env-changed=AMENT_PREFIX_PATH");
let mut builder = bindgen::Builder::default()
.header("src/rcl_wrapper.h")
.derive_copy(false)