1use std::{collections::HashMap, sync::Arc, time::Duration};
2
3use poulpe_ethercat_grpc::client;
4use pyo3::prelude::*;
5use pyo3::wrap_pyfunction;
6use tonic::transport::Uri;
7
8use poulpe_ethercat_grpc::client::{PoulpeIdClient, PoulpeRemoteClient};
9
10use poulpe_ethercat_controller::state_machine;
11
12#[pyclass]
13pub struct PyPoulpeRemoteClient {
14 client: PoulpeRemoteClient,
15}
16
17#[pymethods]
18impl PyPoulpeRemoteClient {
19 #[new]
20 pub fn new(addr: &str, ids: Vec<u16>, update_period: f32) -> Self {
21 let addr_uri = match addr.parse::<Uri>() {
22 Ok(uri) => uri,
23 Err(_) => panic!("Invalid URI format"),
24 };
25 let duration = Duration::from_secs_f32(update_period);
26
27 let client = match PoulpeRemoteClient::connect(addr_uri, ids, duration) {
28 Ok(client) => client,
29 Err(e) => panic!("Failed to connect to the server: {}", e),
30 };
31
32 PyPoulpeRemoteClient { client }
33 }
34
35 pub fn get_mode_of_operation(&mut self, slave_id: u16) -> u32 {
42 match self.client.get_mode_of_operation(slave_id) {
43 Ok(mode) => mode,
44 _ => panic!("Error in getting mode of operation"),
45 }
46 }
47
48 pub fn set_mode_of_operation(&mut self, slave_id: u16, mode: u32) {
54 self.client.set_mode_of_operation(slave_id, mode);
55 }
56
57 pub fn print_mode_of_operation(&mut self, slave_id: u16) {
64 let mode = match self.client.get_mode_of_operation(slave_id) {
65 Ok(mode) => mode,
66 _ => panic!("Error in getting mode of operation"),
67 };
68 let mop = state_machine::CiA402ModeOfOperation::from_u8(mode as u8).unwrap();
69 println!("Mode of operation: {:?}", mop);
70 }
71
72 pub fn turn_on(&mut self, slave_id: u16) {
77 self.client.turn_on(slave_id);
78 }
79
80 pub fn turn_off(&mut self, slave_id: u16) {
85 self.client.turn_off(slave_id);
86 }
87
88 pub fn set_target_position(&mut self, slave_id: u16, position: Vec<f32>) {
94 self.client.set_target_position(slave_id, position);
95 }
96
97 pub fn set_velocity_limit(&mut self, slave_id: u16, velocity: Vec<f32>) {
103 self.client.set_velocity_limit(slave_id, velocity);
104 }
105
106 pub fn set_torque_limit(&mut self, slave_id: u16, torque: Vec<f32>) {
112 self.client.set_torque_limit(slave_id, torque);
113 }
114
115 pub fn get_position_actual_value(&mut self, slave_id: u16) -> Vec<f32> {
122 match self.client.get_position_actual_value(slave_id) {
123 Ok(position) => position,
124 _ => panic!("Error in getting position actual value"),
125 }
126 }
127
128 pub fn get_target_position(&mut self, slave_id: u16) -> Vec<f32> {
135 match self.client.get_target_position(slave_id) {
136 Ok(position) => position,
137 _ => panic!("Error in getting target position"),
138 }
139 }
140
141 pub fn set_target_velocity(&mut self, slave_id: u16, velocity: Vec<f32>) {
148 self.client.set_target_velocity(slave_id, velocity);
149 }
150
151 pub fn set_target_torque(&mut self, slave_id: u16, torque: Vec<f32>) {
157 self.client.set_target_torque(slave_id, torque);
158 }
159
160 pub fn get_velocity_actual_value(&mut self, slave_id: u16) -> Vec<f32> {
167 match self.client.get_velocity_actual_value(slave_id) {
168 Ok(velocity) => velocity,
169 _ => panic!("Error in getting velocity actual value"),
170 }
171 }
172
173 pub fn get_torque_actual_value(&mut self, slave_id: u16) -> Vec<f32> {
180 match self.client.get_torque_actual_value(slave_id) {
181 Ok(torque) => torque,
182 _ => panic!("Error in getting torque actual value"),
183 }
184 }
185
186 pub fn get_axis_sensors(&mut self, slave_id: u16) -> Vec<f32> {
193 match self.client.get_axis_sensors(slave_id) {
194 Ok(sensors) => sensors,
195 _ => panic!("Error in getting axis sensors"),
196 }
197 }
198
199 pub fn get_axis_sensor_zeros(&mut self, slave_id: u16) -> Vec<f32> {
206 match self.client.get_axis_sensor_zeros(slave_id) {
207 Ok(zeros) => zeros,
208 _ => panic!("Error in getting axis sensor zeros"),
209 }
210 }
211
212 pub fn get_torque_state(&mut self, slave_id: u16) -> bool {
219 match self.client.get_torque_state(slave_id) {
220 Ok(state) => state,
221 _ => panic!("Error in getting torque state"),
222 }
223 }
224
225 pub fn get_state(&mut self, slave_id: u16) -> u32 {
232 match self.client.get_state(slave_id) {
233 Ok(state) => state,
234 _ => panic!("Error in getting state"),
235 }
236 }
237
238 pub fn print_state(&mut self, slave_id: u16) {
244 let state = match self.client.get_cia402_state(slave_id) {
245 Ok(state) => state,
246 _ => panic!("Error in getting state"),
247 };
248
249 let cia_state = state_machine::parse_state_from_status_word(state as u16);
250 println!("State: {:?}", cia_state);
251 }
252
253 pub fn get_error_codes(&mut self, slave_id: u16) -> Vec<i32> {
260 match self.client.get_error_codes(slave_id) {
261 Ok(codes) => codes,
262 _ => panic!("Error in getting error codes"),
263 }
264 }
265
266 pub fn print_error_codes(&mut self, slave_id: u16) {
271 let error_codes = match self.client.get_error_codes(slave_id) {
272 Ok(codes) => codes,
273 _ => panic!("Error in getting error codes"),
274 };
275
276 let homing_error =
278 state_machine::parse_homing_error_flags((error_codes[0] as u16).to_le_bytes());
279 if homing_error.len() > 0 {
280 println!("Homing | error flags: {:?}", homing_error);
281 } else {
282 println!("Homing | OK!");
283 }
284 for (i, code) in error_codes[1..].iter().enumerate() {
286 let m_code = state_machine::parse_motor_error_flags((*code as u16).to_le_bytes());
287 if m_code.len() > 0 {
288 println!("Motor {} | Error flags: {:?}", i, m_code);
289 } else {
290 println!("Motor {} | OK!", i);
291 }
292 }
293 }
294
295 pub fn get_connected_devices(&mut self) -> (Vec<u16>, Vec<String>) {
300 (self.client.ids.clone(), self.client.names.clone())
301 }
302
303 pub fn get_all_slaves_in_network(&mut self) -> (Vec<u16>, Vec<String>) {
304 match self.client.get_poulpe_ids_sync() {
305 Ok(slaves) => slaves,
306 _ => panic!("Error in getting connected devices"),
307 }
308 }
309
310 pub fn get_motor_temperatures(&mut self, slave_id: u16) -> Vec<f32> {
317 match self.client.get_motor_temperatures(slave_id) {
318 Ok(temps) => temps,
319 _ => panic!("Error in getting temperatures"),
320 }
321 }
322 pub fn get_board_temperatures(&mut self, slave_id: u16) -> Vec<f32> {
329 match self.client.get_board_temperatures(slave_id) {
330 Ok(temps) => temps,
331 _ => panic!("Error in getting temperatures"),
332 }
333 }
334
335 pub fn emergency_stop(&mut self, slave_id: u16) {
340 self.client.emergency_stop(slave_id);
341 }
342
343 }
345
346#[pyclass]
347pub struct PyEthercatServer {
348 #[pyo3(get, set)]
349 pub addr: String,
350}
351
352#[pymethods]
353impl PyEthercatServer {
354 #[new]
356 pub fn new() -> Self {
357 PyEthercatServer {
358 addr: "http://127.0.0.1:50098".to_string(),
359 }
360 }
361
362 #[pyo3(signature = (file_name=None))]
369 pub fn launch_server(&mut self, file_name: Option<&str>) {
370 let filename = match file_name {
371 Some(name) => name.to_string(),
372 None => "../config/ethercat.yaml".to_string(),
373 };
374
375 std::thread::spawn(move || {
376 let rt = tokio::runtime::Runtime::new().unwrap();
377 rt.block_on(async {
378 if let Err(e) = poulpe_ethercat_grpc::server::launch_server(&filename).await {
379 eprintln!("Failed to launch the server: {}", e);
380 }
381 });
382 });
383 }
384 pub fn get_all_slaves_in_network(&mut self) -> (Vec<u16>, Vec<String>) {
389 let addr_uri = match self.addr.parse::<Uri>() {
390 Ok(uri) => uri,
391 Err(_) => panic!("Invalid URI format"),
392 };
393
394 match PoulpeIdClient::new(addr_uri).get_slaves() {
395 Ok(slaves) => slaves,
396 _ => panic!("Error in getting connected devices"),
397 }
398 }
399}
400
401#[pymodule]
402fn poulpe_ethercat_py(_py: Python, m: &Bound<'_, PyModule>) -> PyResult<()> {
403 m.add_class::<PyPoulpeRemoteClient>()?;
405 m.add_class::<PyEthercatServer>()?;
407 Ok(())
408}