Main robot control loop running at robot_rate Hz. This should be run in a separate thread. Only sends commands when robot is in ENABLED state.
(self)
| 459 | return False |
| 460 | |
| 461 | def control_loop(self) -> None: |
| 462 | """Main robot control loop running at robot_rate Hz. |
| 463 | |
| 464 | This should be run in a separate thread. |
| 465 | Only sends commands when robot is in ENABLED state. |
| 466 | """ |
| 467 | loop_period = 1.0 / self.robot_rate |
| 468 | |
| 469 | while self.running.is_set(): |
| 470 | try: |
| 471 | # Only send commands if robot is enabled |
| 472 | if self.is_robot_enabled(): |
| 473 | # Get current control mode |
| 474 | current_mode = self.get_control_mode() |
| 475 | |
| 476 | with self.position_lock: |
| 477 | if current_mode == PiperController.ControlMode.END_EFFECTOR: |
| 478 | # Send end-effector pose command |
| 479 | self._send_end_effector_command(self._target_pose) |
| 480 | elif current_mode == PiperController.ControlMode.JOINT_SPACE: |
| 481 | # Send joint angles command |
| 482 | self._send_joint_command(self._target_joint_angles) |
| 483 | |
| 484 | # Always send gripper command regardless of control mode |
| 485 | self._send_gripper_command(self._gripper_open_value_degrees) |
| 486 | else: |
| 487 | # Robot is not enabled, just sleep without sending commands |
| 488 | if self.debug_mode: |
| 489 | print("Control loop: Robot not enabled, skipping command") |
| 490 | |
| 491 | time.sleep(loop_period) |
| 492 | |
| 493 | except Exception as e: |
| 494 | print(f"Robot control loop error: {e}") |
| 495 | time.sleep(0.01) |
| 496 | |
| 497 | def _send_end_effector_command(self, transform: np.ndarray) -> None: |
| 498 | """Send end-effector pose command to the robot. |
nothing calls this directly
no test coverage detected