arci_ros/ros_control/
ros_control_client.rs
1use std::{
2 sync::{Arc, LazyLock, Mutex},
3 time::Duration,
4};
5
6use arci::{
7 CompleteCondition, JointTrajectoryClient, SetCompleteCondition, TotalJointDiffCondition,
8 TrajectoryPoint, WaitFuture,
9};
10use msg::trajectory_msgs::JointTrajectory;
11
12use crate::{
13 create_joint_trajectory_message_for_send_joint_positions,
14 create_joint_trajectory_message_for_send_joint_trajectory,
15 extract_current_joint_positions_from_state, msg, JointStateProvider,
16 JointStateProviderFromJointTrajectoryControllerState, LazyJointStateProvider,
17 SubscriberHandler,
18};
19
20#[derive(Clone)]
21pub struct RosControlClient(Arc<RosControlClientInner>);
22
23struct RosControlClientInner {
24 joint_names: Vec<String>,
25 send_partial_joints_goal: bool,
26 joint_state_provider: Arc<LazyJointStateProvider>,
27 complete_condition: Mutex<Arc<dyn CompleteCondition>>,
28 trajectory_publisher: rosrust::Publisher<JointTrajectory>,
29}
30
31impl RosControlClient {
32 pub fn new_with_joint_state_provider(
33 joint_names: Vec<String>,
34 controller_name: &str,
35 send_partial_joints_goal: bool,
36 joint_state_provider: Arc<LazyJointStateProvider>,
37 ) -> Self {
38 let (state_joint_names, _) = joint_state_provider.get_joint_state().unwrap();
39 for joint_name in &joint_names {
40 if !state_joint_names.iter().any(|name| **name == *joint_name) {
41 panic!(
42 "Invalid configuration : Joint ({joint_name}) is not found in state ({state_joint_names:?})",
43 );
44 }
45 }
46
47 let trajectory_publisher =
48 rosrust::publish(&format!("{controller_name}/command"), 1).unwrap();
49
50 let rate = rosrust::rate(10.0);
51 while rosrust::is_ok() && trajectory_publisher.subscriber_count() == 0 {
52 rosrust::ros_info!("waiting trajectory subscriber");
53 rate.sleep();
54 }
55
56 Self(Arc::new(RosControlClientInner {
57 joint_names,
58 trajectory_publisher,
59 send_partial_joints_goal,
60 joint_state_provider,
61 complete_condition: Mutex::new(Arc::new(TotalJointDiffCondition::default())),
62 }))
63 }
64
65 pub fn new(
66 joint_names: Vec<String>,
67 controller_name: &str,
68 send_partial_joints_goal: bool,
69 ) -> Self {
70 let joint_state_topic_name = Self::state_topic_name(controller_name);
71 Self::new_with_state_topic_name(
72 joint_names,
73 controller_name,
74 &joint_state_topic_name,
75 send_partial_joints_goal,
76 )
77 }
78
79 pub(crate) fn state_topic_name(controller_name: &str) -> String {
80 format!("{controller_name}/state")
81 }
82
83 pub(crate) fn create_joint_state_provider(
84 joint_state_topic_name: impl Into<String>,
85 ) -> Arc<LazyJointStateProvider> {
86 let joint_state_topic_name = joint_state_topic_name.into();
87 Arc::new(LazyLock::new(Box::new(move || {
88 Box::new(JointStateProviderFromJointTrajectoryControllerState::new(
89 SubscriberHandler::new(&joint_state_topic_name, 1),
90 ))
91 })))
92 }
93
94 pub fn new_with_state_topic_name(
95 joint_names: Vec<String>,
96 controller_name: &str,
97 joint_state_topic_name: &str,
98 send_partial_joints_goal: bool,
99 ) -> Self {
100 let joint_state_provider = Self::create_joint_state_provider(joint_state_topic_name);
101 Self::new_with_joint_state_provider(
102 joint_names,
103 controller_name,
104 send_partial_joints_goal,
105 joint_state_provider,
106 )
107 }
108}
109
110impl JointStateProvider for RosControlClient {
111 fn get_joint_state(&self) -> Result<(Vec<String>, Vec<f64>), arci::Error> {
112 self.0.joint_state_provider.get_joint_state()
113 }
114}
115
116impl JointTrajectoryClient for RosControlClient {
117 fn joint_names(&self) -> Vec<String> {
118 self.0.joint_names.clone()
119 }
120
121 fn current_joint_positions(&self) -> Result<Vec<f64>, arci::Error> {
122 extract_current_joint_positions_from_state(self, self)
123 }
124
125 fn send_joint_positions(
126 &self,
127 positions: Vec<f64>,
128 duration: Duration,
129 ) -> Result<WaitFuture, arci::Error> {
130 let traj = create_joint_trajectory_message_for_send_joint_positions(
131 self,
132 self,
133 &positions,
134 duration,
135 self.0.send_partial_joints_goal,
136 )?;
137 self.0.trajectory_publisher.send(traj).unwrap();
138 let this = self.clone();
139 Ok(WaitFuture::new(async move {
140 let complete_condition = this.0.complete_condition.lock().unwrap().clone();
142 complete_condition
143 .wait(&this, &positions, duration.as_secs_f64())
144 .await
145 }))
146 }
147
148 fn send_joint_trajectory(
149 &self,
150 trajectory: Vec<TrajectoryPoint>,
151 ) -> Result<WaitFuture, arci::Error> {
152 let traj = create_joint_trajectory_message_for_send_joint_trajectory(
153 self,
154 self,
155 &trajectory,
156 self.0.send_partial_joints_goal,
157 )?;
158 self.0.trajectory_publisher.send(traj).unwrap();
159 let this = self.clone();
160 Ok(WaitFuture::new(async move {
161 let complete_condition = this.0.complete_condition.lock().unwrap().clone();
163 complete_condition
164 .wait(
165 &this,
166 &trajectory.last().unwrap().positions,
167 trajectory.last().unwrap().time_from_start.as_secs_f64(),
168 )
169 .await
170 }))
171 }
172}
173
174impl SetCompleteCondition for RosControlClient {
175 fn set_complete_condition(&mut self, condition: Box<dyn CompleteCondition>) {
176 *self.0.complete_condition.lock().unwrap() = condition.into();
177 }
178}