===================================== CRS93 and CRS97 stations ===================================== The CRS robotic stations feature two 6-DOF articulated robots: the CRS93 and the CRS97. Both robots are controlled by the MARS control unit and are suitable for a variety of robotic tasks. We created a package ``ctu_crs`` to control CTU/CIIRC robots CRS93 and CRS97 via MARS control unit. For detailed specifications and dimensions, please refer to the :download:`product datasheet `. The stations are equipped with `Basler cameras `_ accessible over ethernet via the names ``camera-crs93`` or ``camera-crs97``. .. include:: pylon_viewer.rst .. list-table:: :widths: 50 50 :header-rows: 0 * - .. figure:: imgs/CRS93.jpg :width: 300px :align: center **CRS93 Robot** - .. figure:: imgs/CRS97.jpg :width: 300px :align: center **CRS97 Robot** Installation ============ .. code-block:: bash pip install ctu_crs .. note:: The ``ctu_crs`` package is pre-installed on the computers at the robotic stations. However, you can also install it on your personal computer for experimentation, such as working with the API offline (e.g., forward/inverse kinematics). Step-by-Step Procedure for Operating the Robot ============================================== 1. **Power On the Robot** Turn on the robot using the red switch on the front panel of the control unit (the switch will light up). Press the yellow Arm Power button (a yellow LED will light up above it). 2. **Initialize Communication and Setup in Python** Run the following commands to initiate communication and perform necessary setup. The robot will start moving during this step to perform a "hard home" (finding its physical joint limits) and a "soft home" (moving to a predefined starting joint configuration). .. code-block:: python from ctu_crs import CRS93 # or CRS97 robot = CRS93() # set argument tty_dev=None if you are not connected to robot, # it will allow you to compute FK and IK offline robot.initialize() # initialize connection to the robot, perform hard and soft home .. note:: The "hard/soft home" sequence is only necessary when the control unit has been powered off. If the unit has remained on (e.g., after an emergency stop or opening the safety cage), re-homing is not required. You can disable it by calling ``initialize(home=False)``. 3. **Move the Robot** After initialization, you can continue with your desired commands for operating the robot. For example, you can move the robot to a new joint configuration, grab a picture, or control the gripper. For specific commands and code, please refer to the :ref:`Python examples ` section below. .. warning:: If the robot behaves unexpectedly, immediately press the Emergency Stop button (red mushroom-shaped button). 4. **End of Session - Return Robot to Home Position** To finish working and return the robot to the home position, execute: .. code-block:: python robot.soft_home() robot.close() # close the connection 5. **Turn off the robot** by switching off the red rocker switch on the front panel. Accessing the Robot Within the Safety Cage ------------------------------------------ If you need to work inside the protective cage: 1. Stop the robot (wait until movement stops completely). You can check with: .. code-block:: python robot.in_motion() 2. Run the following command to release the robot: .. code-block:: python robot.release() This will engage the brakes and disconnect feedback. Be cautious, as the robot arm might slightly drop, so avoid performing this command directly above the work surface. 3. Open the cage door (the yellow Arm Power LED will turn off). Restoring Operation After Emergency Stop or Working Inside the Cage ------------------------------------------------------------------- 1. Unlock the emergency stop by pressing the blue button on the side of the emergency button, or close the cage door if open. 2. Press the Motion Stop button. 3. Press the yellow Arm Power button (the yellow Arm Power LED will turn on). 4. Resume sending movement commands to the robot. 5. If the motor enters an error state (indicated by a flashing green status LED above the motor’s letter and a red error LED), reset the motor state with: .. code-block:: python robot.reset_motors() .. _python-examples: Python examples =============== Move the robot ---------------- .. code-block:: python from ctu_crs import CRS93 # or CRS97 robot = CRS93() # set argument tty_dev=None if you are not connected to robot, # it will allow you to compute FK and IK offline robot.initialize() # initialize connection to the robot, perform hard and soft home q = robot.get_q() # get current joint configuration robot.move_to_q(q + [0.1, 0.0, 0.0, 0.0, 0.0, 0.0]) # move robot all values in radians robot.wait_for_motion_stop() # wait until the robot stops robot.close() # close the connection Grab a camera picture --------------------- You can easily capture an image from the camera associated with the robot using the robot interface itself. The library handles the camera connection automatically. .. code-block:: python from ctu_crs import CRS97 # or CRS93 # Initialize the robot interface robot = CRS97() robot.initialize() # Grab an image from the camera # This will automatically connect to and open the camera on the first call img = robot.grab_image() # 'img' is a NumPy array containing the image data. # You can now process it, for example, using a library like OpenCV. if img is not None: print(f"Successfully grabbed image with shape: {img.shape}") # Don't forget to close the connection when you're done robot.close() Control the gripper ------------------- .. code-block:: python from ctu_crs import CRS97 robot = CRS97() robot.initialize() robot.gripper.control_position_relative(0.5) robot.gripper.control_position(robot.gripper.bounds[0]) robot.close() Move individual joints ---------------------- .. code-block:: python import numpy as np from ctu_crs import CRS97 robot = CRS97() robot.initialize() q0 = robot.q_home for i in range(len(q0)): q = q0.copy() q[i] += np.deg2rad(10) robot.move_to_q(q) robot.close() Move to a pose using inverse kinematics (IK) -------------------------------------------- .. code-block:: python import numpy as np from ctu_crs import CRS97 robot = CRS97() robot.initialize() q0 = robot.q_home current_pose = robot.fk(robot.get_q()) current_pose[:3, 3] -= np.array([0.0, 0.0, 0.1]) ik_sols = robot.ik(current_pose) assert len(ik_sols) > 0 closest_solution = min(ik_sols, key=lambda q: np.linalg.norm(q - q0)) robot.move_to_q(closest_solution) robot.wait_for_motion_stop() robot.close() Command-Line Scripts ==================== This package includes command-line scripts for direct robot control from your terminal. This is not suitable for automation but could be used for sanity checks. move_crs93 and move_crs97 ------------------------- After installing the package, you can use the ``move_crs93`` or ``move_crs97`` scripts to move the robot by a relative offset for specified joints. **Usage:** .. code-block:: bash move_crs93 [--nohome] [ ...] move_crs97 [--nohome] [ ...] **Arguments:** * `` ``: One or more pairs of joint names (q0-q5) and their corresponding relative angles in degrees. * ``--nohome``: Optional flag to initialize the robot without performing the homing sequence. **Examples:** To move the crs93's first joint (q0) by 10 degrees and the second joint (q1) by -5 degrees: .. code-block:: bash move_crs93 q0 10 q1 -5 To move the crs97's second joint (q2) by 20.5 degrees without homing the robot first: .. code-block:: bash move_crs97 --nohome q2 20.5