openrr_client/clients/
collision_avoidance_client.rs
1use std::{path::Path, sync::Arc};
2
3use arci::{Error, JointTrajectoryClient, TrajectoryPoint, WaitFuture};
4use openrr_planner::{create_joint_path_planner, JointPathPlannerConfig};
5
6fn trajectory_from_positions(
8 positions: &[Vec<f64>],
9 total_duration: std::time::Duration,
10) -> Vec<TrajectoryPoint> {
11 let num_points = positions.len();
12 let mut traj = vec![];
13 for (i, pos) in positions.iter().enumerate() {
14 let time_rate: f64 = ((i + 1) as f64) / (num_points as f64);
15 traj.push(TrajectoryPoint::new(
16 pos.clone(),
17 total_duration.mul_f64(time_rate),
18 ));
19 }
20 traj
21}
22
23pub struct CollisionAvoidanceClient<T>
24where
25 T: JointTrajectoryClient,
26{
27 pub client: T,
28 pub planner: openrr_planner::JointPathPlanner<f64>,
29}
30
31impl<T> CollisionAvoidanceClient<T>
32where
33 T: JointTrajectoryClient,
34{
35 pub fn new(client: T, planner: openrr_planner::JointPathPlanner<f64>) -> Self {
36 Self { client, planner }
37 }
38}
39
40impl<T> JointTrajectoryClient for CollisionAvoidanceClient<T>
41where
42 T: JointTrajectoryClient,
43{
44 fn joint_names(&self) -> Vec<String> {
45 self.client.joint_names()
46 }
47
48 fn current_joint_positions(&self) -> Result<Vec<f64>, Error> {
49 self.client.current_joint_positions()
50 }
51
52 fn send_joint_positions(
53 &self,
54 positions: Vec<f64>,
55 duration: std::time::Duration,
56 ) -> Result<WaitFuture, Error> {
57 let traj = self
58 .planner
59 .plan_avoid_self_collision(
60 &self.joint_names(),
61 &self.current_joint_positions()?,
62 &positions,
63 )
64 .map_err(|e| Error::Other(e.into()))?;
65 self.client
66 .send_joint_trajectory(trajectory_from_positions(&traj, duration))
67 }
68
69 fn send_joint_trajectory(&self, trajectory: Vec<TrajectoryPoint>) -> Result<WaitFuture, Error> {
70 if trajectory.is_empty() {
71 return Ok(WaitFuture::ready());
72 }
73 let positions = self
74 .planner
75 .plan_avoid_self_collision(
76 &self.joint_names(),
77 &self.current_joint_positions()?,
78 &trajectory[0].positions,
79 )
80 .map_err(|e| Error::Other(e.into()))?;
81 let mut trajs = trajectory_from_positions(&positions, trajectory[0].time_from_start);
82
83 for i in 1..trajectory.len() {
84 let positions = self
85 .planner
86 .plan_avoid_self_collision(
87 &self.joint_names(),
88 &trajectory[i - 1].positions,
89 &trajectory[i].positions,
90 )
91 .map_err(|e| Error::Other(e.into()))?;
92 trajs.append(&mut trajectory_from_positions(
93 &positions,
94 trajectory[i].time_from_start,
95 ));
96 }
97 self.client.send_joint_trajectory(trajs)
98 }
99}
100
101pub fn create_collision_avoidance_client<P: AsRef<Path>>(
102 urdf_path: P,
103 self_collision_check_pairs: Vec<(String, String)>,
104 joint_path_planner_config: &JointPathPlannerConfig,
105 client: Arc<dyn JointTrajectoryClient>,
106 reference_robot: Arc<k::Chain<f64>>,
107) -> CollisionAvoidanceClient<Arc<dyn JointTrajectoryClient>> {
108 let planner = create_joint_path_planner(
109 urdf_path,
110 self_collision_check_pairs,
111 joint_path_planner_config,
112 reference_robot,
113 );
114
115 CollisionAvoidanceClient::new(client, planner)
116}
117
118#[cfg(test)]
119mod tests {
120 use super::*;
121
122 #[tokio::test]
123 async fn test_create_collision_avoidance_client() {
124 let urdf_path = Path::new("sample.urdf");
125 let urdf_robot = urdf_rs::read_file(urdf_path).unwrap();
126 let robot = Arc::new(k::Chain::<f64>::from(&urdf_robot));
127 let client = arci::DummyJointTrajectoryClient::new(
128 robot
129 .iter_joints()
130 .map(|joint| joint.name.clone())
131 .collect(),
132 );
133 client
134 .send_joint_positions(vec![0.0; 8], std::time::Duration::new(0, 0))
135 .unwrap()
136 .await
137 .unwrap();
138
139 let collision_avoidance_client = create_collision_avoidance_client(
140 urdf_path,
141 vec![("root".to_owned(), "l_shoulder_roll".to_owned())],
142 &JointPathPlannerConfig::default(),
143 Arc::new(client),
144 robot,
145 );
146
147 assert_eq!(
148 *collision_avoidance_client
149 .current_joint_positions()
150 .unwrap(),
151 vec![0.0; 8]
152 );
153
154 assert!(collision_avoidance_client
156 .send_joint_positions(vec![0.0; 8], std::time::Duration::new(1, 0),)
157 .is_ok());
158 assert!(collision_avoidance_client
160 .send_joint_positions(
161 vec![1.57, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
162 std::time::Duration::new(1, 0),
163 )
164 .is_err());
165 }
166}