@@ -4,6 +4,7 @@ use std::env;
44use std:: sync:: { Arc , Mutex } ;
55use std:: time:: Duration ;
66use tokio:: time:: interval;
7+ use tokio_stream:: StreamExt ;
78
89pub mod droidgrpc {
910 tonic:: include_proto!( "droidgrpc" ) ;
@@ -20,6 +21,11 @@ struct RobotState {
2021 // Key: ROS joint name, Value: position
2122 joint_data : HashMap < String , f64 > ,
2223}
24+ #[ derive( Default ) ]
25+ struct GoalState {
26+ // Key: ROS joint name, Value: position target
27+ joint_targets : HashMap < String , f32 > ,
28+ }
2329
2430#[ tokio:: main]
2531async fn main ( ) -> Result < ( ) , Box < dyn std:: error:: Error > > {
@@ -32,9 +38,12 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
3238 "/joint_states" ,
3339 r2r:: QosProfile :: default ( ) ,
3440 ) ?;
41+ let mut cmd_sub = node. subscribe :: < r2r:: bitbots_msgs:: msg:: JointCommand > (
42+ "/x02_joint_commands" ,
43+ r2r:: QosProfile :: default ( )
44+ ) ?;
3545 let state_pub = Arc :: new ( Mutex :: new ( state_pub) ) ;
36- let node = Arc :: new ( Mutex :: new ( node) ) ;
37- let spin_node = node. clone ( ) ;
46+ let spin_node = Arc :: new ( Mutex :: new ( node) ) ;
3847
3948 // --- 1. Mapping & Virtual Joints ---
4049 let mut name_map = HashMap :: new ( ) ;
@@ -90,13 +99,38 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
9099 . into_inner ( )
91100 . joint_name ;
92101
93- // --- 4. Writer Tasks: Update shared state when data arrives ---
102+ let mut initial_goals = GoalState :: default ( ) ;
103+
104+ // Seed Leg goals
105+ if let Ok ( resp) = leg_client. get_leg_state ( Empty { } ) . await {
106+ let current_pos = resp. into_inner ( ) . position ;
107+ for ( i, hw_id) in leg_joint_names. iter ( ) . enumerate ( ) {
108+ if let Some ( ros_name) = name_map. get ( hw_id) {
109+ initial_goals. joint_targets . insert ( ros_name. clone ( ) , current_pos. get ( i) . cloned ( ) . unwrap_or ( 0.0 ) ) ;
110+ }
111+ }
112+ }
113+
114+ // Seed Arm goals
115+ if let Ok ( resp) = arm_client. get_arm_state ( Empty { } ) . await {
116+ let current_pos = resp. into_inner ( ) . position ;
117+ for ( i, hw_id) in arm_joint_names. iter ( ) . enumerate ( ) {
118+ if let Some ( ros_name) = name_map. get ( hw_id) {
119+ initial_goals. joint_targets . insert ( ros_name. clone ( ) , current_pos. get ( i) . cloned ( ) . unwrap_or ( 0.0 ) ) ;
120+ }
121+ }
122+ }
123+
124+ let shared_goals = Arc :: new ( Mutex :: new ( initial_goals) ) ;
125+
126+ // --- GPRC Tasks: Update shared state when data arrives, send out commands ---
94127
95128 // Leg Poller
96129 let mut l_client = leg_client. clone ( ) ;
97130 let l_state = shared_state. clone ( ) ;
98131 let l_names = leg_joint_names. clone ( ) ;
99132 let l_map = name_map. clone ( ) ;
133+ let l_goals = shared_goals. clone ( ) ;
100134 tokio:: spawn ( async move {
101135 let mut ticker = interval ( Duration :: from_millis ( 20 ) ) ; // Poll at 50Hz
102136 loop {
@@ -113,6 +147,23 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
113147 }
114148 }
115149 }
150+ let cmd_request = {
151+ let goals = l_goals. lock ( ) . unwrap ( ) ;
152+ let positions: Vec < f32 > = l_names. iter ( )
153+ . map ( |hw_id| {
154+ let ros_name = l_map. get ( hw_id) . expect ( "Map error" ) ;
155+ * goals. joint_targets . get ( ros_name) . expect ( "Leg Joint has no value assigned" )
156+ } )
157+ . collect ( ) ;
158+
159+ droidgrpc:: DroidCommandRequest {
160+ position : positions,
161+ ..Default :: default ( )
162+ }
163+ } ;
164+ if let Err ( e) = l_client. set_leg_command ( cmd_request) . await {
165+ eprintln ! ( "gRPC Error: Failed to set Arm command: {}" , e) ;
166+ }
116167 }
117168 } ) ;
118169
@@ -121,9 +172,28 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
121172 let a_state = shared_state. clone ( ) ;
122173 let a_names = arm_joint_names. clone ( ) ;
123174 let a_map = name_map. clone ( ) ;
175+ let a_goals = shared_goals. clone ( ) ;
124176 tokio:: spawn ( async move {
125177 let mut ticker = interval ( Duration :: from_millis ( 20 ) ) ;
126178 loop {
179+ let cmd_request = {
180+ let goals = a_goals. lock ( ) . unwrap ( ) ;
181+ let positions: Vec < f32 > = a_names. iter ( )
182+ . map ( |hw_id| {
183+ let ros_name = a_map. get ( hw_id) . expect ( "Arm mapping error" ) ;
184+ * goals. joint_targets . get ( ros_name) . expect ( "Arm Joint has no value assigned" )
185+ } )
186+ . collect ( ) ;
187+
188+ droidgrpc:: DroidCommandRequest {
189+ position : positions,
190+ ..Default :: default ( )
191+ }
192+ } ;
193+
194+ if let Err ( e) = a_client. set_arm_command ( cmd_request) . await {
195+ eprintln ! ( "gRPC Error: Failed to set Arm command: {}" , e) ;
196+ }
127197 ticker. tick ( ) . await ;
128198 if let Ok ( resp) = a_client. get_arm_state ( Empty { } ) . await {
129199 let positions = resp. into_inner ( ) . position ;
@@ -140,7 +210,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
140210 }
141211 } ) ;
142212
143- // --- 5. Reader Task: Publish at Fixed ROS Rate ---
213+ // --- Reader Task: Publish at Fixed ROS Rate ---
214+ let read_node = spin_node. clone ( ) ;
144215 let pub_state = shared_state. clone ( ) ;
145216 tokio:: spawn ( async move {
146217 let mut ticker = interval ( Duration :: from_millis ( 10 ) ) ; // Publish at 100Hz
@@ -150,7 +221,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
150221 let mut ros_msg = r2r:: sensor_msgs:: msg:: JointState :: default ( ) ;
151222 // Get the duration from the clock
152223 let now_duration = {
153- let n_lock = node . lock ( ) . expect ( "node lock poisoned" ) ;
224+ let n_lock = read_node . lock ( ) . expect ( "node lock poisoned" ) ;
154225 let clock_res = n_lock. get_ros_clock ( ) ;
155226 let mut c_lock = clock_res. lock ( ) . expect ( "clock lock poisoned" ) ;
156227 c_lock. get_now ( ) . expect ( "Clock failed" )
@@ -194,8 +265,24 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
194265 }
195266 }
196267 } ) ;
268+ // ---ROS receive goals---
269+ let sub_goals = shared_goals. clone ( ) ;
270+
271+ tokio:: spawn ( async move {
272+ while let Some ( msg) = cmd_sub. next ( ) . await {
273+ if msg. joint_names . len ( ) != msg. positions . len ( ) { continue ; }
274+
275+ let mut goals = sub_goals. lock ( ) . unwrap ( ) ;
276+ for ( i, ros_name) in msg. joint_names . iter ( ) . enumerate ( ) {
277+ // Only update if it's a joint we actually track
278+ if goals. joint_targets . contains_key ( ros_name) {
279+ goals. joint_targets . insert ( ros_name. clone ( ) , msg. positions [ i] as f32 ) ;
280+ }
281+ }
282+ }
283+ } ) ;
197284
198- // --- 6. ROS Spin ---
285+ // ---ROS Spin ---
199286 loop {
200287 spin_node
201288 . lock ( )
0 commit comments