├── .gitignore ├── README.md ├── img ├── 1.png └── 2.png └── src ├── CMakeLists.txt ├── Piper_ros ├── LICENSE ├── Q&A.MD ├── README(EN).md ├── README.MD ├── asserts │ └── pictures │ │ ├── piper_gazebo.png │ │ ├── piper_gazebo_90.png │ │ ├── piper_rviz.png │ │ ├── piper_urdf_no_gripper_zero.png │ │ ├── piper_urdf_zero.png │ │ ├── piper_zero.png │ │ └── tostopic_list.jpg ├── can_activate.sh ├── can_config.sh ├── find_all_can_port.sh └── src │ ├── piper │ ├── CMakeLists.txt │ ├── launch │ │ ├── start_double_piper.launch │ │ ├── start_single_piper.launch │ │ └── start_single_piper_rviz.launch │ ├── package.xml │ └── scripts │ │ ├── piper_control.py │ │ ├── piper_ctrl_single_node.py │ │ ├── piper_pinocchio.py │ │ └── piper_start_ms_node.py │ ├── piper_description │ ├── CMakeLists.txt │ ├── config │ │ ├── joint_names_agx_arm_description.yaml │ │ ├── piper_gazebo_control.yaml │ │ └── piper_no_gripper_gazebo_control.yaml │ ├── launch │ │ ├── piper_no_gripper │ │ │ ├── display_no_gripper_urdf.launch │ │ │ ├── display_no_gripper_xacro.launch │ │ │ ├── gazebo_no_gripper_xacro.launch │ │ │ ├── piper_no_gripper_gazebo_controller.launch │ │ │ └── piper_no_gripper_world.launch │ │ └── piper_with_gripper │ │ │ ├── display_urdf.launch │ │ │ ├── display_xacro.launch │ │ │ ├── gazebo_xacro.launch │ │ │ ├── piper_gazebo_controller.launch │ │ │ ├── piper_world.launch │ │ │ └── rviz_ctrl_gazebo.launch │ ├── meshes │ │ ├── base_link.STL │ │ ├── gripper_base.STL │ │ ├── link1.STL │ │ ├── link2.STL │ │ ├── link3.STL │ │ ├── link4.STL │ │ ├── link5.STL │ │ ├── link6.STL │ │ ├── link7.STL │ │ └── link8.STL │ ├── package.xml │ ├── rviz │ │ ├── piper_ctrl.rviz │ │ └── piper_no_gripper.rviz │ ├── scripts │ │ └── rviz_ctrl_gazebo.py │ ├── urdf │ │ ├── piper_description.csv │ │ ├── piper_description.urdf │ │ ├── piper_description.xacro │ │ ├── piper_no_gripper_description.csv │ │ ├── piper_no_gripper_description.urdf │ │ └── piper_no_gripper_description.xacro │ └── worlds │ │ └── empty.world │ └── piper_msgs │ ├── CMakeLists.txt │ ├── msg │ ├── PiperStatusMsg.msg │ └── PosCmd.msg │ ├── package.xml │ └── srv │ ├── Enable.srv │ ├── GoZero.srv │ └── Gripper.srv └── oculus_reader ├── APK ├── alvr_client_android.apk └── teleop-debug.apk ├── CMakeLists.txt ├── config └── oculus_reader.rviz ├── launch ├── teleop_double_piper.launch └── teleop_single_piper.launch ├── package.xml └── scripts ├── FPS_counter.py ├── buttons_parser.py ├── install.py ├── oculus_reader.py ├── piper_control.py ├── teleop_double_piper.py ├── teleop_single_piper.py └── tools.py /.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | /devel 3 | .catkin_workspace 4 | __pycache__ 5 | .vscode 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 |

quest teleop piper

3 |

Agilex Robotics

4 |

5 | English | 中文 6 |

7 |
8 | 9 | 10 | 11 | 12 | ## 介绍 13 | 14 | 该仓库实现了使用 meta quest2/3 VR 套装对 piper 机械臂进行遥操作。 15 | 16 | ### 准备工作 17 | 18 | 1、安装依赖 19 | 20 | ```bash 21 | sudo apt install android-tools-adb 22 | 23 | conda create -n vt python=3.9 24 | 25 | conda activate vt 26 | 27 | conda install pinocchio==3.2.0 casadi==3.6.7 -c conda-forge 28 | 29 | pip install meshcat rospkg pyyaml pure-python-adb piper-sdk 30 | ``` 31 | 32 | 2、配置您的 quest 设备 33 | 34 | - quest必须支持开发者模式 35 | 36 | 如在 quest 设备上找不到开发者模式,请参考该链接配置 quest 设备。 37 | 38 | 点击:[oculus_reader](https://github.com/rail-berkeley/oculus_reader) 39 | 40 | - 在quest上安装`alvr_client_android.apk`和`teleop-debug.apk`文件,文件在代码里面的`oculus_reader/APK`目录下。 41 | 42 | - [步骤1] 到meta商店安装Mobile VR Station 应用(联网) 43 | 44 | - [步骤2] 将 quest 与 pc 相连,开启 USB调试,在 pc 上显示新设备接入后,把要上述 apk 文件下载并复制到 quest的 Dowanload 目录里面 45 | 46 | - [步骤3] 开启Mobile VR Station => Configuration Wizard => Show All Options => Configuration Scoped Storage => Step1: Request Access => 选择根目录Dowanload 里面刚刚步骤2放的apk 点击类似放大的按钮会弹出一个窗口,在弹出的窗口里点击安装 47 | 48 | - 如果上一步无法安装可以用如下链接中的方案,注意需要windows 49 | - 50 | - 其中的SideQuest app界面会更新,但是一定会有安装apk功能 51 | 52 | 3、将代码克隆下来并编译: 53 | 54 | ```bash 55 | git clone git@github.com:agilexrobotics/questVR_ws.git 56 | 57 | cd questVR_ws 58 | 59 | catkin_make 60 | ``` 61 | 62 | 我们在 Ubuntu 20.04 上测试了我们的代码,其他操作系统可能需要不同的配置。 63 | 64 | 有关更多信息,您可以参考 [開始使用 Meta Quest 2](https://www.meta.com/zh-tw/help/quest/articles/getting-started/getting-started-with-quest-2/?srsltid=AfmBOoqvDcwTtPt2P9o6y3qdXT_9zxz4m8yyej4uwLGEXVXv6KAr3QQz) 、[Piper_ros](https://github.com/agilexrobotics/Piper_ros)、[oculus_reader](https://github.com/rail-berkeley/oculus_reader)。 65 | 66 | 4、进入到 piper_description 功能包下,将 urdf 目录下的 piper_description.urdf 所有 STL 文件的用户名修改成你的用户名,例如: 67 | 68 | ```xml 69 | 70 | 72 | 73 | 74 | 修改成 75 | 76 | 77 | 79 | 80 | ``` 81 | 82 | ### 代码架构说明 83 | 84 | oculus_reader,该存储库提供了从 Quest 设备读取位置和按下按钮的工具。 85 | 86 | 以VR眼镜作为基站,将手柄的与基站的TF关系传输给机械臂。 87 | 88 | ```bash 89 | ├── APK #apk文件 90 | │   ├── alvr_client_android.apk 91 | │   └── teleop-debug.apk 92 | ├── CMakeLists.txt 93 | ├── config 94 | │   └── oculus_reader.rviz 95 | ├── launch #启动文件 96 | │   ├── teleop_double_piper.launch 97 | │   └── teleop_single_piper.launch 98 | ├── package.xml 99 | └── scripts 100 | ├── buttons_parser.py 101 | ├── FPS_counter.py 102 | ├── install.py 103 | ├── oculus_reader.py 104 | ├── piper_control.py #机械臂控制接口 105 | ├── teleop_double_piper.py #遥操作双臂代码 106 | ├── teleop_single_piper.py #遥操作单臂代码 107 | └── tools.py 108 | ``` 109 | 110 | ## 软件启动 111 | 112 | 1、机械臂使能 113 | 114 | **单piper使能**: 115 | 116 | 将机械臂的can线接入电脑 117 | 118 | 然后执行: 119 | 120 | ```bash 121 | cd ~/questVR_ws/src/Piper_ros 122 | 123 | bash can_activate.sh can0 1000000 124 | ``` 125 | 126 | **左右双piper使能**: 127 | 128 | 129 | 先将左机械臂的can线接入电脑 130 | 131 | 然后执行: 132 | 133 | ```bash 134 | cd ~/questVR_ws/src/Piper_ros 135 | 136 | bash find_all_can_port.sh 137 | ``` 138 | 139 | 终端会出现左机械臂的端口号,接着将右机械臂的can线接入电脑 140 | 141 | 再次执行: 142 | 143 | ```bash 144 | bash find_all_can_port.sh 145 | ``` 146 | 147 | 终端会出现左机械臂的端口号。 148 | 149 | 将这左右两个端口号复制到 can_config.sh 文件的 111 和 112 行,如下所示: 150 | 151 | ```bash 152 | # 预定义的 USB 端口、目标接口名称及其比特率(在多个 CAN 模块时使用) 153 | if [ "$EXPECTED_CAN_COUNT" -ne 1 ]; then 154 | declare -A USB_PORTS 155 | USB_PORTS["1-8.1:1.0"]="left_piper:1000000" #左机械臂 156 | USB_PORTS["1-8.2:1.0"]="right_piper:1000000" #右机械臂 157 | fi 158 | ``` 159 | 160 | 保存完毕后,激活左右机械臂使能脚本: 161 | 162 | ```bash 163 | cd ~/questVR_ws/src/Piper_ros 164 | 165 | bash can_config.sh 166 | ``` 167 | 168 | 169 | 2、启动遥操机械臂 170 | 171 | ```bash 172 | source /home/agilex/questVR_ws/devel/setup.bash 173 | 174 | conda activate vt 175 | 176 | roslaunch oculus_reader teleop_single_piper.launch # 单臂遥操 177 | 178 | or 179 | 180 | roslaunch oculus_reader teleop_double_piper.launch # 双臂遥操 181 | ``` 182 | 183 | 在启动遥操代码时出现该错误时: 184 | 185 | ```bash 186 | Device not found. Make sure that device is running and is connected over USB 187 | Run `adb devices` to verify that the device is visible. 188 | ``` 189 | 190 | 说明了VR头盔未开启调试模式,开启调试模式方法步骤如下: 191 | 192 | 1. 使用 USB-C 线将VR头盔连接到计算机,然后佩戴该设备。 193 | 194 | 2. 当在通知中出现“检测到USB”,点击一下该通知。 195 | 196 | ![img error](img/2.png) 197 | 198 | 3. 第一次开启程序,会出现上面的报错。 199 | 200 | 4. 当设备上出现提示时,接受**允许 USB 调试**和**始终允许从此计算机进行。** 201 | 202 | ![img error](img/1.png) 203 | 204 | 5. 关掉程序,再次运行。 205 | 206 | 207 | 208 | 209 | 210 | ## 操作说明 211 | 212 | > 注意⚠️: 213 | > 214 | > - 请一定要确保VR屏幕保持常亮,否则TF会乱飘导致遥操作机械臂乱飞,我们建议在VR眼镜里面拿东西遮住感应器,使其保持常亮状态。 215 | > - 开启程序后,请一定要确保手柄在VR视野里以及rviz里面的坐标稳定不会乱飘,然后按住按键“A”||“X”使机械臂复位,复位后才可进行遥操做,否则机械臂也会乱飞。 216 | > - 在遥操 piper 启动后,请注意观察网页端的机械臂是否乱飘, 217 | 218 | - 遥操单臂使用右手手柄,开始遥操前确保机械臂回到初始姿态,按住按键 “A” 能使机械臂回到初始位置,长按按键 “B” 为遥操机械臂,松开为停止控制。遥操双臂同理。 219 | 220 | - 为了操作的人身安全以及减少对机械臂的损害,在遥操结束后,请确保机械臂回到初始位置附件再按下“A”||“X”键复位。 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | -------------------------------------------------------------------------------- /img/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agilexrobotics/questVR_ws/b7a97d3eaa3adfba08af0ecf132dbb88eab4e5b9/img/1.png -------------------------------------------------------------------------------- /img/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agilexrobotics/questVR_ws/b7a97d3eaa3adfba08af0ecf132dbb88eab4e5b9/img/2.png -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | /opt/ros/noetic/share/catkin/cmake/toplevel.cmake -------------------------------------------------------------------------------- /src/Piper_ros/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 RosenYin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/Piper_ros/Q&A.MD: -------------------------------------------------------------------------------- 1 | # piper_ros Q&A 2 | 3 | 1. 录joint的包后播放包,机械臂运行卡顿,并且包播放结束,机械臂还在运动(就是回调函数依旧在处理): 4 | 5 | 原因: 与电脑性能有关,性能差的电脑处理不过来,导致回调函数处理时间长 6 | 7 | 解决办法: 将回调函数如joint_callback函数中的打印以及log注释 8 | -------------------------------------------------------------------------------- /src/Piper_ros/README(EN).md: -------------------------------------------------------------------------------- 1 | # AgileX Robotic Arm 2 | 3 | [CN](README.MD) 4 | 5 | ![ubuntu](https://img.shields.io/badge/Ubuntu-20.04-orange.svg) 6 | 7 | |ROS |STATE| 8 | |---|---| 9 | |![ros](https://img.shields.io/badge/ROS-noetic-blue.svg)|![Pass](https://img.shields.io/badge/Pass-blue.svg)| 10 | 11 | ## Installation 12 | 13 | ### Install dependencies 14 | 15 | ```shell 16 | pip3 install python-can 17 | ``` 18 | 19 | ```shell 20 | pip3 install piper_sdk 21 | ``` 22 | 23 | ## Quick Start 24 | 25 | ### Enable CAN module 26 | 27 | First, you need to set up the shell script parameters. 28 | 29 | #### Single robotic arm 30 | 31 | ##### PC with Only One USB-to-CAN Module Inserted 32 | 33 | - ##### Use the `can_activate.sh` 34 | 35 | Directly run: 36 | 37 | ```bash 38 | bash can_activate.sh can0 1000000 39 | ``` 40 | 41 | ##### PC with Multiple USB-to-CAN Modules Inserted 42 | 43 | - ##### Use the `can_activate.sh` script 44 | 45 | Disconnect all CAN modules. 46 | 47 | Only connect the CAN module linked to the robotic arm to the PC, and then run the script. 48 | 49 | ```shell 50 | sudo ethtool -i can0 | grep bus 51 | ``` 52 | 53 | and record the `bus-info` value, for example, `1-2:1.0`. 54 | 55 | **Note: Generally, the first inserted CAN module defaults to `can0`. If the CAN interface is not found, use `bash find_all_can_port.sh` to check the CAN names corresponding to the USB addresses.** 56 | 57 | Assuming the recorded `bus-info` value from the above operation is `1-2:1.0`. 58 | 59 | Then execute the command to check if the CAN device has been successfully activated. 60 | 61 | ```bash 62 | bash can_activate.sh can_piper 1000000 "1-2:1.0" 63 | ``` 64 | 65 | **Note: This means that the CAN device connected to the USB port with hardware encoding `1-2:1.0` is renamed to `can_piper`, set to a baud rate of 1,000,000, and activated.** 66 | 67 | Then run`ifconfig` to check if `can_piper` appears. If it does, the CAN module has been successfully configured. 68 | 69 | ### Running the Node 70 | 71 | #### Single Robotic Arm 72 | 73 | Node name: `piper_ctrl_single_node.py` 74 | 75 | param 76 | 77 | ```shell 78 | can_port:he name of the CAN route to open. 79 | auto_enable: Whether to automatically enable the system. If True, the system will automatically enable upon starting the program. 80 | # Set this to False if you want to manually control the enable state. If the program is interrupted and then restarted, the robotic arm will maintain the state it had during the last run. 81 | # If the arm was enabled, it will remain enabled after restarting. 82 | # If the arm was disabled, it will remain disabled after restarting. 83 | girpper_exist:Indicates if there is an end-effector gripper. If True, the gripper control will be enabled. 84 | rviz_ctrl_flag: Whether to use RViz to send joint angle messages. If True, the system will receive joint angle messages sent by rViz. 85 | # Since the joint 7 range in RViz is [0,0.04], but the actual gripper travel is 0.08m, joint 7 values sent by RViz will be multiplied by 2 when controlling the gripper. 86 | ``` 87 | 88 | `start_single_piper_rviz.launch`: 89 | 90 | ```xml 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | ``` 105 | 106 | `start_single_piper.launch`: 107 | 108 | ```xml 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | ``` 123 | 124 | Start control node 125 | 126 | ```shell 127 | # Start node 128 | roscore 129 | rosrun piper piper_ctrl_single_node.py _can_port:=can0 _mode:=0 130 | # Start launch 131 | roslaunch piper start_single_piper.launch can_port:=can0 auto_enable:=true 132 | # Or,the node can be run with default parameters 133 | roslaunch piper start_single_piper.launch 134 | # You can also use RViz to enable control by adjusting the parameters as described above. 135 | roslaunch piper start_single_piper_rviz.launch 136 | ``` 137 | 138 | If you only start control node but don't start rviz: 139 | 140 | `rostopic list` 141 | 142 | ```shell 143 | /arm_status #Status of robotic arm. 144 | /enable_flag #Enable flag, sent to the node, send "true" to enable 145 | /end_pose #Feedback on the end-effector pose of the robotic arm 146 | /joint_states #Subscribe to joint messages, sending joint positions through this message allows control of the robotic arm's movement. 147 | /joint_states_single #Feedback on the robotic arm's joint status 148 | /pos_cmd #End-effector control message 149 | ``` 150 | 151 | ## Note 152 | 153 | - You need to activate the CAN device and set the correct baud rate before you can read messages from or control the robotic arm. 154 | - If you see: 155 | 156 | ```shell 157 | Enable Status: False 158 | Message NOT sent 159 | Message NOT sent 160 | ``` 161 | 162 | It indicates that the robotic arm is not connected to the CAN module. After unplugging and replugging the USB, restart the robotic arm, then activate the CAN module, and try restarting the node again. 163 | 164 | If automatic enablement is enabled and enabling fails after 5 seconds, the program will automatically exit. 165 | 166 | ### piper Custom Messages 167 | 168 | ros package `piper_msgs` 169 | 170 | **Robotic Arm Status Feedback Message**: Corresponds to the feedback message with `id=0x2A1` in the CAN protocol. 171 | 172 | `PiperStatusMsg.msg` 173 | 174 | ```c 175 | uint8 ctrl_mode 176 | /* 177 | 0x00 Standby mode 178 | 0x01 CAN command control mode 179 | 0x02 Teaching mode 180 | 0x03 Ethernet control mode 181 | 0x04 wifi control mode 182 | 0x05 Remote controller control mode 183 | 0x06 Linked teaching mode 184 | 0x07 Offline track mode 185 | */ 186 | uint8 arm_status 187 | /* 188 | 0x00 Normal 189 | 0x01 Emergency stop 190 | 0x02 No solution 191 | 0x03 Singularity 192 | 0x04 Target angle exceeds limit 193 | 0x05 Joint communication error 194 | 0x06 Joint brake not released 195 | 0x07 Robotic arm collision detected 196 | 0x08 Overspeed during drag teaching 197 | 0x09 Joint status abnormal 198 | 0x0A Other abnormality 199 | 0x0B Teaching record 200 | 0x0C Teaching execution 201 | 0x0D Teaching paused 202 | 0x0E Main control NTC overheating 203 | 0x0F Discharge resistor NTC overheating 204 | */ 205 | uint8 mode_feedback 206 | /* 207 | 0x00 MOVE P 208 | 0x01 MOVE J 209 | 0x02 MOVE L 210 | 0x03 MOVE C 211 | */ 212 | uint8 teach_status 213 | /* 214 | 0x00 Close 215 | 0x01 Start teaching recording (enter drag teaching mode) 216 | 0x02 End teaching recording (exit drag teaching mode) 217 | 0x03 Execute teaching trajectory (reproduce drag teaching trajectory) 218 | 0x04 Pause 219 | 0x05 Resume (continue trajectory reproduction) 220 | 0x06 Terminate execution 221 | 0x07 Move to trajectory starting point 222 | */ 223 | uint8 motion_status 224 | /* 225 | 0x00 Reached the specified point 226 | 0x01 Not reached the specified point 227 | */ 228 | uint8 trajectory_num 229 | /* 0~255 (Feedback in offline trajectory mode) */ 230 | int64 err_code // Error code 231 | bool joint_1_angle_limit// Joint 1 communication error (0: Normal, 1: Error) 232 | bool joint_2_angle_limit// Joint 2 communication error (0: Normal, 1: Error) 233 | bool joint_3_angle_limit// Joint 3 communication error (0: Normal, 1: Error) 234 | bool joint_4_angle_limit// Joint 4 communication error (0: Normal, 1: Error) 235 | bool joint_5_angle_limit// Joint 5 communication error (0: Normal, 1: Error) 236 | bool joint_6_angle_limit// Joint 6 communication error (0: Normal, 1: Error) 237 | bool communication_status_joint_1// Joint 1 angle exceeds limit (0: Normal, 1: Error) 238 | bool communication_status_joint_2// Joint 2 angle exceeds limit (0: Normal, 1: Error) 239 | bool communication_status_joint_3// Joint 3 angle exceeds limit (0: Normal, 1: Error) 240 | bool communication_status_joint_4// Joint 4 angle exceeds limit (0: Normal, 1: Error) 241 | bool communication_status_joint_5// Joint 5 angle exceeds limit (0: Normal, 1: Error) 242 | bool communication_status_joint_6// Joint 6 angle exceeds limit (0: Normal, 1: Error) 243 | ``` 244 | 245 | End-effector pose control: Note that some singularities may be unreachable. 246 | 247 | `PosCmd.msg` 248 | 249 | ```c 250 | float64 x 251 | float64 y 252 | float64 z 253 | float64 roll 254 | float64 pitch 255 | float64 yaw 256 | float64 gripper 257 | int32 mode1// Temporarily unused 258 | int32 mode2// Temporarily unused 259 | ``` 260 | 261 | ## Simulation 262 | 263 | `display_xacro.launch` 264 | 265 | open rviz 266 | 267 | ```shell 268 | cd Piper_ros 269 | source devel/setup.bash 270 | roslaunch piper_description display_xacro.launch 271 | ``` 272 | 273 | After running, the `/joint_states` topic will be published. You can view it by `rostopic echo /joint_states` 274 | 275 | ![ ](./asserts/pictures/tostopic_list.jpg) 276 | 277 | Two windows will appear simultaneously as follows. The slider values correspond to the `/joint_states` values. Dragging the sliders will change these values, and the model in rviz will update accordingly. 278 | 279 | Sometimes the slider window is not visible. Check if there is a window in the dock. It may be covered by other pages. 280 | 281 | ![ ](./asserts/pictures/piper_rviz.jpg) 282 | 283 | ## Gazebo 284 | 285 | Run 286 | 287 | ```shell 288 | cd Piper_ros 289 | source devel/setup.bash 290 | roslaunch piper_description gazebo_xacro.launch 291 | ``` 292 | 293 | ![ ](./asserts/pictures/piper_gazebo.jpg) 294 | 295 | After running, these will be published: 296 | 297 | ```shell 298 | /piper_description/joint_states 299 | /piper_description/joint1_position_controller/command 300 | /piper_description/joint2_position_controller/command 301 | /piper_description/joint3_position_controller/command 302 | /piper_description/joint4_position_controller/command 303 | /piper_description/joint5_position_controller/command 304 | /piper_description/joint6_position_controller/command 305 | /piper_description/joint7_position_controller/command 306 | /piper_description/joint8_position_controller/command 307 | ``` 308 | 309 | `/piper_description/joint_states` is the virtual feedback topic for the joint states of the robotic arm in Gazebo, while the others are subscriber nodes in Gazebo. 310 | 311 | These command topics are used to control the movement of the robotic arm in Gazebo. The joint limits in the xacro file are as follows: joints 1 to 6 are in radians, and joints 7 and 8 are in meters, as joints 7 and 8 correspond to the gripper. 312 | 313 | | joint_name | limit | 314 | | ---------- | -------------- | 315 | | joint1 | [-2.618,2.618] | 316 | | joint2 | [0,3.14] | 317 | | joint3 | [-2.697,0] | 318 | | joint4 | [-1.832,1.832] | 319 | | joint5 | [-1.22,1.22] | 320 | | joint6 | [-2.0944,2.0944] | 321 | | joint7 | [0,0.038] | 322 | | joint8 | [-0.038,0] | 323 | 324 | To move Joint 1 by 90 degrees, you would need to send a command: 325 | 326 | ```shell 327 | rostopic pub /piper_description/joint1_position_controller/command std_msgs/Float64 "data: 1.57" 328 | ``` 329 | 330 | You can see that the robot link1 rotates 90 degrees 331 | 332 | ![ ](./asserts/pictures/piper_gazebo_90.jpg) 333 | -------------------------------------------------------------------------------- /src/Piper_ros/README.MD: -------------------------------------------------------------------------------- 1 | # agx 机械臂 2 | 3 | [EN](README(EN).md) 4 | 5 | ![ubuntu](https://img.shields.io/badge/Ubuntu-20.04-orange.svg) 6 | 7 | |ROS |STATE| 8 | |---|---| 9 | |![ros](https://img.shields.io/badge/ROS-noetic-blue.svg)|![Pass](https://img.shields.io/badge/Pass-blue.svg)| 10 | 11 | ## 0 注意URDF版本(以零点区分) 12 | 13 | 若您的机械臂,上电后使用上位机使能回零,j2和j3关节抬起了2度的角度,则为v00版零点,如下图: 14 | 15 | ![ ](./asserts/pictures/piper_zero.png) 16 | 17 | 旧版本零点以j2和j3的限位位置偏移2度得到,现URDF中的文件都是接触限位处 18 | 19 | ## 1 安装方法 20 | 21 | ### 1.1 安装依赖 22 | 23 | ```shell 24 | pip3 install python-can 25 | ``` 26 | 27 | ```shell 28 | pip3 install piper_sdk 29 | ``` 30 | 31 | ## 2 快速使用 32 | 33 | ### 2.2 使能can模块 34 | 35 | 首先需要设置好shell脚本参数 36 | 37 | #### 2.2.1 单条机械臂 38 | 39 | ##### 1)pc只插入一个usb转can模块 40 | 41 | - **此处使用`can_activate.sh`脚本** 42 | 43 | 直接执行 44 | 45 | ```bash 46 | bash can_activate.sh can0 1000000 47 | ``` 48 | 49 | ##### 2)pc插入多个usb转can模块 50 | 51 | - **此处使用`can_activate.sh`脚本** 52 | 53 | 拔掉所有can模块 54 | 55 | 只将连接到机械臂的can模块插入PC,执行 56 | 57 | ```shell 58 | sudo ethtool -i can0 | grep bus 59 | ``` 60 | 61 | 并记录下`bus-info`的数值例如`1-2:1.0` 62 | 63 | ps:**一般第一个插入的can模块会默认是can0,如果没有查询到can可以使用`bash find_all_can_port.sh`来查看刚才usb地址对应的can名称** 64 | 65 | 假设上面的操作记录的`bus-info`数值为`1-2:1.0` 66 | 67 | 然后执行,查看can设备是否激活成功 68 | 69 | ```bash 70 | bash can_activate.sh can_piper 1000000 "1-2:1.0" 71 | ``` 72 | 73 | ps:**此处的意思是,1-2:1.0硬件编码的usb端口插入的can设备,名字被重命名为can_piper,波特率为1000000,并激活** 74 | 75 | 然后执行`ifconfig`查看是否有`can_piper`,如果有则can模块设置成功 76 | 77 | ### 2.3 运行节点 78 | 79 | #### 2.3.1 单机械臂 80 | 81 | 节点名`piper_ctrl_single_node.py` 82 | 83 | param 84 | 85 | ```shell 86 | can_port:要打开的can路由名字 87 | auto_enable:是否自动使能,True则开启程序就自动使能 88 | # 注意这个设置为False,中断程序后再启动节点,机械臂会保持上次启动程序的状态 89 | # 若上次启动程序机械臂状态为使能,则中断程序后再启动节点,机械臂仍为使能 90 | # 若上次启动程序机械臂状态为失能,则中断程序后再启动节点,机械臂仍为失能 91 | girpper_exist:是否有末端夹爪,True则说明有末端夹爪,会开启夹爪控制 92 | rviz_ctrl_flag:是否使用rviz来发送关节角消息,True则接收rviz发送的关节角消息 93 | #由于rviz中的joint7范围是[0,0.04],而真实夹爪行程为0.08m,打开rviz控制后会将rviz发出的joint7乘2倍 94 | ``` 95 | 96 | `start_single_piper.launch`如下: 97 | 98 | ```xml 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | ``` 115 | 116 | `start_single_piper_rviz.launch`如下: 117 | 118 | ```xml 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | ``` 134 | 135 | ##### (1)启动控制节点 136 | 137 | 提供几种不同的启动方式,启动的都是相同节点 138 | 139 | ```shell 140 | # 启动节点 141 | roscore 142 | rosrun piper piper_ctrl_single_node.py _can_port:=can0 _mode:=0 143 | # 或,使用launch 启动节点 144 | roslaunch piper start_single_piper.launch can_port:=can0 auto_enable:=true 145 | # 或,直接运行launch,会以默认参数运行 146 | roslaunch piper start_single_piper.launch 147 | # 也可以用rviz开启控制,需要更改的参数如上述 148 | roslaunch piper start_single_piper_rviz.launch 149 | ``` 150 | 151 | 如果只是单独启动了控制节点,没有启动rviz 152 | 153 | `rostopic list` 154 | 155 | ```shell 156 | /arm_status #机械臂状态,详见下文 157 | /enable_flag #使能标志位,发送给节点,发送true用来使能 158 | /end_pose #机械臂末端位姿状态反馈,四元数 159 | /end_pose_euler #机械臂末端位姿状态反馈,欧拉角(为自定义消息) 160 | /joint_states #订阅关节消息,给这个消息发送关节位置能控制机械臂运动 161 | /joint_states_single #机械臂关节状态反馈 162 | /pos_cmd #末端控制消息 163 | ``` 164 | 165 | `rosservice list` 166 | 167 | ```shell 168 | /enable_srv #机械臂使能服务端 169 | /go_zero_srv #机械臂归零服务 170 | /gripper_srv #机械臂夹爪控制服务 171 | /reset_srv #机械臂重置服务 172 | /stop_srv #机械臂停止服务 173 | ``` 174 | 175 | ##### (2)使能机械臂 176 | 177 | ```shell 178 | # call 服务端 179 | rosservice call /enable_srv "enable_request: true" 180 | # pub topic 181 | rostopic pub /enable_flag std_msgs/Bool "data: true" 182 | ``` 183 | 184 | ##### (3)失能机械臂 185 | 186 | ```shell 187 | # call 服务端 188 | rosservice call /enable_srv "enable_request: false" 189 | # pub topic 190 | rostopic pub /enable_flag std_msgs/Bool "data: false" 191 | ``` 192 | 193 | ##### (4)发布关节消息 194 | 195 | 注意,机械臂会抬起,请确保机械臂工作范围内无障碍 196 | 197 | ```shell 198 | rostopic pub /joint_states sensor_msgs/JointState "header: 199 | seq: 0 200 | stamp: {secs: 0, nsecs: 0} 201 | frame_id: '' 202 | name: [''] 203 | position: [0.2,0.2,-0.2,0.3,-0.2,0.5,0.01] 204 | velocity: [0,0,0,0,0,0,10] 205 | effort: [0,0,0,0,0,0,0.5]" 206 | ``` 207 | 208 | ##### (5)停止机械臂,注意机械臂会以一个恒定阻尼落下 209 | 210 | ```shell 211 | rosservice call /stop_srv 212 | ``` 213 | 214 | ##### (6)重置机械臂,注意机械臂会立刻掉电落下 215 | 216 | ```shell 217 | rosservice call /reset_srv 218 | ``` 219 | 220 | ##### (7)令机械臂归零 221 | 222 | - 如果机械臂为mit模式,将`is_mit_mode`置为`true` 223 | - 如果机械臂不为mit模式(位置速度控制模式),将`is_mit_mode`置为`false` 224 | 225 | ```shell 226 | rosservice call /go_zero_srv "is_mit_mode: false" 227 | rosservice call /go_zero_srv "is_mit_mode: true" 228 | ``` 229 | 230 | ### 2.4 piper自定义消息 231 | 232 | ros功能包`piper_msgs` 233 | 234 | 机械臂自身状态反馈消息,对应can协议中`id=0x2A1`的反馈消息 235 | 说明 236 | 237 | `PiperStatusMsg.msg` 238 | 239 | ```c 240 | uint8 ctrl_mode 241 | /* 242 | 0x00 待机模式 243 | 0x01 CAN指令控制模式 244 | 0x02 示教模式 245 | 0x03 以太网控制模式 246 | 0x04 wifi控制模式 247 | 0x05 遥控器控制模式 248 | 0x06 联动示教输入模式 249 | 0x07 离线轨迹模式*/ 250 | uint8 arm_status 251 | /* 252 | 0x00 正常 253 | 0x01 急停 254 | 0x02 无解 255 | 0x03 奇异点 256 | 0x04 目标角度超过限 257 | 0x05 关节通信异常 258 | 0x06 关节抱闸未打开 259 | 0x07 机械臂发生碰撞 260 | 0x08 拖动示教时超速 261 | 0x09 关节状态异常 262 | 0x0A 其它异常 263 | 0x0B 示教记录 264 | 0x0C 示教执行 265 | 0x0D 示教暂停 266 | 0x0E 主控NTC过温 267 | 0x0F 释放电阻NTC过温*/ 268 | uint8 mode_feedback 269 | /* 270 | 0x00 MOVE P 271 | 0x01 MOVE J 272 | 0x02 MOVE L 273 | 0x03 MOVE C*/ 274 | uint8 teach_status 275 | /* 276 | 0x00 关闭 277 | 0x01 开始示教记录(进入拖动示教模式) 278 | 0x02 结束示教记录(退出拖动示教模式) 279 | 0x03 执行示教轨迹(拖动示教轨迹复现) 280 | 0x04 暂停执行 281 | 0x05 继续执行(轨迹复现继续) 282 | 0x06 终止执行 283 | 0x07 运动到轨迹起点*/ 284 | uint8 motion_status 285 | /* 286 | 0x00 到达指定点位 287 | 0x01 未到达指定点位*/ 288 | uint8 trajectory_num 289 | /*0~255 (离线轨迹模式下反馈)*/ 290 | int64 err_code//故障码 291 | bool joint_1_angle_limit//1号关节通信异常(0:正常 1:异常) 292 | bool joint_2_angle_limit//2号关节通信异常(0:正常 1:异常) 293 | bool joint_3_angle_limit//3号关节通信异常(0:正常 1:异常) 294 | bool joint_4_angle_limit//4号关节通信异常(0:正常 1:异常) 295 | bool joint_5_angle_limit//5号关节通信异常(0:正常 1:异常) 296 | bool joint_6_angle_limit//6号关节通信异常(0:正常 1:异常) 297 | bool communication_status_joint_1//1号关节角度超限位(0:正常 1:异常) 298 | bool communication_status_joint_2//2号关节角度超限位(0:正常 1:异常) 299 | bool communication_status_joint_3//3号关节角度超限位(0:正常 1:异常) 300 | bool communication_status_joint_4//4号关节角度超限位(0:正常 1:异常) 301 | bool communication_status_joint_5//5号关节角度超限位(0:正常 1:异常) 302 | bool communication_status_joint_6//6号关节角度超限位(0:正常 1:异常) 303 | ``` 304 | 305 | 机械臂末端位姿控制,注意:有些奇异点无法到达 306 | 307 | `PosCmd.msg` 308 | 309 | ```c 310 | // 单位:m 311 | float64 x 312 | float64 y 313 | float64 z 314 | // 单位:rad 315 | float64 roll 316 | float64 pitch 317 | float64 yaw 318 | float64 gripper 319 | // 暂为无效参数 320 | int32 mode1 321 | int32 mode2 322 | ``` 323 | 324 | ## 3 注意事项 325 | 326 | - 需要先激活can设备,并且设置正确的波特率,才可以读取机械臂消息或者控制机械臂 327 | - 如果出现 328 | 329 | ```shell 330 | 使能状态: False 331 | Message NOT sent 332 | Message NOT sent 333 | ``` 334 | 335 | 说明机械臂没有与can模块连同,拔插usb后,重新启动机械臂,再激活can模块,然后尝试重新启动节点 336 | 337 | - 如果打开了自动使能,尝试使能5s没有成功后,会自动退出程序 338 | 339 | ## 4 使用仿真 340 | 341 | ### 4.1 rviz 342 | 343 | `display_xacro.launch` 打开rviz 344 | 345 | 执行 346 | 347 | ```shell 348 | cd Piper_ros 349 | source devel/setup.bash 350 | roslaunch piper_description display_xacro.launch 351 | ``` 352 | 353 | 运行后会发布`/joint_states`,可以通过`rostopic echo /joint_states` 查看 354 | 355 | ![ ](./asserts/pictures/tostopic_list.jpg) 356 | 357 | 同时会弹出两个页面如下,滑动条数值对应`/joint_states`数值,拖动滑动条可以改变其数值,rviz中的模型也会随动 358 | 359 | 有时滑动条窗口未显示,请查看下dock栏是否有窗口,可能是被其它页面覆盖了 360 | 361 | ![ ](./asserts/pictures/piper_rviz.png) 362 | 363 | ### 4.2 gazebo 364 | 365 | 执行 366 | 367 | ```shell 368 | cd Piper_ros 369 | source devel/setup.bash 370 | roslaunch piper_description gazebo_xacro.launch 371 | ``` 372 | 373 | ![ ](./asserts/pictures/piper_gazebo.png) 374 | 375 | 运行后会发布 376 | 377 | ```shell 378 | /piper_description/joint_states 379 | /piper_description/joint1_position_controller/command 380 | /piper_description/joint2_position_controller/command 381 | /piper_description/joint3_position_controller/command 382 | /piper_description/joint4_position_controller/command 383 | /piper_description/joint5_position_controller/command 384 | /piper_description/joint6_position_controller/command 385 | /piper_description/joint7_position_controller/command 386 | /piper_description/joint8_position_controller/command 387 | ``` 388 | 389 | `/piper_description/joint_states` 是gazebo的机械臂关节状态的虚拟反馈话题,其余的为gazebo的订阅节点 390 | 391 | 这几个command话题用来控制gazebo中的机械臂运动,关节在xacro中的限位如下,其中,1~6关节单位为弧度,7、8关节单位为m,因为7、8关节对应夹爪 392 | 393 | |joint_name| limit(rad) | limit(angle) | limit(rad/s) | limit(rad/s^2) | 394 | |----------| ---------- | ---------- | ---------- | ---------- | 395 | |joint1 | [-2.618, 2.618] | [-150.0, 150.0] | [0, 3.0] | [0, 5.0] | 396 | |joint2 | [0, 3.14] | [0, 180.0] | [0, 3.0] | [0, 5.0] | 397 | |joint3 | [-2.967, 0] | [-170, 0] | [0, 3.0] | [0, 5.0] | 398 | |joint4 | [-1.745, 1.745] | [-100.0, 100.0] | [0, 3.0] | [0, 5.0] | 399 | |joint5 | [-1.22, 1.22] | [-70.0, 70.0] | [0, 3.0] | [0, 5.0] | 400 | |joint6 | [-2.0944, 2.0944]| [-120.0, 120.0] | [0, 3.0] | [0, 5.0] | 401 | 402 | 假如想要令关节1运动90度,发送 403 | 404 | ```shell 405 | rostopic pub /piper_description/joint1_position_controller/command std_msgs/Float64 "data: 1.57" 406 | ``` 407 | 408 | 可以看到机械臂link1旋转了90度 409 | 410 | ![ ](./asserts/pictures/piper_gazebo_90.png) 411 | 412 | ## Q&A 413 | 414 | [Q&A](Q&A.MD) 415 | -------------------------------------------------------------------------------- /src/Piper_ros/asserts/pictures/piper_gazebo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agilexrobotics/questVR_ws/b7a97d3eaa3adfba08af0ecf132dbb88eab4e5b9/src/Piper_ros/asserts/pictures/piper_gazebo.png -------------------------------------------------------------------------------- /src/Piper_ros/asserts/pictures/piper_gazebo_90.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agilexrobotics/questVR_ws/b7a97d3eaa3adfba08af0ecf132dbb88eab4e5b9/src/Piper_ros/asserts/pictures/piper_gazebo_90.png -------------------------------------------------------------------------------- /src/Piper_ros/asserts/pictures/piper_rviz.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agilexrobotics/questVR_ws/b7a97d3eaa3adfba08af0ecf132dbb88eab4e5b9/src/Piper_ros/asserts/pictures/piper_rviz.png -------------------------------------------------------------------------------- /src/Piper_ros/asserts/pictures/piper_urdf_no_gripper_zero.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agilexrobotics/questVR_ws/b7a97d3eaa3adfba08af0ecf132dbb88eab4e5b9/src/Piper_ros/asserts/pictures/piper_urdf_no_gripper_zero.png -------------------------------------------------------------------------------- /src/Piper_ros/asserts/pictures/piper_urdf_zero.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agilexrobotics/questVR_ws/b7a97d3eaa3adfba08af0ecf132dbb88eab4e5b9/src/Piper_ros/asserts/pictures/piper_urdf_zero.png -------------------------------------------------------------------------------- /src/Piper_ros/asserts/pictures/piper_zero.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agilexrobotics/questVR_ws/b7a97d3eaa3adfba08af0ecf132dbb88eab4e5b9/src/Piper_ros/asserts/pictures/piper_zero.png -------------------------------------------------------------------------------- /src/Piper_ros/asserts/pictures/tostopic_list.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agilexrobotics/questVR_ws/b7a97d3eaa3adfba08af0ecf132dbb88eab4e5b9/src/Piper_ros/asserts/pictures/tostopic_list.jpg -------------------------------------------------------------------------------- /src/Piper_ros/can_activate.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 默认的 CAN 名称,用户可以通过命令行参数设定 4 | DEFAULT_CAN_NAME="${1:-can0}" 5 | 6 | # 单个 CAN 模块时的默认比特率,用户可以通过命令行参数设定 7 | DEFAULT_BITRATE="${2:-1000000}" 8 | 9 | # USB 硬件地址(可选参数) 10 | USB_ADDRESS="${3}" 11 | echo "-------------------START-----------------------" 12 | # 检查 ethtool 是否已安装 13 | if ! dpkg -l | grep -q "ethtool"; then 14 | echo "\e[31m错误: 系统中未检测到 ethtool。\e[0m" 15 | echo "请使用以下命令安装 ethtool:" 16 | echo "sudo apt update && sudo apt install ethtool" 17 | exit 1 18 | fi 19 | 20 | # 检查 can-utils 是否已安装 21 | if ! dpkg -l | grep -q "can-utils"; then 22 | echo "\e[31m错误: 系统中未检测到 can-utils。\e[0m" 23 | echo "请使用以下命令安装 can-utils:" 24 | echo "sudo apt update && sudo apt install can-utils" 25 | exit 1 26 | fi 27 | 28 | echo "ethtool 和 can-utils 均已安装。" 29 | 30 | # 获取当前系统中的 CAN 模块数量 31 | CURRENT_CAN_COUNT=$(ip link show type can | grep -c "link/can") 32 | 33 | # 检查当前系统中的 CAN 模块数量是否符合预期 34 | if [ "$CURRENT_CAN_COUNT" -ne "1" ]; then 35 | if [ -z "$USB_ADDRESS" ]; then 36 | # 遍历所有 CAN 接口 37 | for iface in $(ip -br link show type can | awk '{print $1}'); do 38 | # 使用 ethtool 获取 bus-info 39 | BUS_INFO=$(sudo ethtool -i "$iface" | grep "bus-info" | awk '{print $2}') 40 | 41 | if [ -z "$BUS_INFO" ];then 42 | echo "错误: 无法获取接口 $iface 的 bus-info 信息。" 43 | continue 44 | fi 45 | 46 | echo "接口 $iface 插入在 USB 端口 $BUS_INFO" 47 | done 48 | echo -e " \e[31m 错误: 系统检测到的 CAN 模块数量 ($CURRENT_CAN_COUNT) 与预期数量 (1) 不符。\e[0m" 49 | echo -e " \e[31m 请增加usb硬件地址参数,如: \e[0m" 50 | echo -e " bash can_activate.sh can0 1000000 1-2:1.0" 51 | echo "-------------------ERROR-----------------------" 52 | exit 1 53 | fi 54 | fi 55 | 56 | # 加载 gs_usb 模块 57 | # sudo modprobe gs_usb 58 | # if [ $? -ne 0 ]; then 59 | # echo "错误: 无法加载 gs_usb 模块。" 60 | # exit 1 61 | # fi 62 | 63 | if [ -n "$USB_ADDRESS" ]; then 64 | echo "检测到 USB 硬件地址参数: $USB_ADDRESS" 65 | 66 | # 使用 ethtool 查找与 USB 硬件地址对应的 CAN 接口 67 | INTERFACE_NAME="" 68 | for iface in $(ip -br link show type can | awk '{print $1}'); do 69 | BUS_INFO=$(sudo ethtool -i "$iface" | grep "bus-info" | awk '{print $2}') 70 | if [ "$BUS_INFO" == "$USB_ADDRESS" ]; then 71 | INTERFACE_NAME="$iface" 72 | break 73 | fi 74 | done 75 | 76 | if [ -z "$INTERFACE_NAME" ]; then 77 | echo "错误: 无法找到与 USB 硬件地址 $USB_ADDRESS 对应的 CAN 接口。" 78 | exit 1 79 | else 80 | echo "找到与 USB 硬件地址 $USB_ADDRESS 对应的接口: $INTERFACE_NAME" 81 | fi 82 | else 83 | # 获取唯一的 CAN 接口 84 | INTERFACE_NAME=$(ip -br link show type can | awk '{print $1}') 85 | 86 | # 检查是否获取到了接口名称 87 | if [ -z "$INTERFACE_NAME" ]; then 88 | echo "错误: 无法检测到 CAN 接口。" 89 | exit 1 90 | fi 91 | BUS_INFO=$(sudo ethtool -i "$INTERFACE_NAME" | grep "bus-info" | awk '{print $2}') 92 | echo "预期配置单个can模块,检测到接口 $INTERFACE_NAME,对应的usb地址为 $BUS_INFO" 93 | fi 94 | 95 | # 检查当前接口是否已经激活 96 | IS_LINK_UP=$(ip link show "$INTERFACE_NAME" | grep -q "UP" && echo "yes" || echo "no") 97 | 98 | # 获取当前接口的比特率 99 | CURRENT_BITRATE=$(ip -details link show "$INTERFACE_NAME" | grep -oP 'bitrate \K\d+') 100 | 101 | if [ "$IS_LINK_UP" == "yes" ] && [ "$CURRENT_BITRATE" -eq "$DEFAULT_BITRATE" ]; then 102 | echo "接口 $INTERFACE_NAME 已经激活,并且比特率为 $DEFAULT_BITRATE" 103 | 104 | # 检查接口名称是否与默认的名称匹配 105 | if [ "$INTERFACE_NAME" != "$DEFAULT_CAN_NAME" ]; then 106 | echo "将接口 $INTERFACE_NAME 重命名为 $DEFAULT_CAN_NAME" 107 | sudo ip link set "$INTERFACE_NAME" down 108 | sudo ip link set "$INTERFACE_NAME" name "$DEFAULT_CAN_NAME" 109 | sudo ip link set "$DEFAULT_CAN_NAME" up 110 | echo "接口已重命名为 $DEFAULT_CAN_NAME,并重新激活。" 111 | else 112 | echo "接口名称已经是 $DEFAULT_CAN_NAME" 113 | fi 114 | else 115 | # 如果接口未激活或比特率不同,进行设置 116 | if [ "$IS_LINK_UP" == "yes" ]; then 117 | echo "接口 $INTERFACE_NAME 已经激活,但比特率为 $CURRENT_BITRATE,与设定的 $DEFAULT_BITRATE 不符。" 118 | else 119 | echo "接口 $INTERFACE_NAME 未激活或未设置比特率。" 120 | fi 121 | 122 | # 设置接口比特率并激活 123 | sudo ip link set "$INTERFACE_NAME" down 124 | sudo ip link set "$INTERFACE_NAME" type can bitrate $DEFAULT_BITRATE 125 | sudo ip link set "$INTERFACE_NAME" up 126 | echo "接口 $INTERFACE_NAME 已重新设置为比特率 $DEFAULT_BITRATE 并激活。" 127 | 128 | # 重命名接口为默认名称 129 | if [ "$INTERFACE_NAME" != "$DEFAULT_CAN_NAME" ]; then 130 | echo "将接口 $INTERFACE_NAME 重命名为 $DEFAULT_CAN_NAME" 131 | sudo ip link set "$INTERFACE_NAME" down 132 | sudo ip link set "$INTERFACE_NAME" name "$DEFAULT_CAN_NAME" 133 | sudo ip link set "$DEFAULT_CAN_NAME" up 134 | echo "接口已重命名为 $DEFAULT_CAN_NAME,并重新激活。" 135 | fi 136 | fi 137 | 138 | echo "-------------------OVER------------------------" 139 | -------------------------------------------------------------------------------- /src/Piper_ros/can_config.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 使用说明: 4 | 5 | # 1.先决条件 6 | # 需要在系统中安装 ip 工具和 ethtool 工具。 7 | # sudo apt install ethtool can-utils 8 | # 确保 gs_usb 驱动已正确安装。 9 | 10 | # 2.背景 11 | # 本脚本旨在自动管理和重命名并激活 CAN(Controller Area Network)接口。 12 | # 它检查系统中当前的 CAN 模块数量,并根据预定义的 USB 端口重命名 CAN 接口并激活。 13 | # 这对于有多个 CAN 模块的系统,尤其是不同 CAN 模块需要特定名称的情况,非常有用。 14 | 15 | # 3.主要功能 16 | # 检查 CAN 模块数量:确保系统中检测到的 CAN 模块数量与预设的数量一致。 17 | # 获取 USB 端口信息:通过 ethtool 获取每个 CAN 模块的 USB 端口信息。 18 | # 验证 USB 端口:检查每个 CAN 模块的 USB 端口是否符合预定义的端口列表。 19 | # 重命名 CAN 接口:根据预定义的 USB 端口,将 CAN 接口重命名为目标名称。 20 | 21 | # 4.脚本配置说明 22 | # 脚本中的关键配置项包括预期的 CAN 模块数量、默认的 CAN 接口名称和波特率设置: 23 | # 1.预期的 CAN 模块数量: 24 | # EXPECTED_CAN_COUNT=1 25 | # 这个值决定了系统中应该检测到的 CAN 模块数量。 26 | # 2.单个can模块的时候默认的 CAN 接口名称: 27 | # DEFAULT_CAN_NAME="${1:-can0}" 28 | # 可以通过命令行参数指定默认的 CAN 接口名称,如果不提供参数,默认为 can0。 29 | # 3.单个 CAN 模块时的默认比特率: 30 | # DEFAULT_BITRATE="${2:-500000}" 31 | # 可以通过命令行参数指定单个 CAN 模块时的比特率,如果不提供参数,默认为 500000。 32 | # 4.多个 CAN 模块时的配置: 33 | # declare -A USB_PORTS 34 | # USB_PORTS["1-2:1.0"]="can_device_1:500000" 35 | # USB_PORTS["1-3:1.0"]="can_device_2:250000" 36 | # 这里的键表示 USB 端口,值是接口名称和比特率,使用冒号分隔。 37 | 38 | # 5.使用步骤 39 | # 1.编辑脚本: 40 | # 1. 修改预定义值: 41 | # - 预定义的 CAN 模块数量:EXPECTED_CAN_COUNT=2,可以修改为工控机上插入的can模块数量 42 | # - 如果只有一个can模块,设定完上面的参数可以直接跳过此处往后看 43 | # - (多个can模块)预定义的 USB 端口和目标接口名称: 44 | # 先将某个can模块插入到预期的usb口,注意在初次配置时,每次在工控机上插入一个can模块 45 | # 然后执行 sudo ethtool -i can0 | grep bus,并记录下 bus-info: 后面的参数 46 | # 接着插入下一个can模块,注意不可以与上次can模块插入的usb口相同,然后重复执行上一步 47 | # (其实可以用一个can模块去插不同的usb,因为区分模块是根据usb地址来区分的) 48 | # 所有模块都设计好所应该在的usb口并记录完成后, 49 | # 根据实际情况修改 USB 端口(bus-info)和目标接口名称。 50 | # can_device_1:500000,前者为设定的can名称,后者为设定的波特率 51 | # declare -A USB_PORTS 52 | # USB_PORTS["1-2:1.0"]="can_device_1:500000" 53 | # USB_PORTS["1-3:1.0"]="can_device_2:250000" 54 | # 需要修改的是USB_PORTS["1-3:1.0"]内双引号的内容,修改为上面记录的bus-info: 后面的参数 55 | # 2.赋予脚本执行权限: 56 | # 打开终端,导航到脚本所在目录,执行以下命令赋予脚本执行权限: 57 | # chmod +x can_config.sh 58 | # 3.运行脚本: 59 | # 使用 sudo 执行脚本,因为脚本需要管理员权限来修改网络接口: 60 | # 1.单个 CAN 模块 61 | # 1.可以通过命令行参数指定默认的 CAN 接口名称和比特率(默认为 can0 和 500000): 62 | # sudo bash ./can_config.sh [CAN接口名称] [比特率] 63 | # 例如,指定接口名称为 my_can_interface,比特率为 1000000: 64 | # sudo bash ./can_config.sh my_can_interface 1000000 65 | # 2.可以通过指定的usb硬件地址来指定can名称 66 | # sudo bash ./can_config.sh [CAN接口名称] [比特率] [usb硬件地址] 67 | # 例如,指定接口名称为 my_can_interface,比特率为 1000000,usb硬件地址为 1-3:1.0: 68 | # sudo bash ./can_config.sh my_can_interface 1000000 1-3:1.0 69 | # 也就是将 1-3:1.0 usb地址的can设备指定名称为my_can_interface,比特率为 1000000 70 | # 2.多个 CAN 模块 71 | # 对于多个 CAN 模块,通过在脚本中设置 USB_PORTS 数组来指定每个 CAN 模块的接口名称和比特率。 72 | # 无需额外参数,直接运行脚本: 73 | # sudo ./can_config.sh 74 | 75 | # 注意事项 76 | 77 | # 权限要求: 78 | # 脚本需要使用 sudo 权限,因为网络接口的重命名和设置需要管理员权限。 79 | # 确保你有足够的权限来运行该脚本。 80 | 81 | # 脚本环境: 82 | # 本脚本假设在 bash 环境下运行。确保你的系统使用 bash,而不是其他 Shell(如 sh)。 83 | # 可以通过检查脚本的 Shebang 行(#!/bin/bash)确保使用 bash。 84 | 85 | # USB 端口信息: 86 | # 确保你预定义的 USB 端口信息(bus-info)与实际系统中 ethtool 输出的信息一致。 87 | # 使用命令 sudo ethtool -i can0、sudo ethtool -i can1 等检查每个 CAN 接口的 bus-info。 88 | 89 | # 接口冲突: 90 | # 确保目标接口名称(如 can_device_1、can_device_2)是唯一的,不与系统中其他现有接口名称冲突。 91 | # 如果要修改 USB 端口和接口名称的对应关系,请根据实际情况调整 USB_PORTS 数组。 92 | #-------------------------------------------------------------------------------------------------# 93 | 94 | # 预定义的 CAN 模块数量 95 | EXPECTED_CAN_COUNT=2 96 | 97 | if [ "$EXPECTED_CAN_COUNT" -eq 1 ]; then 98 | # 默认的 CAN 名称,用户可以通过命令行参数设定 99 | DEFAULT_CAN_NAME="${1:-can0}" 100 | 101 | # 单个 CAN 模块时的默认比特率,用户可以通过命令行参数设定 102 | DEFAULT_BITRATE="${2:-1000000}" 103 | 104 | # USB 硬件地址(可选参数) 105 | USB_ADDRESS="${3}" 106 | fi 107 | 108 | # 预定义的 USB 端口、目标接口名称及其比特率(在多个 CAN 模块时使用) 109 | if [ "$EXPECTED_CAN_COUNT" -ne 1 ]; then 110 | declare -A USB_PORTS 111 | USB_PORTS["1-8:1.0"]="left_piper:1000000" 112 | USB_PORTS["1-4:1.0"]="right_piper:1000000" 113 | fi 114 | 115 | # 获取当前系统中的 CAN 模块数量 116 | CURRENT_CAN_COUNT=$(ip link show type can | grep -c "link/can") 117 | 118 | # 检查当前系统中的 CAN 模块数量是否符合预期 119 | if [ "$CURRENT_CAN_COUNT" -ne "$EXPECTED_CAN_COUNT" ]; then 120 | echo "错误: 检测到的 CAN 模块数量 ($CURRENT_CAN_COUNT) 与预期数量 ($EXPECTED_CAN_COUNT) 不符。" 121 | exit 1 122 | fi 123 | 124 | # 加载 gs_usb 模块 125 | sudo modprobe gs_usb 126 | if [ $? -ne 0 ]; then 127 | echo "错误: 无法加载 gs_usb 模块。" 128 | exit 1 129 | fi 130 | 131 | # 判断是否只需要处理一个 CAN 模块 132 | if [ "$EXPECTED_CAN_COUNT" -eq 1 ]; then 133 | if [ -n "$USB_ADDRESS" ]; then 134 | echo "检测到 USB 硬件地址参数: $USB_ADDRESS" 135 | 136 | # 使用 ethtool 查找与 USB 硬件地址对应的 CAN 接口 137 | INTERFACE_NAME="" 138 | for iface in $(ip -br link show type can | awk '{print $1}'); do 139 | BUS_INFO=$(sudo ethtool -i "$iface" | grep "bus-info" | awk '{print $2}') 140 | if [ "$BUS_INFO" == "$USB_ADDRESS" ]; then 141 | INTERFACE_NAME="$iface" 142 | break 143 | fi 144 | done 145 | 146 | if [ -z "$INTERFACE_NAME" ]; then 147 | echo "错误: 无法找到与 USB 硬件地址 $USB_ADDRESS 对应的 CAN 接口。" 148 | exit 1 149 | else 150 | echo "找到与 USB 硬件地址 $USB_ADDRESS 对应的接口: $INTERFACE_NAME" 151 | fi 152 | else 153 | # 获取唯一的 CAN 接口 154 | INTERFACE_NAME=$(ip -br link show type can | awk '{print $1}') 155 | 156 | # 检查是否获取到了接口名称 157 | if [ -z "$INTERFACE_NAME" ]; then 158 | echo "错误: 无法检测到 CAN 接口。" 159 | exit 1 160 | fi 161 | 162 | echo "预期只有一个 CAN 模块,检测到接口 $INTERFACE_NAME" 163 | fi 164 | 165 | # 检查当前接口是否已经激活 166 | IS_LINK_UP=$(ip link show "$INTERFACE_NAME" | grep -q "UP" && echo "yes" || echo "no") 167 | 168 | # 获取当前接口的比特率 169 | CURRENT_BITRATE=$(ip -details link show "$INTERFACE_NAME" | grep -oP 'bitrate \K\d+') 170 | 171 | if [ "$IS_LINK_UP" == "yes" ] && [ "$CURRENT_BITRATE" -eq "$DEFAULT_BITRATE" ]; then 172 | echo "接口 $INTERFACE_NAME 已经激活,并且比特率为 $DEFAULT_BITRATE" 173 | 174 | # 检查接口名称是否与默认的名称匹配 175 | if [ "$INTERFACE_NAME" != "$DEFAULT_CAN_NAME" ]; then 176 | echo "将接口 $INTERFACE_NAME 重命名为 $DEFAULT_CAN_NAME" 177 | sudo ip link set "$INTERFACE_NAME" down 178 | sudo ip link set "$INTERFACE_NAME" name "$DEFAULT_CAN_NAME" 179 | sudo ip link set "$DEFAULT_CAN_NAME" up 180 | echo "接口已重命名为 $DEFAULT_CAN_NAME,并重新激活。" 181 | else 182 | echo "接口名称已经是 $DEFAULT_CAN_NAME" 183 | fi 184 | else 185 | # 如果接口未激活或比特率不同,进行设置 186 | if [ "$IS_LINK_UP" == "yes" ]; then 187 | echo "接口 $INTERFACE_NAME 已经激活,但比特率为 $CURRENT_BITRATE,与设定的 $DEFAULT_BITRATE 不符。" 188 | else 189 | echo "接口 $INTERFACE_NAME 未激活或未设置比特率。" 190 | fi 191 | 192 | # 设置接口比特率并激活 193 | sudo ip link set "$INTERFACE_NAME" down 194 | sudo ip link set "$INTERFACE_NAME" type can bitrate $DEFAULT_BITRATE 195 | sudo ip link set "$INTERFACE_NAME" up 196 | echo "接口 $INTERFACE_NAME 已重新设置为比特率 $DEFAULT_BITRATE 并激活。" 197 | 198 | # 重命名接口为默认名称 199 | if [ "$INTERFACE_NAME" != "$DEFAULT_CAN_NAME" ]; then 200 | echo "将接口 $INTERFACE_NAME 重命名为 $DEFAULT_CAN_NAME" 201 | sudo ip link set "$INTERFACE_NAME" down 202 | sudo ip link set "$INTERFACE_NAME" name "$DEFAULT_CAN_NAME" 203 | sudo ip link set "$DEFAULT_CAN_NAME" up 204 | echo "接口已重命名为 $DEFAULT_CAN_NAME,并重新激活。" 205 | fi 206 | fi 207 | else 208 | # 处理多个 CAN 模块 209 | 210 | # 检查 USB 端口和目标接口名称的数量是否与预期 CAN 模块数量匹配 211 | PREDEFINED_COUNT=${#USB_PORTS[@]} 212 | if [ "$EXPECTED_CAN_COUNT" -ne "$PREDEFINED_COUNT" ]; then 213 | echo "错误: 预设的 CAN 模块数量 ($EXPECTED_CAN_COUNT) 与预定义的 USB 端口数量 ($PREDEFINED_COUNT) 不匹配。" 214 | exit 1 215 | fi 216 | 217 | # 遍历所有 CAN 接口 218 | for iface in $(ip -br link show type can | awk '{print $1}'); do 219 | # 使用 ethtool 获取 bus-info 220 | BUS_INFO=$(sudo ethtool -i "$iface" | grep "bus-info" | awk '{print $2}') 221 | 222 | if [ -z "$BUS_INFO" ];then 223 | echo "错误: 无法获取接口 $iface 的 bus-info 信息。" 224 | continue 225 | fi 226 | 227 | echo "接口 $iface 插入在 USB 端口 $BUS_INFO" 228 | 229 | # 检查 bus-info 是否在预定义的 USB 端口列表中 230 | if [ -n "${USB_PORTS[$BUS_INFO]}" ];then 231 | IFS=':' read -r TARGET_NAME TARGET_BITRATE <<< "${USB_PORTS[$BUS_INFO]}" 232 | 233 | # 检查当前接口是否已经激活 234 | IS_LINK_UP=$(ip link show "$iface" | grep -q "UP" && echo "yes" || echo "no") 235 | 236 | # 获取当前接口的比特率 237 | CURRENT_BITRATE=$(ip -details link show "$iface" | grep -oP 'bitrate \K\d+') 238 | 239 | if [ "$IS_LINK_UP" == "yes" ] && [ "$CURRENT_BITRATE" -eq "$TARGET_BITRATE" ]; then 240 | echo "接口 $iface 已经激活,并且比特率为 $TARGET_BITRATE" 241 | 242 | # 检查接口名称是否与目标名称匹配 243 | if [ "$iface" != "$TARGET_NAME" ]; then 244 | echo "将接口 $iface 重命名为 $TARGET_NAME" 245 | sudo ip link set "$iface" down 246 | sudo ip link set "$iface" name "$TARGET_NAME" 247 | sudo ip link set "$TARGET_NAME" up 248 | echo "接口已重命名为 $TARGET_NAME,并重新激活。" 249 | else 250 | echo "接口名称已经是 $TARGET_NAME" 251 | fi 252 | else 253 | # 如果接口未激活或比特率不同,进行设置 254 | if [ "$IS_LINK_UP" == "yes" ]; then 255 | echo "接口 $iface 已经激活,但比特率为 $CURRENT_BITRATE,与设定的 $TARGET_BITRATE 不符。" 256 | else 257 | echo "接口 $iface 未激活或未设置比特率。" 258 | fi 259 | 260 | # 设置接口比特率并激活 261 | sudo ip link set "$iface" down 262 | sudo ip link set "$iface" type can bitrate $TARGET_BITRATE 263 | sudo ip link set "$iface" up 264 | echo "接口 $iface 已重新设置为比特率 $TARGET_BITRATE 并激活。" 265 | 266 | # 重命名接口为目标名称 267 | if [ "$iface" != "$TARGET_NAME" ]; then 268 | echo "将接口 $iface 重命名为 $TARGET_NAME" 269 | sudo ip link set "$iface" down 270 | sudo ip link set "$iface" name "$TARGET_NAME" 271 | sudo ip link set "$TARGET_NAME" up 272 | echo "接口已重命名为 $TARGET_NAME,并重新激活。" 273 | fi 274 | fi 275 | else 276 | echo "错误: 未知的 USB 端口 $BUS_INFO 对应接口 $iface。" 277 | exit 1 278 | fi 279 | done 280 | fi 281 | 282 | echo "所有 CAN 接口已成功重命名并激活。" 283 | -------------------------------------------------------------------------------- /src/Piper_ros/find_all_can_port.sh: -------------------------------------------------------------------------------- 1 | # 检查 ethtool 是否已安装 2 | if ! dpkg -l | grep -q "ethtool"; then 3 | echo "\e[31m错误: 系统中未检测到 ethtool。\e[0m" 4 | echo "请使用以下命令安装 ethtool:" 5 | echo "sudo apt update && sudo apt install ethtool" 6 | exit 1 7 | fi 8 | 9 | # 检查 can-utils 是否已安装 10 | if ! dpkg -l | grep -q "can-utils"; then 11 | echo "\e[31m错误: 系统中未检测到 can-utils。\e[0m" 12 | echo "请使用以下命令安装 can-utils:" 13 | echo "sudo apt update && sudo apt install can-utils" 14 | exit 1 15 | fi 16 | 17 | echo "ethtool 和 can-utils 均已安装。" 18 | 19 | # 遍历所有 CAN 接口 20 | for iface in $(ip -br link show type can | awk '{print $1}'); do 21 | # 使用 ethtool 获取 bus-info 22 | BUS_INFO=$(sudo ethtool -i "$iface" | grep "bus-info" | awk '{print $2}') 23 | 24 | if [ -z "$BUS_INFO" ];then 25 | echo "错误: 无法获取接口 $iface 的 bus-info 信息。" 26 | continue 27 | fi 28 | 29 | echo "接口 $iface 插入在 USB 端口 $BUS_INFO" 30 | done -------------------------------------------------------------------------------- /src/Piper_ros/src/piper/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0.2) 2 | project(piper) 3 | 4 | ## Compile as C++11, supported in ROS Kinetic and newer 5 | # add_compile_options(-std=c++11) 6 | 7 | ## Find catkin macros and libraries 8 | ## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz) 9 | ## is used, also find other catkin packages 10 | find_package(catkin REQUIRED COMPONENTS 11 | actionlib 12 | actionlib_msgs 13 | control_msgs 14 | roscpp 15 | rospy 16 | sensor_msgs 17 | std_msgs 18 | trajectory_msgs 19 | message_generation 20 | geometry_msgs 21 | ) 22 | 23 | ## System dependencies are found with CMake's conventions 24 | # find_package(Boost REQUIRED COMPONENTS system) 25 | 26 | 27 | ## Uncomment this if the package has a setup.py. This macro ensures 28 | ## modules and global scripts declared therein get installed 29 | ## See http://ros.org/doc/api/catkin/html/user_guide/setup_dot_py.html 30 | # catkin_python_setup() 31 | 32 | ################################################ 33 | ## Declare ROS messages, services and actions ## 34 | ################################################ 35 | 36 | ## To declare and build messages, services or actions from within this 37 | ## package, follow these steps: 38 | ## * Let MSG_DEP_SET be the set of packages whose message types you use in 39 | ## your messages/services/actions (e.g. std_msgs, actionlib_msgs, ...). 40 | ## * In the file package.xml: 41 | ## * add a build_depend tag for "message_generation" 42 | ## * add a build_depend and a exec_depend tag for each package in MSG_DEP_SET 43 | ## * If MSG_DEP_SET isn't empty the following dependency has been pulled in 44 | ## but can be declared for certainty nonetheless: 45 | ## * add a exec_depend tag for "message_runtime" 46 | ## * In this file (CMakeLists.txt): 47 | ## * add "message_generation" and every package in MSG_DEP_SET to 48 | ## find_package(catkin REQUIRED COMPONENTS ...) 49 | ## * add "message_runtime" and every package in MSG_DEP_SET to 50 | ## catkin_package(CATKIN_DEPENDS ...) 51 | ## * uncomment the add_*_files sections below as needed 52 | ## and list every .msg/.srv/.action file to be processed 53 | ## * uncomment the generate_messages entry below 54 | ## * add every package in MSG_DEP_SET to generate_messages(DEPENDENCIES ...) 55 | 56 | ## Generate messages in the 'msg' folder 57 | # add_message_files( 58 | # FILES 59 | # Message1.msg 60 | # Message2.msg 61 | # ) 62 | 63 | ## Generate services in the 'srv' folder 64 | # add_service_files( 65 | # FILES 66 | # Service1.srv 67 | # Service2.srv 68 | # ) 69 | 70 | ## Generate actions in the 'action' folder 71 | # add_action_files( 72 | # FILES 73 | # Action1.action 74 | # Action2.action 75 | # ) 76 | 77 | # add_message_files( 78 | # FILES 79 | # AgxArmStatusMsg.msg 80 | # Joint.msg 81 | # PosCmd.msg 82 | # ) 83 | ## Generate added messages and services with any dependencies listed here 84 | # generate_messages( 85 | # DEPENDENCIES 86 | # actionlib_msgs# control_msgs# sensor_msgs# 87 | # std_msgs# trajectory_msgs 88 | # ) 89 | 90 | ################################################ 91 | ## Declare ROS dynamic reconfigure parameters ## 92 | ################################################ 93 | 94 | ## To declare and build dynamic reconfigure parameters within this 95 | ## package, follow these steps: 96 | ## * In the file package.xml: 97 | ## * add a build_depend and a exec_depend tag for "dynamic_reconfigure" 98 | ## * In this file (CMakeLists.txt): 99 | ## * add "dynamic_reconfigure" to 100 | ## find_package(catkin REQUIRED COMPONENTS ...) 101 | ## * uncomment the "generate_dynamic_reconfigure_options" section below 102 | ## and list every .cfg file to be processed 103 | 104 | ## Generate dynamic reconfigure parameters in the 'cfg' folder 105 | # generate_dynamic_reconfigure_options( 106 | # cfg/DynReconf1.cfg 107 | # cfg/DynReconf2.cfg 108 | # ) 109 | 110 | ################################### 111 | ## catkin specific configuration ## 112 | ################################### 113 | ## The catkin_package macro generates cmake config files for your package 114 | ## Declare things to be passed to dependent projects 115 | ## INCLUDE_DIRS: uncomment this if your package contains header files 116 | ## LIBRARIES: libraries you create in this project that dependent projects also need 117 | ## CATKIN_DEPENDS: catkin_packages dependent projects also need 118 | ## DEPENDS: system dependencies of this project that dependent projects also need 119 | catkin_package( 120 | # INCLUDE_DIRS include 121 | # LIBRARIES piper 122 | CATKIN_DEPENDS actionlib actionlib_msgs control_msgs roscpp rospy sensor_msgs std_msgs trajectory_msgs message_generation geometry_msgs 123 | # DEPENDS system_lib 124 | ) 125 | 126 | ########### 127 | ## Build ## 128 | ########### 129 | 130 | ## Specify additional locations of header files 131 | ## Your package locations should be listed before other locations 132 | include_directories( 133 | include 134 | ${catkin_INCLUDE_DIRS} 135 | ) 136 | 137 | ## Declare a C++ library 138 | # add_library(${PROJECT_NAME} 139 | # src/${PROJECT_NAME}/piper.cpp 140 | # ) 141 | 142 | ## Add cmake target dependencies of the library 143 | ## as an example, code may need to be generated before libraries 144 | ## either from message generation or dynamic reconfigure 145 | # add_dependencies(${PROJECT_NAME} ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS}) 146 | 147 | ## Declare a C++ executable 148 | ## With catkin_make all packages are built within a single CMake context 149 | ## The recommended prefix ensures that target names across packages don't collide 150 | # add_executable(${PROJECT_NAME}_node src/piper_node.cpp) 151 | 152 | ## Rename C++ executable without prefix 153 | ## The above recommended prefix causes long target names, the following renames the 154 | ## target back to the shorter version for ease of user use 155 | ## e.g. "rosrun someones_pkg node" instead of "rosrun someones_pkg someones_pkg_node" 156 | # set_target_properties(${PROJECT_NAME}_node PROPERTIES OUTPUT_NAME node PREFIX "") 157 | 158 | ## Add cmake target dependencies of the executable 159 | ## same as for the library above 160 | # add_dependencies(${PROJECT_NAME}_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS}) 161 | 162 | ## Specify libraries to link a library or executable target against 163 | # target_link_libraries(${PROJECT_NAME}_node 164 | # ${catkin_LIBRARIES} 165 | # ) 166 | 167 | ############# 168 | ## Install ## 169 | ############# 170 | 171 | # all install targets should use catkin DESTINATION variables 172 | # See http://ros.org/doc/api/catkin/html/adv_user_guide/variables.html 173 | 174 | ## Mark executable scripts (Python etc.) for installation 175 | ## in contrast to setup.py, you can choose the destination 176 | # catkin_install_python(PROGRAMS 177 | # scripts/my_python_script 178 | # DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} 179 | # ) 180 | 181 | ## Mark executables for installation 182 | ## See http://docs.ros.org/melodic/api/catkin/html/howto/format1/building_executables.html 183 | # install(TARGETS ${PROJECT_NAME}_node 184 | # RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} 185 | # ) 186 | 187 | ## Mark libraries for installation 188 | ## See http://docs.ros.org/melodic/api/catkin/html/howto/format1/building_libraries.html 189 | # install(TARGETS ${PROJECT_NAME} 190 | # ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} 191 | # LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} 192 | # RUNTIME DESTINATION ${CATKIN_GLOBAL_BIN_DESTINATION} 193 | # ) 194 | 195 | ## Mark cpp header files for installation 196 | # install(DIRECTORY include/${PROJECT_NAME}/ 197 | # DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION} 198 | # FILES_MATCHING PATTERN "*.h" 199 | # PATTERN ".svn" EXCLUDE 200 | # ) 201 | 202 | ## Mark other files for installation (e.g. launch and bag files, etc.) 203 | # install(FILES 204 | # # myfile1 205 | # # myfile2 206 | # DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION} 207 | # ) 208 | 209 | ############# 210 | ## Testing ## 211 | ############# 212 | 213 | ## Add gtest based cpp test target and link libraries 214 | # catkin_add_gtest(${PROJECT_NAME}-test test/test_piper.cpp) 215 | # if(TARGET ${PROJECT_NAME}-test) 216 | # target_link_libraries(${PROJECT_NAME}-test ${PROJECT_NAME}) 217 | # endif() 218 | 219 | ## Add folders to be run by python nosetests 220 | # catkin_add_nosetests(test) 221 | -------------------------------------------------------------------------------- /src/Piper_ros/src/piper/launch/start_double_piper.launch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/Piper_ros/src/piper/launch/start_single_piper.launch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/Piper_ros/src/piper/launch/start_single_piper_rviz.launch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/Piper_ros/src/piper/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | piper 4 | 0.0.0 5 | The piper package 6 | 7 | 8 | 9 | 10 | agilex 11 | 12 | 13 | 14 | 15 | 16 | TODO 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | catkin 52 | actionlib 53 | actionlib_msgs 54 | control_msgs 55 | roscpp 56 | rospy 57 | sensor_msgs 58 | std_msgs 59 | trajectory_msgs 60 | actionlib 61 | actionlib_msgs 62 | control_msgs 63 | roscpp 64 | rospy 65 | sensor_msgs 66 | std_msgs 67 | trajectory_msgs 68 | actionlib 69 | actionlib_msgs 70 | control_msgs 71 | roscpp 72 | rospy 73 | sensor_msgs 74 | std_msgs 75 | trajectory_msgs 76 | 77 | message_generation 78 | message_runtime 79 | 80 | message_generation 81 | message_runtime 82 | 83 | geometry_msgs 84 | geometry_msgs 85 | geometry_msgs 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /src/Piper_ros/src/piper/scripts/piper_control.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | import rospy 5 | from sensor_msgs.msg import JointState 6 | from piper_msgs.msg import PosCmd 7 | from std_msgs.msg import Header 8 | 9 | # float64 x 10 | # float64 y 11 | # float64 z 12 | # float64 roll 13 | # float64 pitch 14 | # float64 yaw 15 | # float64 gripper # 单位:米 范围:0 ~ 0.08米 16 | # int32 mode1 17 | # int32 mode2 18 | 19 | class PIPER: 20 | def __init__(self): 21 | 22 | # 发布控制piper机械臂话题 23 | self.pub_descartes = rospy.Publisher('pos_cmd', PosCmd, queue_size=10) 24 | self.pub_joint = rospy.Publisher('/joint_states', JointState, queue_size=10) 25 | self.left_pub_joint = rospy.Publisher('/left_joint_states', JointState, queue_size=100) 26 | self.right_pub_joint = rospy.Publisher('/right_joint_states', JointState, queue_size=100) 27 | self.descartes_msgs = PosCmd() 28 | 29 | # self.rate = rospy.Rate(80) # 10hz 30 | 31 | def init_pose(self): 32 | joint_states_msgs = JointState() 33 | joint_states_msgs.header = Header() 34 | joint_states_msgs.header.stamp = rospy.Time.now() 35 | joint_states_msgs.name = [f'joint{i+1}' for i in range(7)] 36 | joint_states_msgs.position = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] 37 | self.pub_joint.publish(joint_states_msgs) 38 | # self.rate.sleep() 39 | print("send joint control piper command") 40 | 41 | def left_init_pose(self): 42 | joint_states_msgs = JointState() 43 | joint_states_msgs.header = Header() 44 | joint_states_msgs.header.stamp = rospy.Time.now() 45 | joint_states_msgs.name = [f'joint{i+1}' for i in range(7)] 46 | joint_states_msgs.position = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] 47 | self.left_pub_joint.publish(joint_states_msgs) 48 | # self.rate.sleep() 49 | print("send joint control piper command") 50 | 51 | def right_init_pose(self): 52 | joint_states_msgs = JointState() 53 | joint_states_msgs.header = Header() 54 | joint_states_msgs.header.stamp = rospy.Time.now() 55 | joint_states_msgs.name = [f'joint{i+1}' for i in range(7)] 56 | joint_states_msgs.position = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] 57 | self.right_pub_joint.publish(joint_states_msgs) 58 | # self.rate.sleep() 59 | print("send joint control piper command") 60 | 61 | def descartes_control_piper(self,x,y,z,roll,pitch,yaw,gripper): 62 | self.descartes_msgs.x = x 63 | self.descartes_msgs.y = y 64 | self.descartes_msgs.z = z 65 | self.descartes_msgs.roll = roll 66 | self.descartes_msgs.pitch = pitch 67 | self.descartes_msgs.yaw = yaw 68 | self.descartes_msgs.gripper = gripper 69 | self.pub_descartes.publish(self.descartes_msgs) 70 | # print("send descartes control piper command") 71 | 72 | def joint_control_piper(self,j1,j2,j3,j4,j5,j6,gripper): 73 | joint_states_msgs = JointState() 74 | joint_states_msgs.header = Header() 75 | joint_states_msgs.header.stamp = rospy.Time.now() 76 | joint_states_msgs.name = [f'joint{i+1}' for i in range(7)] 77 | joint_states_msgs.position.append(j1) 78 | joint_states_msgs.position.append(j2) 79 | joint_states_msgs.position.append(j3) 80 | joint_states_msgs.position.append(j4) 81 | joint_states_msgs.position.append(j5) 82 | joint_states_msgs.position.append(j6) 83 | joint_states_msgs.position.append(gripper) 84 | self.pub_joint.publish(joint_states_msgs) 85 | # self.rate.sleep() 86 | print("send joint control piper command") 87 | 88 | def left_joint_control_piper(self,j1,j2,j3,j4,j5,j6,gripper): 89 | joint_states_msgs = JointState() 90 | joint_states_msgs.header = Header() 91 | joint_states_msgs.header.stamp = rospy.Time.now() 92 | joint_states_msgs.name = [f'joint{i+1}' for i in range(7)] 93 | joint_states_msgs.position.append(j1) 94 | joint_states_msgs.position.append(j2) 95 | joint_states_msgs.position.append(j3) 96 | joint_states_msgs.position.append(j4) 97 | joint_states_msgs.position.append(j5) 98 | joint_states_msgs.position.append(j6) 99 | joint_states_msgs.position.append(gripper) 100 | self.left_pub_joint.publish(joint_states_msgs) 101 | # self.rate.sleep() 102 | print("send joint control piper command") 103 | 104 | 105 | def right_joint_control_piper(self,j1,j2,j3,j4,j5,j6,gripper): 106 | joint_states_msgs = JointState() 107 | joint_states_msgs.header = Header() 108 | joint_states_msgs.header.stamp = rospy.Time.now() 109 | joint_states_msgs.name = [f'joint{i+1}' for i in range(7)] 110 | joint_states_msgs.position.append(j1) 111 | joint_states_msgs.position.append(j2) 112 | joint_states_msgs.position.append(j3) 113 | joint_states_msgs.position.append(j4) 114 | joint_states_msgs.position.append(j5) 115 | joint_states_msgs.position.append(j6) 116 | joint_states_msgs.position.append(gripper) 117 | self.right_pub_joint.publish(joint_states_msgs) 118 | # self.rate.sleep() 119 | print("send joint control piper command") 120 | 121 | 122 | 123 | # test code 124 | if __name__ == '__main__': 125 | # piper = PIPER() 126 | rospy.init_node('control_piper_node', anonymous=True) 127 | # piper.control_piper(0.0,0.0,0.0,0.0,0.0,0.0,0.05) 128 | # 保持节点运行并监听外部程序的调用 129 | rospy.spin() 130 | -------------------------------------------------------------------------------- /src/Piper_ros/src/piper/scripts/piper_pinocchio.py: -------------------------------------------------------------------------------- 1 | import casadi 2 | import meshcat.geometry as mg 3 | import numpy as np 4 | import pinocchio as pin 5 | import time 6 | 7 | import rospy 8 | from pinocchio import casadi as cpin 9 | from pinocchio.robot_wrapper import RobotWrapper 10 | from pinocchio.visualize import MeshcatVisualizer 11 | from tf.transformations import quaternion_from_euler, euler_from_quaternion 12 | import os 13 | import sys 14 | import cv2 15 | import threading 16 | from piper_control import PIPER 17 | from piper_msgs.msg import PosCmd 18 | 19 | piper_control = PIPER() 20 | 21 | current_dir = os.path.dirname(os.path.abspath(__file__)) 22 | parent_dir = os.path.dirname(current_dir) 23 | sys.path.append(parent_dir) 24 | 25 | 26 | class Arm_IK: 27 | def __init__(self): 28 | np.set_printoptions(precision=5, suppress=True, linewidth=200) 29 | 30 | urdf_path = '/home/agilex/piper_ws/src/piper_description/urdf/piper_description.urdf' 31 | 32 | self.robot = pin.RobotWrapper.BuildFromURDF(urdf_path) 33 | 34 | self.mixed_jointsToLockIDs = ["joint7", 35 | "joint8" 36 | ] 37 | 38 | self.reduced_robot = self.robot.buildReducedRobot( 39 | list_of_joints_to_lock=self.mixed_jointsToLockIDs, 40 | reference_configuration=np.array([0] * self.robot.model.nq), 41 | ) 42 | 43 | q = quaternion_from_euler(0, -1.57, -1.57) 44 | self.reduced_robot.model.addFrame( 45 | pin.Frame('ee', 46 | self.reduced_robot.model.getJointId('joint6'), 47 | pin.SE3( 48 | # pin.Quaternion(1, 0, 0, 0), 49 | pin.Quaternion(q[3], q[0], q[1], q[2]), 50 | np.array([0.0, 0.0, 0.0]), 51 | ), 52 | pin.FrameType.OP_FRAME) 53 | ) 54 | 55 | self.geom_model = pin.buildGeomFromUrdf(self.robot.model, urdf_path, pin.GeometryType.COLLISION) 56 | for i in range(4, 9): 57 | for j in range(0, 3): 58 | self.geom_model.addCollisionPair(pin.CollisionPair(i, j)) 59 | self.geometry_data = pin.GeometryData(self.geom_model) 60 | 61 | self.init_data = np.zeros(self.reduced_robot.model.nq) 62 | self.history_data = np.zeros(self.reduced_robot.model.nq) 63 | 64 | # # Initialize the Meshcat visualizer for visualization 65 | self.vis = MeshcatVisualizer(self.reduced_robot.model, self.reduced_robot.collision_model, self.reduced_robot.visual_model) 66 | self.vis.initViewer(open=True) 67 | self.vis.loadViewerModel("pinocchio") 68 | self.vis.displayFrames(True, frame_ids=[113, 114], axis_length=0.15, axis_width=5) 69 | self.vis.display(pin.neutral(self.reduced_robot.model)) 70 | 71 | # Enable the display of end effector target frames with short axis lengths and greater width. 72 | frame_viz_names = ['ee_target'] 73 | FRAME_AXIS_POSITIONS = ( 74 | np.array([[0, 0, 0], [1, 0, 0], 75 | [0, 0, 0], [0, 1, 0], 76 | [0, 0, 0], [0, 0, 1]]).astype(np.float32).T 77 | ) 78 | FRAME_AXIS_COLORS = ( 79 | np.array([[1, 0, 0], [1, 0.6, 0], 80 | [0, 1, 0], [0.6, 1, 0], 81 | [0, 0, 1], [0, 0.6, 1]]).astype(np.float32).T 82 | ) 83 | axis_length = 0.1 84 | axis_width = 10 85 | for frame_viz_name in frame_viz_names: 86 | self.vis.viewer[frame_viz_name].set_object( 87 | mg.LineSegments( 88 | mg.PointsGeometry( 89 | position=axis_length * FRAME_AXIS_POSITIONS, 90 | color=FRAME_AXIS_COLORS, 91 | ), 92 | mg.LineBasicMaterial( 93 | linewidth=axis_width, 94 | vertexColors=True, 95 | ), 96 | ) 97 | ) 98 | 99 | # Creating Casadi models and data for symbolic computing 100 | self.cmodel = cpin.Model(self.reduced_robot.model) 101 | self.cdata = self.cmodel.createData() 102 | 103 | # Creating symbolic variables 104 | self.cq = casadi.SX.sym("q", self.reduced_robot.model.nq, 1) 105 | self.cTf = casadi.SX.sym("tf", 4, 4) 106 | cpin.framesForwardKinematics(self.cmodel, self.cdata, self.cq) 107 | 108 | # # Get the hand joint ID and define the error function 109 | self.gripper_id = self.reduced_robot.model.getFrameId("ee") 110 | self.error = casadi.Function( 111 | "error", 112 | [self.cq, self.cTf], 113 | [ 114 | casadi.vertcat( 115 | cpin.log6( 116 | self.cdata.oMf[self.gripper_id].inverse() * cpin.SE3(self.cTf) 117 | ).vector, 118 | ) 119 | ], 120 | ) 121 | 122 | # Defining the optimization problem 123 | self.opti = casadi.Opti() 124 | self.var_q = self.opti.variable(self.reduced_robot.model.nq) 125 | # self.var_q_last = self.opti.parameter(self.reduced_robot.model.nq) # for smooth 126 | self.param_tf = self.opti.parameter(4, 4) 127 | self.totalcost = casadi.sumsqr(self.error(self.var_q, self.param_tf)) 128 | self.regularization = casadi.sumsqr(self.var_q) 129 | # self.smooth_cost = casadi.sumsqr(self.var_q - self.var_q_last) # for smooth 130 | 131 | # Setting optimization constraints and goals 132 | self.opti.subject_to(self.opti.bounded( 133 | self.reduced_robot.model.lowerPositionLimit, 134 | self.var_q, 135 | self.reduced_robot.model.upperPositionLimit) 136 | ) 137 | # print("self.reduced_robot.model.lowerPositionLimit:", self.reduced_robot.model.lowerPositionLimit) 138 | # print("self.reduced_robot.model.upperPositionLimit:", self.reduced_robot.model.upperPositionLimit) 139 | self.opti.minimize(20 * self.totalcost + 0.01 * self.regularization) 140 | # self.opti.minimize(20 * self.totalcost + 0.01 * self.regularization + 0.1 * self.smooth_cost) # for smooth 141 | 142 | opts = { 143 | 'ipopt': { 144 | 'print_level': 0, 145 | 'max_iter': 50, 146 | 'tol': 1e-4 147 | }, 148 | 'print_time': False 149 | } 150 | self.opti.solver("ipopt", opts) 151 | 152 | def ik_fun(self, target_pose, gripper=0, motorstate=None, motorV=None): 153 | gripper = np.array([gripper/2.0, -gripper/2.0]) 154 | if motorstate is not None: 155 | self.init_data = motorstate 156 | self.opti.set_initial(self.var_q, self.init_data) 157 | 158 | self.vis.viewer['ee_target'].set_transform(target_pose) # for visualization 159 | 160 | self.opti.set_value(self.param_tf, target_pose) 161 | # self.opti.set_value(self.var_q_last, self.init_data) # for smooth 162 | 163 | try: 164 | # sol = self.opti.solve() 165 | sol = self.opti.solve_limited() 166 | sol_q = self.opti.value(self.var_q) 167 | 168 | if self.init_data is not None: 169 | max_diff = max(abs(self.history_data - sol_q)) 170 | # print("max_diff:", max_diff) 171 | self.init_data = sol_q 172 | if max_diff > 30.0/180.0*3.1415: 173 | # print("Excessive changes in joint angle:", max_diff) 174 | self.init_data = np.zeros(self.reduced_robot.model.nq) 175 | else: 176 | self.init_data = sol_q 177 | self.history_data = sol_q 178 | 179 | self.vis.display(sol_q) # for visualization 180 | 181 | if motorV is not None: 182 | v = motorV * 0.0 183 | else: 184 | v = (sol_q - self.init_data) * 0.0 185 | 186 | tau_ff = pin.rnea(self.reduced_robot.model, self.reduced_robot.data, sol_q, v, 187 | np.zeros(self.reduced_robot.model.nv)) 188 | 189 | is_collision = self.check_self_collision(sol_q, gripper) 190 | 191 | return sol_q, tau_ff, not is_collision 192 | 193 | except Exception as e: 194 | print(f"ERROR in convergence, plotting debug info.{e}") 195 | # sol_q = self.opti.debug.value(self.var_q) # return original value 196 | return sol_q, '', False 197 | 198 | def check_self_collision(self, q, gripper=np.array([0, 0])): 199 | pin.forwardKinematics(self.robot.model, self.robot.data, np.concatenate([q, gripper], axis=0)) 200 | pin.updateGeometryPlacements(self.robot.model, self.robot.data, self.geom_model, self.geometry_data) 201 | collision = pin.computeCollisions(self.geom_model, self.geometry_data, False) 202 | # print("collision:", collision) 203 | return collision 204 | 205 | def get_ik_solution(self, x,y,z,roll,pitch,yaw): 206 | 207 | q = quaternion_from_euler(roll, pitch, yaw) 208 | target = pin.SE3( 209 | pin.Quaternion(q[3], q[0], q[1], q[2]), 210 | np.array([x, y, z]), 211 | ) 212 | sol_q, tau_ff, get_result = self.ik_fun(target.homogeneous,0) 213 | # print("result:", sol_q) 214 | 215 | if get_result : 216 | piper_control.joint_control_piper(sol_q[0],sol_q[1],sol_q[2],sol_q[3],sol_q[4],sol_q[5],0) 217 | else : 218 | print("collision!!!") 219 | 220 | class C_PiperIK(): 221 | def __init__(self): 222 | rospy.init_node('inverse_solution_node', anonymous=True) 223 | # 创建Arm_IK实例 224 | self.arm_ik = Arm_IK() 225 | 226 | # 启动订阅线程 227 | sub_pos_th = threading.Thread(target=self.SubPosThread) 228 | sub_pos_th.daemon = True 229 | sub_pos_th.start() 230 | 231 | def SubPosThread(self): 232 | # 创建订阅者,监听PosCmd类型的消息 233 | rospy.Subscriber('pin_pos_cmd', PosCmd, self.pos_cmd_callback) 234 | rospy.spin() 235 | 236 | def pos_cmd_callback(self, msg): 237 | # 获取PosCmd类型消息中的数据 238 | x = msg.x 239 | y = msg.y 240 | z = msg.z 241 | roll = msg.roll 242 | pitch = msg.pitch 243 | yaw = msg.yaw 244 | 245 | # 调用Arm_IK类的逆解函数 246 | self.arm_ik.get_ik_solution(x, y, z, roll, pitch, yaw) 247 | 248 | if __name__ == "__main__": 249 | piper_ik = C_PiperIK() 250 | while True: 251 | pass 252 | 253 | 254 | -------------------------------------------------------------------------------- /src/Piper_ros/src/piper_description/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8.3) 2 | 3 | project(piper_description) 4 | 5 | find_package(catkin REQUIRED) 6 | 7 | catkin_package() 8 | 9 | find_package(roslaunch) 10 | 11 | foreach(dir config launch meshes urdf) 12 | install(DIRECTORY ${dir}/ 13 | DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}/${dir}) 14 | endforeach(dir) 15 | -------------------------------------------------------------------------------- /src/Piper_ros/src/piper_description/config/joint_names_agx_arm_description.yaml: -------------------------------------------------------------------------------- 1 | controller_joint_names: ['', 'joint1', 'joint2', 'joint3', 'joint4', 'joint5', 'joint6', 'joint7', 'joint8', ] 2 | -------------------------------------------------------------------------------- /src/Piper_ros/src/piper_description/config/piper_gazebo_control.yaml: -------------------------------------------------------------------------------- 1 | piper_description: 2 | joint_state_controller: 3 | type: joint_state_controller/JointStateController 4 | publish_rate: 200 5 | 6 | joint1_position_controller: 7 | type: position_controllers/JointPositionController 8 | joint: joint1 9 | pid: {p: 100.0, i: 0.01, d: 5.0} 10 | joint2_position_controller: 11 | type: position_controllers/JointPositionController 12 | joint: joint2 13 | pid: {p: 100.0, i: 0.01, d: 5.0} 14 | joint3_position_controller: 15 | type: position_controllers/JointPositionController 16 | joint: joint3 17 | pid: {p: 100.0, i: 0.01, d: 5.0} 18 | joint4_position_controller: 19 | type: position_controllers/JointPositionController 20 | joint: joint4 21 | pid: {p: 100.0, i: 0.01, d: 5.0} 22 | joint5_position_controller: 23 | type: position_controllers/JointPositionController 24 | joint: joint5 25 | pid: {p: 100.0, i: 0.01, d: 5.0} 26 | joint6_position_controller: 27 | type: position_controllers/JointPositionController 28 | joint: joint6 29 | pid: {p: 100.0, i: 0.01, d: 5.0} 30 | joint7_position_controller: 31 | type: position_controllers/JointPositionController 32 | joint: joint7 33 | pid: {p: 100, i: 0.001, d: 10.0} 34 | joint8_position_controller: 35 | type: position_controllers/JointPositionController 36 | joint: joint8 37 | pid: {p: 100, i: 0.001, d: 10.0} 38 | # gazebo_ros_control: 39 | # pid_gains: 40 | # joint1: 41 | # p: 0 42 | # i: 0 43 | # d: 0 44 | # joint2: 45 | # p: 0 46 | # i: 0 47 | # d: 0 48 | # joint3: 49 | # p: 0 50 | # i: 0 51 | # d: 0 52 | # joint4: 53 | # p: 0 54 | # i: 0 55 | # d: 0 56 | # joint5: 57 | # p: 0 58 | # i: 0 59 | # d: 0 60 | # joint6: 61 | # p: 0 62 | # i: 0 63 | # d: 0 64 | # joint7: 65 | # p: 0 66 | # i: 0.001 67 | # d: 0 68 | # joint8: 69 | # p: 0 70 | # i: 0.001 71 | # d: 0 -------------------------------------------------------------------------------- /src/Piper_ros/src/piper_description/config/piper_no_gripper_gazebo_control.yaml: -------------------------------------------------------------------------------- 1 | piper_description: 2 | joint_state_controller: 3 | type: joint_state_controller/JointStateController 4 | publish_rate: 200 5 | 6 | joint1_position_controller: 7 | type: position_controllers/JointPositionController 8 | joint: joint1 9 | pid: {p: 100.0, i: 0.01, d: 5.0} 10 | joint2_position_controller: 11 | type: position_controllers/JointPositionController 12 | joint: joint2 13 | pid: {p: 100.0, i: 0.01, d: 5.0} 14 | joint3_position_controller: 15 | type: position_controllers/JointPositionController 16 | joint: joint3 17 | pid: {p: 100.0, i: 0.01, d: 5.0} 18 | joint4_position_controller: 19 | type: position_controllers/JointPositionController 20 | joint: joint4 21 | pid: {p: 100.0, i: 0.01, d: 5.0} 22 | joint5_position_controller: 23 | type: position_controllers/JointPositionController 24 | joint: joint5 25 | pid: {p: 100.0, i: 0.01, d: 5.0} 26 | joint6_position_controller: 27 | type: position_controllers/JointPositionController 28 | joint: joint6 29 | pid: {p: 100.0, i: 0.01, d: 5.0} 30 | -------------------------------------------------------------------------------- /src/Piper_ros/src/piper_description/launch/piper_no_gripper/display_no_gripper_urdf.launch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 11 | 15 | 20 | -------------------------------------------------------------------------------- /src/Piper_ros/src/piper_description/launch/piper_no_gripper/display_no_gripper_xacro.launch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 11 | 15 | 20 | -------------------------------------------------------------------------------- /src/Piper_ros/src/piper_description/launch/piper_no_gripper/gazebo_no_gripper_xacro.launch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/Piper_ros/src/piper_description/launch/piper_no_gripper/piper_no_gripper_gazebo_controller.launch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 15 | 16 | 17 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/Piper_ros/src/piper_description/launch/piper_no_gripper/piper_no_gripper_world.launch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/Piper_ros/src/piper_description/launch/piper_with_gripper/display_urdf.launch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 12 | 13 | 17 | 21 | 26 | -------------------------------------------------------------------------------- /src/Piper_ros/src/piper_description/launch/piper_with_gripper/display_xacro.launch: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 8 | 12 | 13 | 14 | 18 | 19 | 20 | 25 | -------------------------------------------------------------------------------- /src/Piper_ros/src/piper_description/launch/piper_with_gripper/gazebo_xacro.launch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/Piper_ros/src/piper_description/launch/piper_with_gripper/piper_gazebo_controller.launch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 17 | 18 | 19 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/Piper_ros/src/piper_description/launch/piper_with_gripper/piper_world.launch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/Piper_ros/src/piper_description/launch/piper_with_gripper/rviz_ctrl_gazebo.launch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/Piper_ros/src/piper_description/meshes/base_link.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agilexrobotics/questVR_ws/b7a97d3eaa3adfba08af0ecf132dbb88eab4e5b9/src/Piper_ros/src/piper_description/meshes/base_link.STL -------------------------------------------------------------------------------- /src/Piper_ros/src/piper_description/meshes/gripper_base.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agilexrobotics/questVR_ws/b7a97d3eaa3adfba08af0ecf132dbb88eab4e5b9/src/Piper_ros/src/piper_description/meshes/gripper_base.STL -------------------------------------------------------------------------------- /src/Piper_ros/src/piper_description/meshes/link1.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agilexrobotics/questVR_ws/b7a97d3eaa3adfba08af0ecf132dbb88eab4e5b9/src/Piper_ros/src/piper_description/meshes/link1.STL -------------------------------------------------------------------------------- /src/Piper_ros/src/piper_description/meshes/link2.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agilexrobotics/questVR_ws/b7a97d3eaa3adfba08af0ecf132dbb88eab4e5b9/src/Piper_ros/src/piper_description/meshes/link2.STL -------------------------------------------------------------------------------- /src/Piper_ros/src/piper_description/meshes/link3.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agilexrobotics/questVR_ws/b7a97d3eaa3adfba08af0ecf132dbb88eab4e5b9/src/Piper_ros/src/piper_description/meshes/link3.STL -------------------------------------------------------------------------------- /src/Piper_ros/src/piper_description/meshes/link4.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agilexrobotics/questVR_ws/b7a97d3eaa3adfba08af0ecf132dbb88eab4e5b9/src/Piper_ros/src/piper_description/meshes/link4.STL -------------------------------------------------------------------------------- /src/Piper_ros/src/piper_description/meshes/link5.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agilexrobotics/questVR_ws/b7a97d3eaa3adfba08af0ecf132dbb88eab4e5b9/src/Piper_ros/src/piper_description/meshes/link5.STL -------------------------------------------------------------------------------- /src/Piper_ros/src/piper_description/meshes/link6.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agilexrobotics/questVR_ws/b7a97d3eaa3adfba08af0ecf132dbb88eab4e5b9/src/Piper_ros/src/piper_description/meshes/link6.STL -------------------------------------------------------------------------------- /src/Piper_ros/src/piper_description/meshes/link7.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agilexrobotics/questVR_ws/b7a97d3eaa3adfba08af0ecf132dbb88eab4e5b9/src/Piper_ros/src/piper_description/meshes/link7.STL -------------------------------------------------------------------------------- /src/Piper_ros/src/piper_description/meshes/link8.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agilexrobotics/questVR_ws/b7a97d3eaa3adfba08af0ecf132dbb88eab4e5b9/src/Piper_ros/src/piper_description/meshes/link8.STL -------------------------------------------------------------------------------- /src/Piper_ros/src/piper_description/package.xml: -------------------------------------------------------------------------------- 1 | 2 | piper_description 3 | 1.0.0 4 | 5 |

URDF Description package for piper_description

6 |

This package contains configuration data, 3D models and launch files 7 | for piper_description robot

8 |
9 | TODO 10 | 11 | BSD 12 | catkin 13 | roslaunch 14 | robot_state_publisher 15 | rviz 16 | joint_state_publisher_gui 17 | gazebo 18 | 19 | 20 | 21 |
-------------------------------------------------------------------------------- /src/Piper_ros/src/piper_description/rviz/piper_ctrl.rviz: -------------------------------------------------------------------------------- 1 | Panels: 2 | - Class: rviz/Displays 3 | Help Height: 78 4 | Name: Displays 5 | Property Tree Widget: 6 | Expanded: 7 | - /Global Options1 8 | - /Status1 9 | Splitter Ratio: 0.5 10 | Tree Height: 549 11 | - Class: rviz/Selection 12 | Name: Selection 13 | - Class: rviz/Tool Properties 14 | Expanded: 15 | - /2D Pose Estimate1 16 | - /2D Nav Goal1 17 | - /Publish Point1 18 | Name: Tool Properties 19 | Splitter Ratio: 0.5886790156364441 20 | - Class: rviz/Views 21 | Expanded: 22 | - /Current View1 23 | Name: Views 24 | Splitter Ratio: 0.5 25 | - Class: rviz/Time 26 | Name: Time 27 | SyncMode: 0 28 | SyncSource: "" 29 | Preferences: 30 | PromptSaveOnExit: true 31 | Toolbars: 32 | toolButtonStyle: 2 33 | Visualization Manager: 34 | Class: "" 35 | Displays: 36 | - Alpha: 0.5 37 | Cell Size: 1 38 | Class: rviz/Grid 39 | Color: 160; 160; 164 40 | Enabled: true 41 | Line Style: 42 | Line Width: 0.029999999329447746 43 | Value: Lines 44 | Name: Grid 45 | Normal Cell Count: 0 46 | Offset: 47 | X: 0 48 | Y: 0 49 | Z: 0 50 | Plane: XY 51 | Plane Cell Count: 10 52 | Reference Frame: 53 | Value: true 54 | - Alpha: 1 55 | Class: rviz/RobotModel 56 | Collision Enabled: false 57 | Enabled: true 58 | Links: 59 | All Links Enabled: true 60 | Expand Joint Details: false 61 | Expand Link Details: false 62 | Expand Tree: false 63 | Link Tree Style: Links in Alphabetic Order 64 | base_link: 65 | Alpha: 1 66 | Show Axes: false 67 | Show Trail: false 68 | Value: true 69 | link1: 70 | Alpha: 1 71 | Show Axes: false 72 | Show Trail: false 73 | Value: true 74 | link2: 75 | Alpha: 1 76 | Show Axes: false 77 | Show Trail: false 78 | Value: true 79 | link3: 80 | Alpha: 1 81 | Show Axes: false 82 | Show Trail: false 83 | Value: true 84 | link4: 85 | Alpha: 1 86 | Show Axes: false 87 | Show Trail: false 88 | Value: true 89 | link5: 90 | Alpha: 1 91 | Show Axes: false 92 | Show Trail: false 93 | Value: true 94 | link6: 95 | Alpha: 1 96 | Show Axes: false 97 | Show Trail: false 98 | Value: true 99 | link7: 100 | Alpha: 1 101 | Show Axes: false 102 | Show Trail: false 103 | Value: true 104 | link8: 105 | Alpha: 1 106 | Show Axes: false 107 | Show Trail: false 108 | Value: true 109 | world: 110 | Alpha: 1 111 | Show Axes: false 112 | Show Trail: false 113 | Name: RobotModel 114 | Robot Description: robot_description 115 | TF Prefix: "" 116 | Update Interval: 0 117 | Value: true 118 | Visual Enabled: true 119 | Enabled: true 120 | Global Options: 121 | Background Color: 48; 48; 48 122 | Default Light: true 123 | Fixed Frame: base_link 124 | Frame Rate: 30 125 | Name: root 126 | Tools: 127 | - Class: rviz/Interact 128 | Hide Inactive Objects: true 129 | - Class: rviz/MoveCamera 130 | - Class: rviz/Select 131 | - Class: rviz/FocusCamera 132 | - Class: rviz/Measure 133 | - Class: rviz/SetInitialPose 134 | Theta std deviation: 0.2617993950843811 135 | Topic: /initialpose 136 | X std deviation: 0.5 137 | Y std deviation: 0.5 138 | - Class: rviz/SetGoal 139 | Topic: /move_base_simple/goal 140 | - Class: rviz/PublishPoint 141 | Single click: true 142 | Topic: /clicked_point 143 | Value: true 144 | Views: 145 | Current: 146 | Class: rviz/Orbit 147 | Distance: 1.985201120376587 148 | Enable Stereo Rendering: 149 | Stereo Eye Separation: 0.05999999865889549 150 | Stereo Focal Distance: 1 151 | Swap Stereo Eyes: false 152 | Value: false 153 | Field of View: 0.7853981852531433 154 | Focal Point: 155 | X: 0 156 | Y: 0 157 | Z: 0 158 | Focal Shape Fixed Size: true 159 | Focal Shape Size: 0.05000000074505806 160 | Invert Z Axis: false 161 | Name: Current View 162 | Near Clip Distance: 0.009999999776482582 163 | Pitch: 0.785398006439209 164 | Target Frame: 165 | Yaw: 0.785398006439209 166 | Saved: ~ 167 | Window Geometry: 168 | Displays: 169 | collapsed: false 170 | Height: 846 171 | Hide Left Dock: false 172 | Hide Right Dock: false 173 | QMainWindow State: 000000ff00000000fd000000040000000000000156000002b0fc0200000008fb0000001200530065006c0065006300740069006f006e00000001e10000009b0000005c00fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000185000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb000000100044006900730070006c006100790073010000003d000002b0000000c900fffffffb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c00000261000000010000010f000002b0fc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a00560069006500770073010000003d000002b0000000a400fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000490000000a9fc0100000001fb0000000a00560069006500770073030000004e00000080000002e10000019700000003000004b00000003efc0100000002fb0000000800540069006d00650100000000000004b0000003bc00fffffffb0000000800540069006d006501000000000000045000000000000000000000023f000002b000000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000 174 | Selection: 175 | collapsed: false 176 | Time: 177 | collapsed: false 178 | Tool Properties: 179 | collapsed: false 180 | Views: 181 | collapsed: false 182 | Width: 1200 183 | X: 72 184 | Y: 27 185 | -------------------------------------------------------------------------------- /src/Piper_ros/src/piper_description/rviz/piper_no_gripper.rviz: -------------------------------------------------------------------------------- 1 | Panels: 2 | - Class: rviz/Displays 3 | Help Height: 78 4 | Name: Displays 5 | Property Tree Widget: 6 | Expanded: 7 | - /Global Options1 8 | - /Status1 9 | Splitter Ratio: 0.5 10 | Tree Height: 549 11 | - Class: rviz/Selection 12 | Name: Selection 13 | - Class: rviz/Tool Properties 14 | Expanded: 15 | - /2D Pose Estimate1 16 | - /2D Nav Goal1 17 | - /Publish Point1 18 | Name: Tool Properties 19 | Splitter Ratio: 0.5886790156364441 20 | - Class: rviz/Views 21 | Expanded: 22 | - /Current View1 23 | Name: Views 24 | Splitter Ratio: 0.5 25 | - Class: rviz/Time 26 | Name: Time 27 | SyncMode: 0 28 | SyncSource: "" 29 | Preferences: 30 | PromptSaveOnExit: true 31 | Toolbars: 32 | toolButtonStyle: 2 33 | Visualization Manager: 34 | Class: "" 35 | Displays: 36 | - Alpha: 0.5 37 | Cell Size: 1 38 | Class: rviz/Grid 39 | Color: 160; 160; 164 40 | Enabled: true 41 | Line Style: 42 | Line Width: 0.029999999329447746 43 | Value: Lines 44 | Name: Grid 45 | Normal Cell Count: 0 46 | Offset: 47 | X: 0 48 | Y: 0 49 | Z: 0 50 | Plane: XY 51 | Plane Cell Count: 10 52 | Reference Frame: 53 | Value: true 54 | - Alpha: 1 55 | Class: rviz/RobotModel 56 | Collision Enabled: false 57 | Enabled: true 58 | Links: 59 | All Links Enabled: true 60 | Expand Joint Details: false 61 | Expand Link Details: false 62 | Expand Tree: false 63 | Link Tree Style: Links in Alphabetic Order 64 | base_link: 65 | Alpha: 1 66 | Show Axes: false 67 | Show Trail: false 68 | Value: true 69 | link1: 70 | Alpha: 1 71 | Show Axes: false 72 | Show Trail: false 73 | Value: true 74 | link2: 75 | Alpha: 1 76 | Show Axes: false 77 | Show Trail: false 78 | Value: true 79 | link3: 80 | Alpha: 1 81 | Show Axes: false 82 | Show Trail: false 83 | Value: true 84 | link4: 85 | Alpha: 1 86 | Show Axes: false 87 | Show Trail: false 88 | Value: true 89 | link5: 90 | Alpha: 1 91 | Show Axes: false 92 | Show Trail: false 93 | Value: true 94 | world: 95 | Alpha: 1 96 | Show Axes: false 97 | Show Trail: false 98 | Name: RobotModel 99 | Robot Description: robot_description 100 | TF Prefix: "" 101 | Update Interval: 0 102 | Value: true 103 | Visual Enabled: true 104 | - Class: rviz/TF 105 | Enabled: false 106 | Filter (blacklist): "" 107 | Filter (whitelist): "" 108 | Frame Timeout: 15 109 | Frames: 110 | All Enabled: true 111 | Marker Alpha: 1 112 | Marker Scale: 1 113 | Name: TF 114 | Show Arrows: true 115 | Show Axes: true 116 | Show Names: true 117 | Tree: 118 | {} 119 | Update Interval: 0 120 | Value: false 121 | Enabled: true 122 | Global Options: 123 | Background Color: 48; 48; 48 124 | Default Light: true 125 | Fixed Frame: base_link 126 | Frame Rate: 30 127 | Name: root 128 | Tools: 129 | - Class: rviz/Interact 130 | Hide Inactive Objects: true 131 | - Class: rviz/MoveCamera 132 | - Class: rviz/Select 133 | - Class: rviz/FocusCamera 134 | - Class: rviz/Measure 135 | - Class: rviz/SetInitialPose 136 | Theta std deviation: 0.2617993950843811 137 | Topic: /initialpose 138 | X std deviation: 0.5 139 | Y std deviation: 0.5 140 | - Class: rviz/SetGoal 141 | Topic: /move_base_simple/goal 142 | - Class: rviz/PublishPoint 143 | Single click: true 144 | Topic: /clicked_point 145 | Value: true 146 | Views: 147 | Current: 148 | Class: rviz/Orbit 149 | Distance: 2.1567115783691406 150 | Enable Stereo Rendering: 151 | Stereo Eye Separation: 0.05999999865889549 152 | Stereo Focal Distance: 1 153 | Swap Stereo Eyes: false 154 | Value: false 155 | Field of View: 0.7853981852531433 156 | Focal Point: 157 | X: 0 158 | Y: 0 159 | Z: 0 160 | Focal Shape Fixed Size: true 161 | Focal Shape Size: 0.05000000074505806 162 | Invert Z Axis: false 163 | Name: Current View 164 | Near Clip Distance: 0.009999999776482582 165 | Pitch: 0.785398006439209 166 | Target Frame: 167 | Yaw: 0.785398006439209 168 | Saved: ~ 169 | Window Geometry: 170 | Displays: 171 | collapsed: false 172 | Height: 846 173 | Hide Left Dock: false 174 | Hide Right Dock: false 175 | QMainWindow State: 000000ff00000000fd000000040000000000000156000002b0fc0200000008fb0000001200530065006c0065006300740069006f006e00000001e10000009b0000005c00fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000185000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb000000100044006900730070006c006100790073010000003d000002b0000000c900fffffffb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c00000261000000010000010f000002b0fc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a00560069006500770073010000003d000002b0000000a400fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000490000000a9fc0100000001fb0000000a00560069006500770073030000004e00000080000002e10000019700000003000004b00000003efc0100000002fb0000000800540069006d00650100000000000004b0000003bc00fffffffb0000000800540069006d006501000000000000045000000000000000000000023f000002b000000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000 176 | Selection: 177 | collapsed: false 178 | Time: 179 | collapsed: false 180 | Tool Properties: 181 | collapsed: false 182 | Views: 183 | collapsed: false 184 | Width: 1200 185 | X: 60 186 | Y: 27 187 | -------------------------------------------------------------------------------- /src/Piper_ros/src/piper_description/scripts/rviz_ctrl_gazebo.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import rospy 4 | from sensor_msgs.msg import JointState 5 | from std_msgs.msg import Float64 6 | 7 | class JointStateRelay: 8 | def __init__(self): 9 | rospy.init_node('rviz_ctrl_gazebo', anonymous=True) 10 | 11 | # 创建发布者来发布到每个关节的控制器话题 12 | self.joint1_pub = rospy.Publisher('/piper_description/joint1_position_controller/command', Float64, queue_size=2) 13 | self.joint2_pub = rospy.Publisher('/piper_description/joint2_position_controller/command', Float64, queue_size=2) 14 | self.joint3_pub = rospy.Publisher('/piper_description/joint3_position_controller/command', Float64, queue_size=2) 15 | self.joint4_pub = rospy.Publisher('/piper_description/joint4_position_controller/command', Float64, queue_size=2) 16 | self.joint5_pub = rospy.Publisher('/piper_description/joint5_position_controller/command', Float64, queue_size=2) 17 | self.joint6_pub = rospy.Publisher('/piper_description/joint6_position_controller/command', Float64, queue_size=2) 18 | self.joint7_pub = rospy.Publisher('/piper_description/joint7_position_controller/command', Float64, queue_size=2) 19 | self.joint8_pub = rospy.Publisher('/piper_description/joint8_position_controller/command', Float64, queue_size=2) 20 | 21 | # 订阅/joint_states话题 22 | rospy.Subscriber('/joint_states', JointState, self.joint_states_callback) 23 | 24 | def joint_states_callback(self, msg): 25 | # 假设joint_states中的关节名称和控制器的话题顺序一致 26 | # 如果顺序不同,需要进行映射 27 | try: 28 | # 逐个发布到相应的话题 29 | self.joint1_pub.publish(msg.position[0]) 30 | self.joint2_pub.publish(msg.position[1]) 31 | self.joint3_pub.publish(msg.position[2]) 32 | self.joint4_pub.publish(msg.position[3]) 33 | self.joint5_pub.publish(msg.position[4]) 34 | self.joint6_pub.publish(msg.position[5]) 35 | self.joint7_pub.publish(msg.position[6]) 36 | self.joint8_pub.publish(msg.position[7]) 37 | except IndexError: 38 | rospy.logerr("Received joint states do not match expected number of joints.") 39 | 40 | def run(self): 41 | rospy.spin() 42 | 43 | if __name__ == '__main__': 44 | try: 45 | relay = JointStateRelay() 46 | relay.run() 47 | except rospy.ROSInterruptException: 48 | pass 49 | -------------------------------------------------------------------------------- /src/Piper_ros/src/piper_description/urdf/piper_description.csv: -------------------------------------------------------------------------------- 1 | Link Name,Center of Mass X,Center of Mass Y,Center of Mass Z,Center of Mass Roll,Center of Mass Pitch,Center of Mass Yaw,Mass,Moment Ixx,Moment Ixy,Moment Ixz,Moment Iyy,Moment Iyz,Moment Izz,Visual X,Visual Y,Visual Z,Visual Roll,Visual Pitch,Visual Yaw,Mesh Filename,Color Red,Color Green,Color Blue,Color Alpha,Collision X,Collision Y,Collision Z,Collision Roll,Collision Pitch,Collision Yaw,Collision Mesh Filename,Material Name,SW Components,Coordinate System,Axis Name,Joint Name,Joint Type,Joint Origin X,Joint Origin Y,Joint Origin Z,Joint Origin Roll,Joint Origin Pitch,Joint Origin Yaw,Parent,Joint Axis X,Joint Axis Y,Joint Axis Z,Limit Effort,Limit Velocity,Limit Lower,Limit Upper,Calibration rising,Calibration falling,Dynamics Damping,Dynamics Friction,Safety Soft Upper,Safety Soft Lower,Safety K Position,Safety K Velocity 2 | base_link,-0.00473641164191482,2.56829134630247E-05,0.041451518036016,0,0,0,0.333893486740112,0.000254953479570424,2.06931238580746E-07,7.30912474718368E-06,0.00027202099920186,2.65131745382267E-07,0.000276534627629623,0,0,0,0,0,0,package://piper_description/meshes/base_link.STL,0.792156862745098,0.819607843137255,0.933333333333333,1,0,0,0,0,0,0,package://piper_description/meshes/base_link.STL,,base_link-1,base_link_axis,,,,0,0,0,0,0,0,,0,0,0,,,,,,,,,,,, 3 | link1,0.000121504734057468,0.000104632162460536,-0.00438597309559853,0,0,0,0.215052383265765,0.000109639007860341,2.50631260865109E-07,-1.89352789149844E-07,9.95612262461418E-05,1.00634716976093E-08,0.000116363910317385,0,0,0,0,0,0,package://piper_description/meshes/link1.STL,0.792156862745098,0.819607843137255,0.933333333333333,1,0,0,0,0,0,0,package://piper_description/meshes/link1.STL,,link1-1,axis1,基准轴1,joint1,revolute,0,0,0.123,0,0,0,base_link,0,0,1,100,5,-2.618,2.168,,,,,,,, 4 | link2,0.198666145229743,-0.010926924140076,0.00142121714502687,0,0,0,0.463914239236335,0.000214137415059993,7.26120579340088E-05,-9.88224861011274E-07,0.00100030277518254,-1.32818212212246E-06,0.00104417184176783,0,0,0,0,0,0,package://piper_description/meshes/link2.STL,0.792156862745098,0.819607843137255,0.933333333333333,1,0,0,0,0,0,0,package://piper_description/meshes/link2.STL,,link2-1,axis2,基准轴2,joint2,revolute,0,0,0,1.5708,-0.10095,-3.1416,link1,0,0,1,100,5,0,3.14,,,,,,,, 5 | link3,-0.0202737662122021,-0.133914995944595,-0.000458682652737356,0,0,0,0.219942452993132,0.00018953849076141,-8.05719205057736E-06,5.10255053956334E-07,7.1424497082494E-05,8.89044974368937E-07,0.000201212938725775,0,0,0,0,0,0,package://piper_description/meshes/link3.STL,0.792156862745098,0.819607843137255,0.933333333333333,1,0,0,0,0,0,0,package://piper_description/meshes/link3.STL,,link3-1,axis3,基准轴3,joint3,revolute,0.28503,0,0,0,0,-1.759,link2,0,0,1,100,5,-2.697,0,,,,,,,, 6 | link4,-9.66635791618542E-05,0.000876064475651083,-0.00496880904640868,0,0,0,0.131814339939458,3.96965423235175E-05,-2.32268338444837E-08,-1.14702090783249E-07,5.13319789853892E-05,9.92852686264567E-08,4.14768131680711E-05,0,0,0,0,0,0,package://piper_description/meshes/link4.STL,0.792156862745098,0.819607843137255,0.933333333333333,1,0,0,0,0,0,0,package://piper_description/meshes/link4.STL,,link4-1,axis4,基准轴4,joint4,revolute,-0.021984,-0.25075,0,1.5708,0,0,link3,0,0,1,100,5,-1.832,1.832,,,,,,,, 7 | link5,-4.10554118924211E-05,-0.0566486692356075,-0.0037205791677906,0,0,0,0.134101341225523,4.10994130543451E-05,-2.06433983793957E-08,1.29591347668502E-10,5.27723004189144E-05,1.9140716904272E-07,4.60418752810541E-05,0,0,0,0,0,0,package://piper_description/meshes/link5.STL,0.792156862745098,0.819607843137255,0.933333333333333,1,0,0,0,0,0,0,package://piper_description/meshes/link5.STL,,link5-1,axis5,基准轴5,joint5,revolute,0,0,0,-1.5708,0,0,link4,0,0,1,100,5,-1.22,1.22,,,,,,,, 8 | link6,-8.82590762930069E-05,9.0598378529832E-06,-0.002,0,0,0,0.00699089613564366,5.43015540542155E-07,-1.98305403089247E-22,-7.2791893904596E-23,5.43015540542155E-07,-3.4146026640245E-24,1.06738869138926E-06,0,0,0,0,0,0,package://piper_description/meshes/link6.STL,0.898039215686275,0.917647058823529,0.929411764705882,1,0,0,0,0,0,0,package://piper_description/meshes/link6.STL,,link6-1,axis6,基准轴6,joint6,revolute,8.8259E-05,-0.091,0,1.5708,0,0,link5,0,0,1,100,5,-2.0944,2.0944,,,,,,,, 9 | link7,0.000651231850428001,0.0491929869132543,-0.00972258769184212,0,0,0,0.0303534920715453,1.13870358990681E-05,-4.28534109923149E-07,6.45170690452229E-08,6.26108891787295E-06,1.57290362128572E-06,1.57822030592225E-05,0,0,0,0,0,0,package://gripper_description/meshes/link7.STL,0.792156862745098,0.819607843137255,0.933333333333333,1,0,0,0,0,0,0,package://gripper_description/meshes/link7.STL,,爪夹-夹子-1,坐标系2,基准轴2,joint7,prismatic,0,-0.035,0.1358,-1.5708,0,0,base_link,0,0,1,10,1,0,0.035,,,,,,,, 10 | link8,0.000651231850427983,0.0491929869132549,-0.00972258769184214,0,0,0,0.0303534920715448,1.13870358990674E-05,-4.28534109923206E-07,6.45170690452328E-08,6.26108891787295E-06,1.5729036212857E-06,1.57822030592218E-05,0,0,0,0,0,0,package://gripper_description/meshes/link8.STL,0.792156862745098,0.819607843137255,0.933333333333333,1,0,0,0,0,0,0,package://gripper_description/meshes/link8.STL,,爪夹-夹子-2,坐标系3,基准轴2,joint8,prismatic,0,0.035,0.1358,-1.5708,0,-3.1416,base_link,0,0,-1,10,1,-0.035,0,,,,,,,, 11 | -------------------------------------------------------------------------------- /src/Piper_ros/src/piper_description/urdf/piper_description.urdf: -------------------------------------------------------------------------------- 1 | 2 | 5 | 7 | 9 | 10 | 13 | 15 | 22 | 23 | 24 | 27 | 28 | 30 | 31 | 33 | 35 | 36 | 37 | 38 | 41 | 42 | 44 | 45 | 46 | 47 | 49 | 50 | 53 | 55 | 62 | 63 | 64 | 67 | 68 | 70 | 71 | 73 | 75 | 76 | 77 | 78 | 81 | 82 | 84 | 85 | 86 | 87 | 90 | 93 | 95 | 97 | 99 | 104 | 105 | 107 | 108 | 111 | 113 | 120 | 121 | 122 | 125 | 126 | 128 | 129 | 131 | 133 | 134 | 135 | 136 | 139 | 140 | 142 | 143 | 144 | 145 | 148 | 151 | 153 | 155 | 157 | 162 | 163 | 165 | 166 | 169 | 171 | 178 | 179 | 180 | 183 | 184 | 186 | 187 | 189 | 191 | 192 | 193 | 194 | 197 | 198 | 200 | 201 | 202 | 203 | 206 | 209 | 211 | 213 | 215 | 220 | 221 | 223 | 224 | 227 | 229 | 236 | 237 | 238 | 241 | 242 | 244 | 245 | 247 | 249 | 250 | 251 | 252 | 255 | 256 | 258 | 259 | 260 | 261 | 264 | 267 | 269 | 271 | 273 | 278 | 279 | 281 | 282 | 285 | 287 | 294 | 295 | 296 | 299 | 300 | 302 | 303 | 305 | 307 | 308 | 309 | 310 | 313 | 314 | 316 | 317 | 318 | 319 | 322 | 325 | 327 | 329 | 331 | 336 | 337 | 339 | 340 | 343 | 345 | 352 | 353 | 354 | 357 | 358 | 360 | 361 | 363 | 365 | 366 | 367 | 368 | 371 | 372 | 374 | 375 | 376 | 377 | 380 | 383 | 385 | 387 | 389 | 394 | 395 | 397 | 398 | 401 | 403 | 410 | 411 | 412 | 415 | 416 | 418 | 419 | 421 | 423 | 424 | 425 | 426 | 429 | 430 | 432 | 433 | 434 | 435 | 438 | 441 | 443 | 445 | 446 | 448 | 449 | 452 | 454 | 461 | 462 | 463 | 466 | 467 | 469 | 470 | 472 | 474 | 475 | 476 | 477 | 480 | 481 | 483 | 484 | 485 | 486 | 489 | 492 | 494 | 496 | 498 | 503 | 504 | 506 | 507 | 510 | 512 | 519 | 520 | 521 | 524 | 525 | 527 | 528 | 530 | 532 | 533 | 534 | 535 | 538 | 539 | 541 | 542 | 543 | 544 | 547 | 550 | 552 | 554 | 556 | 561 | 562 | -------------------------------------------------------------------------------- /src/Piper_ros/src/piper_description/urdf/piper_no_gripper_description.csv: -------------------------------------------------------------------------------- 1 | Link Name,Center of Mass X,Center of Mass Y,Center of Mass Z,Center of Mass Roll,Center of Mass Pitch,Center of Mass Yaw,Mass,Moment Ixx,Moment Ixy,Moment Ixz,Moment Iyy,Moment Iyz,Moment Izz,Visual X,Visual Y,Visual Z,Visual Roll,Visual Pitch,Visual Yaw,Mesh Filename,Color Red,Color Green,Color Blue,Color Alpha,Collision X,Collision Y,Collision Z,Collision Roll,Collision Pitch,Collision Yaw,Collision Mesh Filename,Material Name,SW Components,Coordinate System,Axis Name,Joint Name,Joint Type,Joint Origin X,Joint Origin Y,Joint Origin Z,Joint Origin Roll,Joint Origin Pitch,Joint Origin Yaw,Parent,Joint Axis X,Joint Axis Y,Joint Axis Z,Limit Effort,Limit Velocity,Limit Lower,Limit Upper,Calibration rising,Calibration falling,Dynamics Damping,Dynamics Friction,Safety Soft Upper,Safety Soft Lower,Safety K Position,Safety K Velocity 2 | base_link,-0.00473641164191482,2.56829134630247E-05,0.041451518036016,0,0,0,0.333893486740112,0.000254953479570424,2.06931238580746E-07,7.30912474718368E-06,0.00027202099920186,2.65131745382267E-07,0.000276534627629623,0,0,0,0,0,0,package://piper_description/meshes/base_link.STL,0.792156862745098,0.819607843137255,0.933333333333333,1,0,0,0,0,0,0,package://piper_description/meshes/base_link.STL,,base_link-1,base_link_axis,,,,0,0,0,0,0,0,,0,0,0,,,,,,,,,,,, 3 | link1,0.000121504734057468,0.000104632162460536,-0.00438597309559853,0,0,0,0.215052383265765,0.000109639007860341,2.50631260865109E-07,-1.89352789149844E-07,9.95612262461418E-05,1.00634716976093E-08,0.000116363910317385,0,0,0,0,0,0,package://piper_description/meshes/link1.STL,0.792156862745098,0.819607843137255,0.933333333333333,1,0,0,0,0,0,0,package://piper_description/meshes/link1.STL,,link1-1,axis1,基准轴1,joint1,revolute,0,0,0.123,0,0,0,base_link,0,0,1,100,5,-2.618,2.168,,,,,,,, 4 | link2,0.198666145229743,-0.010926924140076,0.00142121714502687,0,0,0,0.463914239236335,0.000214137415059993,7.26120579340088E-05,-9.88224861011274E-07,0.00100030277518254,-1.32818212212246E-06,0.00104417184176783,0,0,0,0,0,0,package://piper_description/meshes/link2.STL,0.792156862745098,0.819607843137255,0.933333333333333,1,0,0,0,0,0,0,package://piper_description/meshes/link2.STL,,link2-1,axis2,基准轴2,joint2,revolute,0,0,0,1.5708,-0.10095,-3.1416,link1,0,0,1,100,5,0,3.14,,,,,,,, 5 | link3,-0.0202737662122021,-0.133914995944595,-0.000458682652737356,0,0,0,0.219942452993132,0.00018953849076141,-8.05719205057736E-06,5.10255053956334E-07,7.1424497082494E-05,8.89044974368937E-07,0.000201212938725775,0,0,0,0,0,0,package://piper_description/meshes/link3.STL,0.792156862745098,0.819607843137255,0.933333333333333,1,0,0,0,0,0,0,package://piper_description/meshes/link3.STL,,link3-1,axis3,基准轴3,joint3,revolute,0.28503,0,0,0,0,-1.759,link2,0,0,1,100,5,-2.697,0,,,,,,,, 6 | link4,-9.66635791618542E-05,0.000876064475651083,-0.00496880904640868,0,0,0,0.131814339939458,3.96965423235175E-05,-2.32268338444837E-08,-1.14702090783249E-07,5.13319789853892E-05,9.92852686264567E-08,4.14768131680711E-05,0,0,0,0,0,0,package://piper_description/meshes/link4.STL,0.792156862745098,0.819607843137255,0.933333333333333,1,0,0,0,0,0,0,package://piper_description/meshes/link4.STL,,link4-1,axis4,基准轴4,joint4,revolute,-0.021984,-0.25075,0,1.5708,0,0,link3,0,0,1,100,5,-1.832,1.832,,,,,,,, 7 | link5,-4.10554118924211E-05,-0.0566486692356075,-0.0037205791677906,0,0,0,0.134101341225523,4.10994130543451E-05,-2.06433983793957E-08,1.29591347668502E-10,5.27723004189144E-05,1.9140716904272E-07,4.60418752810541E-05,0,0,0,0,0,0,package://piper_description/meshes/link5.STL,0.792156862745098,0.819607843137255,0.933333333333333,1,0,0,0,0,0,0,package://piper_description/meshes/link5.STL,,link5-1,axis5,基准轴5,joint5,revolute,0,0,0,-1.5708,0,0,link4,0,0,1,100,5,-1.22,1.22,,,,,,,, 8 | link6,-8.82590762930069E-05,9.0598378529832E-06,-0.002,0,0,0,0.00699089613564366,5.43015540542155E-07,-1.98305403089247E-22,-7.2791893904596E-23,5.43015540542155E-07,-3.4146026640245E-24,1.06738869138926E-06,0,0,0,0,0,0,package://piper_description/meshes/link6.STL,0.898039215686275,0.917647058823529,0.929411764705882,1,0,0,0,0,0,0,package://piper_description/meshes/link6.STL,,link6-1,axis6,基准轴6,joint6,revolute,8.8259E-05,-0.091,0,1.5708,0,0,link5,0,0,1,100,5,-2.0944,2.0944,,,,,,,, -------------------------------------------------------------------------------- /src/Piper_ros/src/piper_description/urdf/piper_no_gripper_description.urdf: -------------------------------------------------------------------------------- 1 | 2 | 5 | 7 | 9 | 10 | 13 | 15 | 22 | 23 | 24 | 27 | 28 | 30 | 31 | 33 | 35 | 36 | 37 | 38 | 41 | 42 | 44 | 45 | 46 | 47 | 49 | 50 | 53 | 55 | 62 | 63 | 64 | 67 | 68 | 70 | 71 | 73 | 75 | 76 | 77 | 78 | 81 | 82 | 84 | 85 | 86 | 87 | 90 | 93 | 95 | 97 | 99 | 104 | 105 | 107 | 108 | 111 | 113 | 120 | 121 | 122 | 125 | 126 | 128 | 129 | 131 | 133 | 134 | 135 | 136 | 139 | 140 | 142 | 143 | 144 | 145 | 148 | 151 | 153 | 155 | 157 | 162 | 163 | 165 | 166 | 169 | 171 | 178 | 179 | 180 | 183 | 184 | 186 | 187 | 189 | 191 | 192 | 193 | 194 | 197 | 198 | 200 | 201 | 202 | 203 | 206 | 209 | 211 | 213 | 215 | 220 | 221 | 223 | 224 | 227 | 229 | 236 | 237 | 238 | 241 | 242 | 244 | 245 | 247 | 249 | 250 | 251 | 252 | 255 | 256 | 258 | 259 | 260 | 261 | 264 | 267 | 269 | 271 | 273 | 278 | 279 | 281 | 282 | 285 | 287 | 294 | 295 | 296 | 299 | 300 | 302 | 303 | 305 | 307 | 308 | 309 | 310 | 313 | 314 | 316 | 317 | 318 | 319 | 322 | 325 | 327 | 329 | 331 | 336 | 337 | 339 | 340 | 343 | 345 | 352 | 353 | 354 | 357 | 358 | 360 | 361 | 363 | 365 | 366 | 367 | 368 | 371 | 372 | 374 | 375 | 376 | 377 | 380 | 383 | 385 | 387 | 389 | 394 | 395 | -------------------------------------------------------------------------------- /src/Piper_ros/src/piper_description/urdf/piper_no_gripper_description.xacro: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 14 | 15 | 18 | 20 | 27 | 28 | 29 | 32 | 33 | 35 | 36 | 38 | 40 | 41 | 42 | 43 | 46 | 47 | 49 | 50 | 51 | 52 | 54 | 55 | 58 | 60 | 67 | 68 | 69 | 72 | 73 | 75 | 76 | 78 | 80 | 81 | 82 | 83 | 86 | 87 | 89 | 90 | 91 | 92 | 95 | 98 | 100 | 102 | 104 | 109 | 110 | 112 | 113 | 116 | 118 | 125 | 126 | 127 | 130 | 131 | 133 | 134 | 136 | 138 | 139 | 140 | 141 | 144 | 145 | 147 | 148 | 149 | 150 | 153 | 156 | 158 | 160 | 162 | 167 | 168 | 170 | 171 | 174 | 176 | 183 | 184 | 185 | 188 | 189 | 191 | 192 | 194 | 196 | 197 | 198 | 199 | 202 | 203 | 205 | 206 | 207 | 208 | 211 | 214 | 216 | 218 | 220 | 225 | 226 | 228 | 229 | 232 | 234 | 241 | 242 | 243 | 246 | 247 | 249 | 250 | 252 | 254 | 255 | 256 | 257 | 260 | 261 | 263 | 264 | 265 | 266 | 269 | 272 | 274 | 276 | 278 | 283 | 284 | 286 | 287 | 290 | 292 | 299 | 300 | 301 | 304 | 305 | 307 | 308 | 310 | 312 | 313 | 314 | 315 | 318 | 319 | 321 | 322 | 323 | 324 | 327 | 330 | 332 | 334 | 336 | 341 | 342 | 344 | 345 | 348 | 350 | 357 | 358 | 359 | 362 | 363 | 365 | 366 | 368 | 370 | 371 | 372 | 373 | 376 | 377 | 379 | 380 | 381 | 382 | 385 | 388 | 390 | 392 | 394 | 399 | 400 | 401 | 402 | 403 | 404 | transmission_interface/SimpleTransmission 405 | 406 | hardware_interface/PositionJointInterface 407 | 408 | 409 | hardware_interface/PositionJointInterface 410 | 1 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | /piper_description 425 | true 426 | 427 | 428 | -------------------------------------------------------------------------------- /src/Piper_ros/src/piper_description/worlds/empty.world: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | model://sun 7 | 8 | 9 | 10 | 11 | model://ground_plane 12 | 13 | 14 | 15 | 16 | 0.01 17 | 1 18 | 100 19 | 0 0 -9.8 20 | 21 | 22 | quick 23 | 500 24 | 1.3 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/Piper_ros/src/piper_msgs/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0.2) 2 | project(piper_msgs) 3 | 4 | ## Compile as C++11, supported in ROS Kinetic and newer 5 | # add_compile_options(-std=c++11) 6 | 7 | ## Find catkin macros and libraries 8 | ## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz) 9 | ## is used, also find other catkin packages 10 | find_package(catkin REQUIRED COMPONENTS 11 | actionlib 12 | actionlib_msgs 13 | control_msgs 14 | roscpp 15 | rospy 16 | sensor_msgs 17 | std_msgs 18 | trajectory_msgs 19 | message_generation 20 | geometry_msgs 21 | ) 22 | 23 | ## System dependencies are found with CMake's conventions 24 | # find_package(Boost REQUIRED COMPONENTS system) 25 | 26 | 27 | ## Uncomment this if the package has a setup.py. This macro ensures 28 | ## modules and global scripts declared therein get installed 29 | ## See http://ros.org/doc/api/catkin/html/user_guide/setup_dot_py.html 30 | # catkin_python_setup() 31 | 32 | ################################################ 33 | ## Declare ROS messages, services and actions ## 34 | ################################################ 35 | 36 | ## To declare and build messages, services or actions from within this 37 | ## package, follow these steps: 38 | ## * Let MSG_DEP_SET be the set of packages whose message types you use in 39 | ## your messages/services/actions (e.g. std_msgs, actionlib_msgs, ...). 40 | ## * In the file package.xml: 41 | ## * add a build_depend tag for "message_generation" 42 | ## * add a build_depend and a exec_depend tag for each package in MSG_DEP_SET 43 | ## * If MSG_DEP_SET isn't empty the following dependency has been pulled in 44 | ## but can be declared for certainty nonetheless: 45 | ## * add a exec_depend tag for "message_runtime" 46 | ## * In this file (CMakeLists.txt): 47 | ## * add "message_generation" and every package in MSG_DEP_SET to 48 | ## find_package(catkin REQUIRED COMPONENTS ...) 49 | ## * add "message_runtime" and every package in MSG_DEP_SET to 50 | ## catkin_package(CATKIN_DEPENDS ...) 51 | ## * uncomment the add_*_files sections below as needed 52 | ## and list every .msg/.srv/.action file to be processed 53 | ## * uncomment the generate_messages entry below 54 | ## * add every package in MSG_DEP_SET to generate_messages(DEPENDENCIES ...) 55 | 56 | ## Generate messages in the 'msg' folder 57 | # add_message_files( 58 | # FILES 59 | # Message1.msg 60 | # Message2.msg 61 | # ) 62 | 63 | ## Generate services in the 'srv' folder 64 | # add_service_files( 65 | # FILES 66 | # Service1.srv 67 | # Service2.srv 68 | # ) 69 | 70 | ## Generate actions in the 'action' folder 71 | # add_action_files( 72 | # FILES 73 | # Action1.action 74 | # Action2.action 75 | # ) 76 | add_message_files( 77 | FILES 78 | PiperStatusMsg.msg 79 | PosCmd.msg 80 | ) 81 | add_service_files( 82 | FILES 83 | Enable.srv 84 | Gripper.srv 85 | GoZero.srv 86 | ) 87 | ## Generate added messages and services with any dependencies listed here 88 | generate_messages( 89 | DEPENDENCIES 90 | actionlib_msgs# control_msgs# sensor_msgs# 91 | std_msgs# trajectory_msgs 92 | ) 93 | 94 | ################################################ 95 | ## Declare ROS dynamic reconfigure parameters ## 96 | ################################################ 97 | 98 | ## To declare and build dynamic reconfigure parameters within this 99 | ## package, follow these steps: 100 | ## * In the file package.xml: 101 | ## * add a build_depend and a exec_depend tag for "dynamic_reconfigure" 102 | ## * In this file (CMakeLists.txt): 103 | ## * add "dynamic_reconfigure" to 104 | ## find_package(catkin REQUIRED COMPONENTS ...) 105 | ## * uncomment the "generate_dynamic_reconfigure_options" section below 106 | ## and list every .cfg file to be processed 107 | 108 | ## Generate dynamic reconfigure parameters in the 'cfg' folder 109 | # generate_dynamic_reconfigure_options( 110 | # cfg/DynReconf1.cfg 111 | # cfg/DynReconf2.cfg 112 | # ) 113 | 114 | ################################### 115 | ## catkin specific configuration ## 116 | ################################### 117 | ## The catkin_package macro generates cmake config files for your package 118 | ## Declare things to be passed to dependent projects 119 | ## INCLUDE_DIRS: uncomment this if your package contains header files 120 | ## LIBRARIES: libraries you create in this project that dependent projects also need 121 | ## CATKIN_DEPENDS: catkin_packages dependent projects also need 122 | ## DEPENDS: system dependencies of this project that dependent projects also need 123 | catkin_package( 124 | # INCLUDE_DIRS include 125 | # LIBRARIES piper 126 | CATKIN_DEPENDS actionlib actionlib_msgs control_msgs roscpp rospy sensor_msgs std_msgs trajectory_msgs message_generation geometry_msgs 127 | # DEPENDS system_lib 128 | ) 129 | 130 | ########### 131 | ## Build ## 132 | ########### 133 | 134 | ## Specify additional locations of header files 135 | ## Your package locations should be listed before other locations 136 | include_directories( 137 | include 138 | ${catkin_INCLUDE_DIRS} 139 | ) 140 | 141 | ## Declare a C++ library 142 | # add_library(${PROJECT_NAME} 143 | # src/${PROJECT_NAME}/piper.cpp 144 | # ) 145 | 146 | ## Add cmake target dependencies of the library 147 | ## as an example, code may need to be generated before libraries 148 | ## either from message generation or dynamic reconfigure 149 | # add_dependencies(${PROJECT_NAME} ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS}) 150 | 151 | ## Declare a C++ executable 152 | ## With catkin_make all packages are built within a single CMake context 153 | ## The recommended prefix ensures that target names across packages don't collide 154 | # add_executable(${PROJECT_NAME}_node src/piper_node.cpp) 155 | 156 | ## Rename C++ executable without prefix 157 | ## The above recommended prefix causes long target names, the following renames the 158 | ## target back to the shorter version for ease of user use 159 | ## e.g. "rosrun someones_pkg node" instead of "rosrun someones_pkg someones_pkg_node" 160 | # set_target_properties(${PROJECT_NAME}_node PROPERTIES OUTPUT_NAME node PREFIX "") 161 | 162 | ## Add cmake target dependencies of the executable 163 | ## same as for the library above 164 | # add_dependencies(${PROJECT_NAME}_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS}) 165 | 166 | ## Specify libraries to link a library or executable target against 167 | # target_link_libraries(${PROJECT_NAME}_node 168 | # ${catkin_LIBRARIES} 169 | # ) 170 | 171 | ############# 172 | ## Install ## 173 | ############# 174 | 175 | # all install targets should use catkin DESTINATION variables 176 | # See http://ros.org/doc/api/catkin/html/adv_user_guide/variables.html 177 | 178 | ## Mark executable scripts (Python etc.) for installation 179 | ## in contrast to setup.py, you can choose the destination 180 | # catkin_install_python(PROGRAMS 181 | # scripts/my_python_script 182 | # DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} 183 | # ) 184 | 185 | ## Mark executables for installation 186 | ## See http://docs.ros.org/melodic/api/catkin/html/howto/format1/building_executables.html 187 | # install(TARGETS ${PROJECT_NAME}_node 188 | # RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} 189 | # ) 190 | 191 | ## Mark libraries for installation 192 | ## See http://docs.ros.org/melodic/api/catkin/html/howto/format1/building_libraries.html 193 | # install(TARGETS ${PROJECT_NAME} 194 | # ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} 195 | # LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} 196 | # RUNTIME DESTINATION ${CATKIN_GLOBAL_BIN_DESTINATION} 197 | # ) 198 | 199 | ## Mark cpp header files for installation 200 | # install(DIRECTORY include/${PROJECT_NAME}/ 201 | # DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION} 202 | # FILES_MATCHING PATTERN "*.h" 203 | # PATTERN ".svn" EXCLUDE 204 | # ) 205 | 206 | ## Mark other files for installation (e.g. launch and bag files, etc.) 207 | # install(FILES 208 | # # myfile1 209 | # # myfile2 210 | # DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION} 211 | # ) 212 | 213 | ############# 214 | ## Testing ## 215 | ############# 216 | 217 | ## Add gtest based cpp test target and link libraries 218 | # catkin_add_gtest(${PROJECT_NAME}-test test/test_piper.cpp) 219 | # if(TARGET ${PROJECT_NAME}-test) 220 | # target_link_libraries(${PROJECT_NAME}-test ${PROJECT_NAME}) 221 | # endif() 222 | 223 | ## Add folders to be run by python nosetests 224 | # catkin_add_nosetests(test) 225 | -------------------------------------------------------------------------------- /src/Piper_ros/src/piper_msgs/msg/PiperStatusMsg.msg: -------------------------------------------------------------------------------- 1 | uint8 ctrl_mode 2 | uint8 arm_status 3 | uint8 mode_feedback 4 | uint8 teach_status 5 | uint8 motion_status 6 | uint8 trajectory_num 7 | int64 err_code 8 | bool joint_1_angle_limit 9 | bool joint_2_angle_limit 10 | bool joint_3_angle_limit 11 | bool joint_4_angle_limit 12 | bool joint_5_angle_limit 13 | bool joint_6_angle_limit 14 | bool communication_status_joint_1 15 | bool communication_status_joint_2 16 | bool communication_status_joint_3 17 | bool communication_status_joint_4 18 | bool communication_status_joint_5 19 | bool communication_status_joint_6 20 | 21 | -------------------------------------------------------------------------------- /src/Piper_ros/src/piper_msgs/msg/PosCmd.msg: -------------------------------------------------------------------------------- 1 | float64 x 2 | float64 y 3 | float64 z 4 | float64 roll 5 | float64 pitch 6 | float64 yaw 7 | float64 gripper 8 | int32 mode1 9 | int32 mode2 -------------------------------------------------------------------------------- /src/Piper_ros/src/piper_msgs/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | piper_msgs 4 | 0.0.0 5 | The piper_msgs package 6 | 7 | 8 | 9 | 10 | agilex 11 | 12 | 13 | 14 | 15 | 16 | TODO 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | catkin 52 | actionlib 53 | actionlib_msgs 54 | control_msgs 55 | roscpp 56 | rospy 57 | sensor_msgs 58 | std_msgs 59 | trajectory_msgs 60 | actionlib 61 | actionlib_msgs 62 | control_msgs 63 | roscpp 64 | rospy 65 | sensor_msgs 66 | std_msgs 67 | trajectory_msgs 68 | actionlib 69 | actionlib_msgs 70 | control_msgs 71 | roscpp 72 | rospy 73 | sensor_msgs 74 | std_msgs 75 | trajectory_msgs 76 | 77 | message_generation 78 | message_runtime 79 | 80 | message_generation 81 | message_runtime 82 | 83 | geometry_msgs 84 | geometry_msgs 85 | geometry_msgs 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /src/Piper_ros/src/piper_msgs/srv/Enable.srv: -------------------------------------------------------------------------------- 1 | bool enable_request # 请求消息类型为bool 2 | --- 3 | bool enable_response # 响应消息类型为bool 4 | -------------------------------------------------------------------------------- /src/Piper_ros/src/piper_msgs/srv/GoZero.srv: -------------------------------------------------------------------------------- 1 | bool is_mit_mode 2 | --- 3 | int64 code 4 | bool status # 响应消息类型为bool -------------------------------------------------------------------------------- /src/Piper_ros/src/piper_msgs/srv/Gripper.srv: -------------------------------------------------------------------------------- 1 | float64 gripper_angle 2 | float64 gripper_effort 3 | int64 gripper_code 4 | int64 set_zero 5 | --- 6 | int64 code 7 | bool status # 响应消息类型为bool -------------------------------------------------------------------------------- /src/oculus_reader/APK/alvr_client_android.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agilexrobotics/questVR_ws/b7a97d3eaa3adfba08af0ecf132dbb88eab4e5b9/src/oculus_reader/APK/alvr_client_android.apk -------------------------------------------------------------------------------- /src/oculus_reader/APK/teleop-debug.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agilexrobotics/questVR_ws/b7a97d3eaa3adfba08af0ecf132dbb88eab4e5b9/src/oculus_reader/APK/teleop-debug.apk -------------------------------------------------------------------------------- /src/oculus_reader/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0.2) 2 | project(oculus_reader) 3 | 4 | find_package(catkin REQUIRED COMPONENTS 5 | rospy 6 | geometry_msgs 7 | tf2_ros 8 | ) 9 | 10 | catkin_package( 11 | CATKIN_DEPENDS geometry_msgs 12 | ) 13 | -------------------------------------------------------------------------------- /src/oculus_reader/config/oculus_reader.rviz: -------------------------------------------------------------------------------- 1 | Panels: 2 | - Class: rviz/Displays 3 | Help Height: 138 4 | Name: Displays 5 | Property Tree Widget: 6 | Expanded: 7 | - /Global Options1 8 | - /Status1 9 | - /TF1 10 | - /TF1/Frames1 11 | Splitter Ratio: 0.5 12 | Tree Height: 866 13 | - Class: rviz/Selection 14 | Name: Selection 15 | - Class: rviz/Tool Properties 16 | Expanded: 17 | - /2D Pose Estimate1 18 | - /2D Nav Goal1 19 | - /Publish Point1 20 | Name: Tool Properties 21 | Splitter Ratio: 0.5886790156364441 22 | - Class: rviz/Views 23 | Expanded: 24 | - /Current View1 25 | Name: Views 26 | Splitter Ratio: 0.5 27 | - Class: rviz/Time 28 | Name: Time 29 | SyncMode: 0 30 | SyncSource: "" 31 | Preferences: 32 | PromptSaveOnExit: true 33 | Toolbars: 34 | toolButtonStyle: 2 35 | Visualization Manager: 36 | Class: "" 37 | Displays: 38 | - Alpha: 0.5 39 | Cell Size: 1 40 | Class: rviz/Grid 41 | Color: 160; 160; 164 42 | Enabled: true 43 | Line Style: 44 | Line Width: 0.029999999329447746 45 | Value: Lines 46 | Name: Grid 47 | Normal Cell Count: 0 48 | Offset: 49 | X: 0 50 | Y: 0 51 | Z: 0 52 | Plane: XY 53 | Plane Cell Count: 10 54 | Reference Frame: 55 | Value: true 56 | - Class: rviz/TF 57 | Enabled: true 58 | Filter (blacklist): "" 59 | Filter (whitelist): "" 60 | Frame Timeout: 1 61 | Frames: 62 | All Enabled: true 63 | right_hand: 64 | Value: true 65 | vr_device: 66 | Value: true 67 | Marker Alpha: 1 68 | Marker Scale: 0.10000000149011612 69 | Name: TF 70 | Show Arrows: true 71 | Show Axes: true 72 | Show Names: true 73 | Tree: 74 | vr_device: 75 | right_hand: 76 | {} 77 | Update Interval: 0 78 | Value: true 79 | Enabled: true 80 | Global Options: 81 | Background Color: 48; 48; 48 82 | Default Light: true 83 | Fixed Frame: vr_device 84 | Frame Rate: 30 85 | Name: root 86 | Tools: 87 | - Class: rviz/Interact 88 | Hide Inactive Objects: true 89 | - Class: rviz/MoveCamera 90 | - Class: rviz/Select 91 | - Class: rviz/FocusCamera 92 | - Class: rviz/Measure 93 | - Class: rviz/SetInitialPose 94 | Theta std deviation: 0.2617993950843811 95 | Topic: /initialpose 96 | X std deviation: 0.5 97 | Y std deviation: 0.5 98 | - Class: rviz/SetGoal 99 | Topic: /move_base_simple/goal 100 | - Class: rviz/PublishPoint 101 | Single click: true 102 | Topic: /clicked_point 103 | Value: true 104 | Views: 105 | Current: 106 | Class: rviz/Orbit 107 | Distance: 0.48121994733810425 108 | Enable Stereo Rendering: 109 | Stereo Eye Separation: 0.05999999865889549 110 | Stereo Focal Distance: 1 111 | Swap Stereo Eyes: false 112 | Value: false 113 | Field of View: 0.7853981852531433 114 | Focal Point: 115 | X: 0 116 | Y: 0 117 | Z: 0 118 | Focal Shape Fixed Size: true 119 | Focal Shape Size: 0.05000000074505806 120 | Invert Z Axis: false 121 | Name: Current View 122 | Near Clip Distance: 0.009999999776482582 123 | Pitch: 0.5447977781295776 124 | Target Frame: 125 | Yaw: 2.668574333190918 126 | Saved: ~ 127 | Window Geometry: 128 | Displays: 129 | collapsed: false 130 | Height: 1376 131 | Hide Left Dock: false 132 | Hide Right Dock: false 133 | QMainWindow State: 000000ff00000000fd0000000400000000000001f70000045afc0200000008fb0000001200530065006c0065006300740069006f006e00000001e10000009b000000b000fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000185000000b0fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb000000100044006900730070006c006100790073010000006e0000045a0000018200fffffffb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c00000261000000010000015f0000045afc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a00560069006500770073010000006e0000045a0000013200fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000490000000a9fc0100000001fb0000000a00560069006500770073030000004e00000080000002e1000001970000000300000a000000005efc0100000002fb0000000800540069006d0065010000000000000a00000006dc00fffffffb0000000800540069006d00650100000000000004500000000000000000000006920000045a00000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000 134 | Selection: 135 | collapsed: false 136 | Time: 137 | collapsed: false 138 | Tool Properties: 139 | collapsed: false 140 | Views: 141 | collapsed: false 142 | Width: 2560 143 | X: 0 144 | Y: 0 145 | -------------------------------------------------------------------------------- /src/oculus_reader/launch/teleop_double_piper.launch: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/oculus_reader/launch/teleop_single_piper.launch: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/oculus_reader/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | oculus_reader 4 | 0.0.1 5 | The oculus_reader package 6 | 7 | TODO 8 | 9 | Apache-2 10 | 11 | catkin 12 | 13 | rospy 14 | geometry_msgs 15 | tf2_ros 16 | 17 | -------------------------------------------------------------------------------- /src/oculus_reader/scripts/FPS_counter.py: -------------------------------------------------------------------------------- 1 | import time 2 | import numpy as np 3 | 4 | 5 | class FPSCounter: 6 | def __init__(self): 7 | current_time = time.time() 8 | self.start_time_for_display = current_time 9 | self.last_time = current_time 10 | self.x = 5 # displays the frame rate every X second 11 | self.time_between_calls = [] 12 | self.elements_for_mean = 50 13 | 14 | def getAndPrintFPS(self, print_fps=True): 15 | current_time = time.time() 16 | self.time_between_calls.append(1.0/(current_time - self.last_time + 1e-9)) 17 | if len(self.time_between_calls) > self.elements_for_mean: 18 | self.time_between_calls.pop(0) 19 | self.last_time = current_time 20 | frequency = np.mean(self.time_between_calls) 21 | if (current_time - self.start_time_for_display) > self.x and print_fps: 22 | print("Frequency: {}Hz".format(int(frequency))) 23 | self.start_time_for_display = current_time 24 | return frequency -------------------------------------------------------------------------------- /src/oculus_reader/scripts/buttons_parser.py: -------------------------------------------------------------------------------- 1 | def parse_buttons(text): 2 | split_text = text.split(',') 3 | buttons = {} 4 | if 'R' in split_text: # right hand if available 5 | split_text.remove('R') # remove marker 6 | buttons.update({'A': False, 7 | 'B': False, 8 | 'RThU': False, # indicates that right thumb is up from the rest position 9 | 'RJ': False, # joystick pressed 10 | 'RG': False, # boolean value for trigger on the grip (delivered by SDK) 11 | 'RTr': False # boolean value for trigger on the index finger (delivered by SDK) 12 | }) 13 | # besides following keys are provided: 14 | # 'rightJS' / 'leftJS' - (x, y) position of joystick. x, y both in range (-1.0, 1.0) 15 | # 'rightGrip' / 'leftGrip' - float value for trigger on the grip in range (0.0, 1.0) 16 | # 'rightTrig' / 'leftTrig' - float value for trigger on the index finger in range (0.0, 1.0) 17 | 18 | if 'L' in split_text: # left hand accordingly 19 | split_text.remove('L') # remove marker 20 | buttons.update({'X': False, 'Y': False, 'LThU': False, 'LJ': False, 'LG': False, 'LTr': False}) 21 | for key in buttons.keys(): 22 | if key in list(split_text): 23 | buttons[key] = True 24 | split_text.remove(key) 25 | for elem in split_text: 26 | split_elem = elem.split(' ') 27 | if len(split_elem) < 2: 28 | continue 29 | key = split_elem[0] 30 | value = tuple([float(x) for x in split_elem[1:]]) 31 | buttons[key] = value 32 | return buttons 33 | 34 | -------------------------------------------------------------------------------- /src/oculus_reader/scripts/install.py: -------------------------------------------------------------------------------- 1 | from oculus_reader import OculusReader 2 | 3 | def main(): 4 | import argparse 5 | 6 | parser = argparse.ArgumentParser(description='Utility to manage teleoperation APK. Installs APK if no arguments are provided.') 7 | parser.add_argument("--reinstall", action="store_true", help='reinstalls APK from the default path') 8 | parser.add_argument("--uninstall", action="store_true", help='uninstalls APK') 9 | args = parser.parse_args() 10 | 11 | reader = OculusReader(run=False) 12 | 13 | if args.reinstall: 14 | reader.install(reinstall=True) 15 | elif args.uninstall: 16 | reader.uninstall() 17 | else: 18 | reader.install() 19 | print('Done.') 20 | 21 | if __name__ == "__main__": 22 | main() 23 | -------------------------------------------------------------------------------- /src/oculus_reader/scripts/oculus_reader.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | from FPS_counter import FPSCounter 4 | from buttons_parser import parse_buttons 5 | import numpy as np 6 | import threading 7 | import time 8 | import os 9 | from ppadb.client import Client as AdbClient 10 | import sys 11 | 12 | def eprint(*args, **kwargs): 13 | RED = "\033[1;31m" 14 | sys.stderr.write(RED) 15 | print(*args, file=sys.stderr, **kwargs) 16 | RESET = "\033[0;0m" 17 | sys.stderr.write(RESET) 18 | 19 | class OculusReader: 20 | def __init__(self, 21 | ip_address=None, 22 | port = 5555, 23 | APK_name='com.rail.oculus.teleop', 24 | print_FPS=False, 25 | run=True 26 | ): 27 | self.running = False 28 | self.last_transforms = {} 29 | self.last_buttons = {} 30 | self._lock = threading.Lock() 31 | self.tag = 'wE9ryARX' 32 | 33 | self.ip_address = ip_address 34 | self.port = port 35 | self.APK_name = APK_name 36 | self.print_FPS = print_FPS 37 | if self.print_FPS: 38 | self.fps_counter = FPSCounter() 39 | self.device = self.get_device() 40 | self.install(verbose=False) 41 | if run: 42 | self.run() 43 | 44 | def __del__(self): 45 | self.stop() 46 | 47 | def run(self): 48 | self.running = True 49 | self.device.shell('am start -n "com.rail.oculus.teleop/com.rail.oculus.teleop.MainActivity" -a android.intent.action.MAIN -c android.intent.category.LAUNCHER') 50 | # self.device.shell('am startservice -n "com.rail.oculus.teleop/com.rail.oculus.teleop.MainService" -a android.intent.action.MAIN -c android.intent.category.DEFAULT') 51 | self.thread = threading.Thread(target=self.device.shell, args=("logcat -T 0", self.read_logcat_by_line)) 52 | self.thread.start() 53 | 54 | def stop(self): 55 | self.running = False 56 | if hasattr(self, 'thread'): 57 | self.thread.join() 58 | 59 | def get_network_device(self, client, retry=0): 60 | try: 61 | client.remote_connect(self.ip_address, self.port) 62 | except RuntimeError: 63 | os.system('adb devices') 64 | client.remote_connect(self.ip_address, self.port) 65 | device = client.device(self.ip_address + ':' + str(self.port)) 66 | 67 | if device is None: 68 | if retry==1: 69 | os.system('adb tcpip ' + str(self.port)) 70 | if retry==2: 71 | eprint('Make sure that device is running and is available at the IP address specified as the OculusReader argument `ip_address`.') 72 | eprint('Currently provided IP address:', self.ip_address) 73 | eprint('Run `adb shell ip route` to verify the IP address.') 74 | exit(1) 75 | else: 76 | self.get_network_device(client=client, retry=retry+1) 77 | return device 78 | 79 | def get_usb_device(self, client): 80 | try: 81 | devices = client.devices() 82 | except RuntimeError: 83 | os.system('adb devices') 84 | devices = client.devices() 85 | for device in devices: 86 | if device.serial.count('.') < 3: 87 | return device 88 | eprint('Device not found. Make sure that device is running and is connected over USB') 89 | eprint('Run `adb devices` to verify that the device is visible.') 90 | exit(1) 91 | 92 | def get_device(self): 93 | # Default is "127.0.0.1" and 5037 94 | client = AdbClient(host="127.0.0.1", port=5037) 95 | if self.ip_address is not None: 96 | return self.get_network_device(client) 97 | else: 98 | return self.get_usb_device(client) 99 | 100 | def install(self, APK_path=None, verbose=True, reinstall=False): 101 | try: 102 | installed = self.device.is_installed(self.APK_name) 103 | if not installed or reinstall: 104 | if APK_path is None: 105 | APK_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'APK', 'teleop-debug.apk') 106 | success = self.device.install(APK_path, test=True, reinstall=reinstall) 107 | installed = self.device.is_installed(self.APK_name) 108 | if installed and success: 109 | print('APK installed successfully.') 110 | else: 111 | eprint('APK install failed.') 112 | elif verbose: 113 | print('APK is already installed.') 114 | except RuntimeError: 115 | eprint('Device is visible but could not be accessed.') 116 | eprint('Run `adb devices` to verify that the device is visible and accessible.') 117 | eprint('If you see "no permissions" next to the device serial, please put on the Oculus Quest and allow the access.') 118 | exit(1) 119 | 120 | def uninstall(self, verbose=True): 121 | try: 122 | installed = self.device.is_installed(self.APK_name) 123 | if installed: 124 | success = self.device.uninstall(self.APK_name) 125 | installed = self.device.is_installed(self.APK_name) 126 | if not installed and success: 127 | print('APK uninstall finished.') 128 | print('Please verify if the app disappeared from the list as described in "UNINSTALL.md".') 129 | print('For the resolution of this issue, please follow https://github.com/Swind/pure-python-adb/issues/71.') 130 | else: 131 | eprint('APK uninstall failed') 132 | elif verbose: 133 | print('APK is not installed.') 134 | except RuntimeError: 135 | eprint('Device is visible but could not be accessed.') 136 | eprint('Run `adb devices` to verify that the device is visible and accessible.') 137 | eprint('If you see "no permissions" next to the device serial, please put on the Oculus Quest and allow the access.') 138 | exit(1) 139 | 140 | @staticmethod 141 | def process_data(string): 142 | try: 143 | transforms_string, buttons_string = string.split('&') 144 | except ValueError: 145 | return None, None 146 | split_transform_strings = transforms_string.split('|') 147 | transforms = {} 148 | for pair_string in split_transform_strings: 149 | transform = np.empty((4,4)) 150 | pair = pair_string.split(':') 151 | if len(pair) != 2: 152 | continue 153 | left_right_char = pair[0] # is r or l 154 | transform_string = pair[1] 155 | values = transform_string.split(' ') 156 | c = 0 157 | r = 0 158 | count = 0 159 | for value in values: 160 | if not value: 161 | continue 162 | transform[r][c] = float(value) 163 | c += 1 164 | if c >= 4: 165 | c = 0 166 | r += 1 167 | count += 1 168 | if count == 16: 169 | transforms[left_right_char] = transform 170 | buttons = parse_buttons(buttons_string) 171 | return transforms, buttons 172 | 173 | def extract_data(self, line): 174 | output = '' 175 | if self.tag in line: 176 | try: 177 | output += line.split(self.tag + ': ')[1] 178 | except ValueError: 179 | pass 180 | return output 181 | 182 | def get_transformations_and_buttons(self): 183 | with self._lock: 184 | return self.last_transforms, self.last_buttons 185 | 186 | def read_logcat_by_line(self, connection): 187 | file_obj = connection.socket.makefile() 188 | while self.running: 189 | try: 190 | line = file_obj.readline().strip() 191 | data = self.extract_data(line) 192 | if data: 193 | transforms, buttons = OculusReader.process_data(data) 194 | with self._lock: 195 | self.last_transforms, self.last_buttons = transforms, buttons 196 | if self.print_FPS: 197 | self.fps_counter.getAndPrintFPS() 198 | except UnicodeDecodeError: 199 | pass 200 | file_obj.close() 201 | connection.close() 202 | 203 | 204 | def main(): 205 | oculus_reader = OculusReader() 206 | 207 | while True: 208 | time.sleep(0.3) 209 | # print(oculus_reader.get_transformations_and_buttons()) 210 | 211 | 212 | if __name__ == '__main__': 213 | main() 214 | -------------------------------------------------------------------------------- /src/oculus_reader/scripts/piper_control.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | import rospy 5 | from sensor_msgs.msg import JointState 6 | # from piper_msgs.msg import PosCmd 7 | from std_msgs.msg import Header 8 | 9 | class PIPER: 10 | def __init__(self): 11 | 12 | # 发布控制piper机械臂话题 13 | # self.pub_descartes = rospy.Publisher('pos_cmd', PosCmd, queue_size=10) 14 | self.pub_joint = rospy.Publisher('/joint_states', JointState, queue_size=1) 15 | self.left_pub_joint = rospy.Publisher('/left_joint_states', JointState, queue_size=1) 16 | self.right_pub_joint = rospy.Publisher('/right_joint_states', JointState, queue_size=1) 17 | # self.descartes_msgs = PosCmd() 18 | 19 | # self.rate = rospy.Rate(80) # 10hz 20 | 21 | def init_pose(self): 22 | joint_states_msgs = JointState() 23 | joint_states_msgs.header = Header() 24 | joint_states_msgs.header.stamp = rospy.Time.now() 25 | joint_states_msgs.name = [f'joint{i+1}' for i in range(7)] 26 | joint_states_msgs.position = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] 27 | self.pub_joint.publish(joint_states_msgs) 28 | # self.rate.sleep() 29 | print("send joint control piper command") 30 | 31 | def left_init_pose(self): 32 | joint_states_msgs = JointState() 33 | joint_states_msgs.header = Header() 34 | joint_states_msgs.header.stamp = rospy.Time.now() 35 | joint_states_msgs.name = [f'joint{i+1}' for i in range(7)] 36 | joint_states_msgs.position = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] 37 | self.left_pub_joint.publish(joint_states_msgs) 38 | # self.rate.sleep() 39 | print("send joint control piper command") 40 | 41 | def right_init_pose(self): 42 | joint_states_msgs = JointState() 43 | joint_states_msgs.header = Header() 44 | joint_states_msgs.header.stamp = rospy.Time.now() 45 | joint_states_msgs.name = [f'joint{i+1}' for i in range(7)] 46 | joint_states_msgs.position = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] 47 | self.right_pub_joint.publish(joint_states_msgs) 48 | # self.rate.sleep() 49 | print("send joint control piper command") 50 | 51 | def descartes_control_piper(self,x,y,z,roll,pitch,yaw,gripper): 52 | self.descartes_msgs.x = x 53 | self.descartes_msgs.y = y 54 | self.descartes_msgs.z = z 55 | self.descartes_msgs.roll = roll 56 | self.descartes_msgs.pitch = pitch 57 | self.descartes_msgs.yaw = yaw 58 | self.descartes_msgs.gripper = gripper 59 | self.pub_descartes.publish(self.descartes_msgs) 60 | # print("send descartes control piper command") 61 | 62 | def joint_control_piper(self,j1,j2,j3,j4,j5,j6,gripper): 63 | joint_states_msgs = JointState() 64 | joint_states_msgs.header = Header() 65 | joint_states_msgs.header.stamp = rospy.Time.now() 66 | joint_states_msgs.name = [f'joint{i+1}' for i in range(7)] 67 | joint_states_msgs.position.append(j1) 68 | joint_states_msgs.position.append(j2) 69 | joint_states_msgs.position.append(j3) 70 | joint_states_msgs.position.append(j4) 71 | joint_states_msgs.position.append(j5) 72 | joint_states_msgs.position.append(j6) 73 | joint_states_msgs.position.append(gripper) 74 | self.pub_joint.publish(joint_states_msgs) 75 | # self.rate.sleep() 76 | print("send joint control piper command") 77 | 78 | def left_joint_control_piper(self,j1,j2,j3,j4,j5,j6,gripper): 79 | joint_states_msgs = JointState() 80 | joint_states_msgs.header = Header() 81 | joint_states_msgs.header.stamp = rospy.Time.now() 82 | joint_states_msgs.name = [f'joint{i+1}' for i in range(7)] 83 | joint_states_msgs.position.append(j1) 84 | joint_states_msgs.position.append(j2) 85 | joint_states_msgs.position.append(j3) 86 | joint_states_msgs.position.append(j4) 87 | joint_states_msgs.position.append(j5) 88 | joint_states_msgs.position.append(j6) 89 | joint_states_msgs.position.append(gripper) 90 | self.left_pub_joint.publish(joint_states_msgs) 91 | # self.rate.sleep() 92 | print("send joint control piper command") 93 | 94 | 95 | def right_joint_control_piper(self,j1,j2,j3,j4,j5,j6,gripper): 96 | joint_states_msgs = JointState() 97 | joint_states_msgs.header = Header() 98 | joint_states_msgs.header.stamp = rospy.Time.now() 99 | joint_states_msgs.name = [f'joint{i+1}' for i in range(7)] 100 | joint_states_msgs.position.append(j1) 101 | joint_states_msgs.position.append(j2) 102 | joint_states_msgs.position.append(j3) 103 | joint_states_msgs.position.append(j4) 104 | joint_states_msgs.position.append(j5) 105 | joint_states_msgs.position.append(j6) 106 | joint_states_msgs.position.append(gripper) 107 | self.right_pub_joint.publish(joint_states_msgs) 108 | # self.rate.sleep() 109 | print("send joint control piper command") 110 | 111 | 112 | 113 | # test code 114 | # if __name__ == '__main__': 115 | # piper = PIPER() 116 | # rospy.init_node('control_piper_node', anonymous=True) 117 | # piper.control_piper(0.0,0.0,0.0,0.0,0.0,0.0,0.05) 118 | # piper.init_pose() 119 | # 保持节点运行并监听外部程序的调用 120 | # rospy.spin() 121 | -------------------------------------------------------------------------------- /src/oculus_reader/scripts/teleop_single_piper.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import rospy 3 | import tf2_ros 4 | import rospkg 5 | import geometry_msgs.msg 6 | from tf.transformations import quaternion_from_matrix 7 | from tf.transformations import quaternion_from_euler, quaternion_from_matrix 8 | 9 | import casadi 10 | import meshcat.geometry as mg 11 | import pinocchio as pin 12 | from pinocchio import casadi as cpin 13 | from pinocchio.visualize import MeshcatVisualizer 14 | from oculus_reader import OculusReader 15 | 16 | import os 17 | import numpy as np 18 | import math 19 | 20 | from tools import MATHTOOLS 21 | from piper_control import PIPER 22 | 23 | def matrix_to_xyzrpy(matrix): 24 | x = matrix[0, 3] 25 | y = matrix[1, 3] 26 | z = matrix[2, 3] 27 | roll = math.atan2(matrix[2, 1], matrix[2, 2]) 28 | pitch = math.asin(-matrix[2, 0]) 29 | yaw = math.atan2(matrix[1, 0], matrix[0, 0]) 30 | return [x, y, z, roll, pitch, yaw] 31 | 32 | 33 | def create_transformation_matrix(x, y, z, roll, pitch, yaw): 34 | transformation_matrix = np.eye(4) 35 | A = np.cos(yaw) 36 | B = np.sin(yaw) 37 | C = np.cos(pitch) 38 | D = np.sin(pitch) 39 | E = np.cos(roll) 40 | F = np.sin(roll) 41 | DE = D * E 42 | DF = D * F 43 | transformation_matrix[0, 0] = A * C 44 | transformation_matrix[0, 1] = A * DF - B * E 45 | transformation_matrix[0, 2] = B * F + A * DE 46 | transformation_matrix[0, 3] = x 47 | transformation_matrix[1, 0] = B * C 48 | transformation_matrix[1, 1] = A * E + B * DF 49 | transformation_matrix[1, 2] = B * DE - A * F 50 | transformation_matrix[1, 3] = y 51 | transformation_matrix[2, 0] = -D 52 | transformation_matrix[2, 1] = C * F 53 | transformation_matrix[2, 2] = C * E 54 | transformation_matrix[2, 3] = z 55 | transformation_matrix[3, 0] = 0 56 | transformation_matrix[3, 1] = 0 57 | transformation_matrix[3, 2] = 0 58 | transformation_matrix[3, 3] = 1 59 | return transformation_matrix 60 | 61 | def calc_pose_incre(base_pose, pose_data): 62 | begin_matrix = create_transformation_matrix(base_pose[0], base_pose[1], base_pose[2], 63 | base_pose[3], base_pose[4], base_pose[5]) 64 | zero_matrix = create_transformation_matrix(0.19, 0.0, 0.2, 0, 0, 0) 65 | end_matrix = create_transformation_matrix(pose_data[0], pose_data[1], pose_data[2], 66 | pose_data[3], pose_data[4], pose_data[5]) 67 | result_matrix = np.dot(zero_matrix, np.dot(np.linalg.inv(begin_matrix), end_matrix)) 68 | xyzrpy = matrix_to_xyzrpy(result_matrix) 69 | return xyzrpy 70 | 71 | class Arm_IK: 72 | def __init__(self): 73 | np.set_printoptions(precision=5, suppress=True, linewidth=200) 74 | 75 | rospack = rospkg.RosPack() 76 | package_path = rospack.get_path('piper_description') 77 | 78 | urdf_path = os.path.join(package_path, 'urdf', 'piper_description.urdf') 79 | 80 | self.robot = pin.RobotWrapper.BuildFromURDF(urdf_path) 81 | 82 | self.mixed_jointsToLockIDs = ["joint7", 83 | "joint8" 84 | ] 85 | 86 | self.reduced_robot = self.robot.buildReducedRobot( 87 | list_of_joints_to_lock=self.mixed_jointsToLockIDs, 88 | reference_configuration=np.array([0] * self.robot.model.nq), 89 | ) 90 | 91 | self.first_matrix = create_transformation_matrix(0, 0, 0, 0, -1.57, 0) 92 | self.second_matrix = create_transformation_matrix(0.13, 0.0, 0.0, 0, 0, 0) #第六轴到末端夹爪坐标的变换矩阵 93 | self.last_matrix = np.dot(self.first_matrix, self.second_matrix) 94 | q = quaternion_from_matrix(self.last_matrix) 95 | self.reduced_robot.model.addFrame( 96 | pin.Frame('ee', 97 | self.reduced_robot.model.getJointId('joint6'), 98 | pin.SE3( 99 | # pin.Quaternion(1, 0, 0, 0), 100 | pin.Quaternion(q[3], q[0], q[1], q[2]), 101 | np.array([self.last_matrix[0, 3], self.last_matrix[1, 3], self.last_matrix[2, 3]]), # -y 102 | ), 103 | pin.FrameType.OP_FRAME) 104 | ) 105 | 106 | self.geom_model = pin.buildGeomFromUrdf(self.robot.model, urdf_path, pin.GeometryType.COLLISION) 107 | for i in range(4, 9): 108 | for j in range(0, 3): 109 | self.geom_model.addCollisionPair(pin.CollisionPair(i, j)) 110 | self.geometry_data = pin.GeometryData(self.geom_model) 111 | 112 | self.init_data = np.zeros(self.reduced_robot.model.nq) 113 | self.history_data = np.zeros(self.reduced_robot.model.nq) 114 | 115 | # # Initialize the Meshcat visualizer for visualization 116 | self.vis = MeshcatVisualizer(self.reduced_robot.model, self.reduced_robot.collision_model, self.reduced_robot.visual_model) 117 | self.vis.initViewer(open=True) 118 | self.vis.loadViewerModel("pinocchio") 119 | self.vis.displayFrames(True, frame_ids=[113, 114], axis_length=0.15, axis_width=5) 120 | self.vis.display(pin.neutral(self.reduced_robot.model)) 121 | 122 | # Enable the display of end effector target frames with short axis lengths and greater width. 123 | frame_viz_names = ['ee_target'] 124 | FRAME_AXIS_POSITIONS = ( 125 | np.array([[0, 0, 0], [1, 0, 0], 126 | [0, 0, 0], [0, 1, 0], 127 | [0, 0, 0], [0, 0, 1]]).astype(np.float32).T 128 | ) 129 | FRAME_AXIS_COLORS = ( 130 | np.array([[1, 0, 0], [1, 0.6, 0], 131 | [0, 1, 0], [0.6, 1, 0], 132 | [0, 0, 1], [0, 0.6, 1]]).astype(np.float32).T 133 | ) 134 | axis_length = 0.1 135 | axis_width = 10 136 | for frame_viz_name in frame_viz_names: 137 | self.vis.viewer[frame_viz_name].set_object( 138 | mg.LineSegments( 139 | mg.PointsGeometry( 140 | position=axis_length * FRAME_AXIS_POSITIONS, 141 | color=FRAME_AXIS_COLORS, 142 | ), 143 | mg.LineBasicMaterial( 144 | linewidth=axis_width, 145 | vertexColors=True, 146 | ), 147 | ) 148 | ) 149 | 150 | # Creating Casadi models and data for symbolic computing 151 | self.cmodel = cpin.Model(self.reduced_robot.model) 152 | self.cdata = self.cmodel.createData() 153 | 154 | # Creating symbolic variables 155 | self.cq = casadi.SX.sym("q", self.reduced_robot.model.nq, 1) 156 | self.cTf = casadi.SX.sym("tf", 4, 4) 157 | cpin.framesForwardKinematics(self.cmodel, self.cdata, self.cq) 158 | 159 | # # Get the hand joint ID and define the error function 160 | self.gripper_id = self.reduced_robot.model.getFrameId("ee") 161 | self.error = casadi.Function( 162 | "error", 163 | [self.cq, self.cTf], 164 | [ 165 | casadi.vertcat( 166 | cpin.log6( 167 | self.cdata.oMf[self.gripper_id].inverse() * cpin.SE3(self.cTf) 168 | ).vector, 169 | ) 170 | ], 171 | ) 172 | 173 | # Defining the optimization problem 174 | self.opti = casadi.Opti() 175 | self.var_q = self.opti.variable(self.reduced_robot.model.nq) 176 | # self.var_q_last = self.opti.parameter(self.reduced_robot.model.nq) # for smooth 177 | self.param_tf = self.opti.parameter(4, 4) 178 | 179 | # self.totalcost = casadi.sumsqr(self.error(self.var_q, self.param_tf)) 180 | # self.regularization = casadi.sumsqr(self.var_q) 181 | 182 | error_vec = self.error(self.var_q, self.param_tf) 183 | pos_error = error_vec[:3] 184 | ori_error = error_vec[3:] 185 | weight_position = 1.0 186 | weight_orientation = 0.1 187 | self.totalcost = casadi.sumsqr(weight_position * pos_error) + casadi.sumsqr(weight_orientation * ori_error) 188 | self.regularization = casadi.sumsqr(self.var_q) 189 | 190 | # Setting optimization constraints and goals 191 | self.opti.subject_to(self.opti.bounded( 192 | self.reduced_robot.model.lowerPositionLimit, 193 | self.var_q, 194 | self.reduced_robot.model.upperPositionLimit) 195 | ) 196 | # print("self.reduced_robot.model.lowerPositionLimit:", self.reduced_robot.model.lowerPositionLimit) 197 | # print("self.reduced_robot.model.upperPositionLimit:", self.reduced_robot.model.upperPositionLimit) 198 | self.opti.minimize(20 * self.totalcost + 0.01 * self.regularization) 199 | # self.opti.minimize(20 * self.totalcost + 0.01 * self.regularization + 0.1 * self.smooth_cost) # for smooth 200 | 201 | opts = { 202 | 'ipopt': { 203 | 'print_level': 0, 204 | 'max_iter': 50, 205 | 'tol': 1e-4 206 | }, 207 | 'print_time': False 208 | } 209 | self.opti.solver("ipopt", opts) 210 | 211 | def ik_fun(self, target_pose, gripper=0, motorstate=None, motorV=None): 212 | gripper = np.array([gripper/2.0, -gripper/2.0]) 213 | if motorstate is not None: 214 | self.init_data = motorstate 215 | self.opti.set_initial(self.var_q, self.init_data) 216 | 217 | self.vis.viewer['ee_target'].set_transform(target_pose) # for visualization 218 | 219 | self.opti.set_value(self.param_tf, target_pose) 220 | # self.opti.set_value(self.var_q_last, self.init_data) # for smooth 221 | 222 | try: 223 | # sol = self.opti.solve() 224 | sol = self.opti.solve_limited() 225 | sol_q = self.opti.value(self.var_q) 226 | 227 | if self.init_data is not None: 228 | max_diff = max(abs(self.history_data - sol_q)) 229 | # print("max_diff:", max_diff) 230 | self.init_data = sol_q 231 | if max_diff > 30.0/180.0*3.1415: 232 | # print("Excessive changes in joint angle:", max_diff) 233 | self.init_data = np.zeros(self.reduced_robot.model.nq) 234 | else: 235 | self.init_data = sol_q 236 | self.history_data = sol_q 237 | 238 | self.vis.display(sol_q) # for visualization 239 | 240 | if motorV is not None: 241 | v = motorV * 0.0 242 | else: 243 | v = (sol_q - self.init_data) * 0.0 244 | 245 | tau_ff = pin.rnea(self.reduced_robot.model, self.reduced_robot.data, sol_q, v, 246 | np.zeros(self.reduced_robot.model.nv)) 247 | 248 | is_collision = self.check_self_collision(sol_q, gripper) 249 | dist = self.get_dist(sol_q, target_pose[:3, 3]) 250 | # print("dist:", dist) 251 | return sol_q, tau_ff, not is_collision 252 | 253 | except Exception as e: 254 | print(f"ERROR in convergence, plotting debug info.{e}") 255 | # sol_q = self.opti.debug.value(self.var_q) # return original value 256 | return None, '', False 257 | 258 | def check_self_collision(self, q, gripper=np.array([0, 0])): 259 | pin.forwardKinematics(self.robot.model, self.robot.data, np.concatenate([q, gripper], axis=0)) 260 | pin.updateGeometryPlacements(self.robot.model, self.robot.data, self.geom_model, self.geometry_data) 261 | collision = pin.computeCollisions(self.geom_model, self.geometry_data, False) 262 | # print("collision:", collision) 263 | return collision 264 | 265 | def get_dist(self, q, xyz): 266 | # print("q:", q) 267 | pin.forwardKinematics(self.reduced_robot.model, self.reduced_robot.data, np.concatenate([q], axis=0)) 268 | dist = math.sqrt(pow((xyz[0] - self.reduced_robot.data.oMi[6].translation[0]), 2) + pow((xyz[1] - self.reduced_robot.data.oMi[6].translation[1]), 2) + pow((xyz[2] - self.reduced_robot.data.oMi[6].translation[2]), 2)) 269 | return dist 270 | 271 | def get_pose(self, q): 272 | index = 6 273 | pin.forwardKinematics(self.reduced_robot.model, self.reduced_robot.data, np.concatenate([q], axis=0)) 274 | end_pose = create_transformation_matrix(self.reduced_robot.data.oMi[index].translation[0], self.reduced_robot.data.oMi[index].translation[1], self.reduced_robot.data.oMi[index].translation[2], 275 | math.atan2(self.reduced_robot.data.oMi[index].rotation[2, 1], self.reduced_robot.data.oMi[index].rotation[2, 2]), 276 | math.asin(-self.reduced_robot.data.oMi[index].rotation[2, 0]), 277 | math.atan2(self.reduced_robot.data.oMi[index].rotation[1, 0], self.reduced_robot.data.oMi[index].rotation[0, 0])) 278 | end_pose = np.dot(end_pose, self.last_matrix) 279 | return matrix_to_xyzrpy(end_pose) 280 | 281 | 282 | class VR: 283 | def __init__(self): 284 | rospy.init_node('oculus_reader') 285 | self.piper_control = PIPER() 286 | self.tools = MATHTOOLS() 287 | self.inverse_solution = Arm_IK() 288 | self.piper_control.init_pose() 289 | 290 | def adjustment_matrix(self,transform): 291 | 292 | if transform.shape != (4, 4): 293 | raise ValueError("Input transform must be a 4x4 numpy array.") 294 | 295 | adj_mat = np.array([ 296 | [0,0,-1,0], 297 | [-1,0,0,0], 298 | [0,1,0,0], 299 | [0,0,0,1] 300 | ]) 301 | 302 | r_adj = self.tools.xyzrpy2Mat(0,0,0, -np.pi , 0, -np.pi/2) 303 | 304 | transform = adj_mat @ transform 305 | 306 | transform = np.dot(transform, r_adj) 307 | 308 | return transform 309 | 310 | def publish_transform(self,transform, name): 311 | translation = transform[:3, 3] 312 | 313 | br = tf2_ros.TransformBroadcaster() 314 | t = geometry_msgs.msg.TransformStamped() 315 | 316 | t.header.stamp = rospy.Time.now() 317 | t.header.frame_id = 'vr_device' 318 | t.child_frame_id = name 319 | t.transform.translation.x = translation[0] 320 | t.transform.translation.y = translation[1] 321 | t.transform.translation.z = translation[2] 322 | 323 | quat = quaternion_from_matrix(transform) 324 | t.transform.rotation.x = quat[0] 325 | t.transform.rotation.y = quat[1] 326 | t.transform.rotation.z = quat[2] 327 | t.transform.rotation.w = quat[3] 328 | 329 | br.sendTransform(t) 330 | 331 | 332 | def get_ik_solution(self, x,y,z,roll,pitch,yaw,gripper,b): 333 | 334 | q = quaternion_from_euler(roll, pitch, yaw) 335 | target = pin.SE3( 336 | pin.Quaternion(q[3], q[0], q[1], q[2]), 337 | np.array([x, y, z]), 338 | ) 339 | sol_q, tau_ff, is_collision = self.inverse_solution.ik_fun(target.homogeneous,0) 340 | # print("result:", sol_q) 341 | 342 | if b : 343 | self.piper_control.joint_control_piper(sol_q[0],sol_q[1],sol_q[2],sol_q[3],sol_q[4],sol_q[5],gripper) 344 | print("ctrolling!!!") 345 | # else : 346 | # print("collision!!!") 347 | 348 | def Run(self): 349 | # 这里可选为 WIFI连接 或 USB连接 350 | # oculus_reader = OculusReader(ip_address='10.12.11.14') # WIFI连接 351 | oculus_reader = OculusReader() # USB连接 352 | 353 | 354 | rate = rospy.Rate(50) 355 | 356 | # 夹爪坐标系到到基坐标系的变换 357 | base_RR = [0.19, 0.0, 0.2, 0, 0, 0] 358 | 359 | while not rospy.is_shutdown(): 360 | rate.sleep() 361 | transformations, buttons = oculus_reader.get_transformations_and_buttons() 362 | if 'r' not in transformations : 363 | continue 364 | 365 | transformations['r'] = self.adjustment_matrix(transformations['r']) 366 | 367 | right_controller_pose = transformations['r'] 368 | 369 | self.publish_transform(right_controller_pose, 'right_hand') 370 | 371 | RR = self.tools.matrix2Pose(transformations['r']) 372 | 373 | if buttons['A'] == True : 374 | # 按下A键后,机械臂回到初始点位并且记录 右 坐标原点 375 | self.piper_control.init_pose() 376 | base_RR = self.tools.matrix2Pose(transformations['r']) 377 | 378 | RR_ = calc_pose_incre(base_RR,RR) 379 | 380 | r_gripper_value = buttons['rightTrig'][0] * 0.07 381 | # 按下B键后,开始遥操作 382 | self.get_ik_solution(RR_[0],RR_[1],RR_[2],RR_[3],RR_[4],RR_[5],r_gripper_value,buttons['B']) 383 | 384 | if __name__ == '__main__': 385 | vr = VR() 386 | vr.Run() 387 | 388 | -------------------------------------------------------------------------------- /src/oculus_reader/scripts/tools.py: -------------------------------------------------------------------------------- 1 | import math 2 | import numpy as np 3 | from tf.transformations import (quaternion_from_matrix, euler_from_matrix, 4 | quaternion_from_euler, euler_from_quaternion) 5 | 6 | class MATHTOOLS: 7 | 8 | # 从xyzrpy创建旋转矩阵 9 | def xyzrpy2Mat(self,x, y, z, roll, pitch, yaw): 10 | transformation_matrix = np.eye(4) 11 | A = np.cos(yaw) 12 | B = np.sin(yaw) 13 | C = np.cos(pitch) 14 | D = np.sin(pitch) 15 | E = np.cos(roll) 16 | F = np.sin(roll) 17 | DE = D * E 18 | DF = D * F 19 | transformation_matrix[0, 0] = A * C 20 | transformation_matrix[0, 1] = A * DF - B * E 21 | transformation_matrix[0, 2] = B * F + A * DE 22 | transformation_matrix[0, 3] = x 23 | transformation_matrix[1, 0] = B * C 24 | transformation_matrix[1, 1] = A * E + B * DF 25 | transformation_matrix[1, 2] = B * DE - A * F 26 | transformation_matrix[1, 3] = y 27 | transformation_matrix[2, 0] = -D 28 | transformation_matrix[2, 1] = C * F 29 | transformation_matrix[2, 2] = C * E 30 | transformation_matrix[2, 3] = z 31 | transformation_matrix[3, 0] = 0 32 | transformation_matrix[3, 1] = 0 33 | transformation_matrix[3, 2] = 0 34 | transformation_matrix[3, 3] = 1 35 | return transformation_matrix 36 | 37 | # 将矩阵转换为位姿 38 | def matrix2Pose(self,transform): 39 | # 提取平移部分 x, y, z 40 | x = transform[0, 3] 41 | y = transform[1, 3] 42 | z = transform[2, 3] 43 | 44 | # 提取旋转矩阵 45 | rotation_matrix = transform[:3, :3] 46 | 47 | # 将旋转矩阵转换为欧拉角 (roll, pitch, yaw) 48 | roll, pitch, yaw = euler_from_matrix(rotation_matrix) 49 | 50 | return x, y, z, roll, pitch, yaw 51 | 52 | def mat2xyzrpy(self,matrix): 53 | x = matrix[0, 3] 54 | y = matrix[1, 3] 55 | z = matrix[2, 3] 56 | roll = math.atan2(matrix[2, 1], matrix[2, 2]) 57 | pitch = math.asin(-matrix[2, 0]) 58 | yaw = math.atan2(matrix[1, 0], matrix[0, 0]) 59 | return [x, y, z, roll, pitch, yaw] 60 | 61 | def xyzQuaternion2matrix(x, y, z, qx, qy, qz, qw): 62 | # 四元数到旋转矩阵:根据标准公式,将四元数分量转换为一个 3x3 的旋转矩阵。 63 | R = np.array([ 64 | [1 - 2 * (qy ** 2 + qz ** 2), 2 * (qx * qy - qz * qw), 2 * (qx * qz + qy * qw)], 65 | [2 * (qx * qy + qz * qw), 1 - 2 * (qx ** 2 + qz ** 2), 2 * (qy * qz - qx * qw)], 66 | [2 * (qx * qz - qy * qw), 2 * (qy * qz + qx * qw), 1 - 2 * (qx ** 2 + qy ** 2)] 67 | ]) 68 | 69 | # 构造齐次变换矩阵:在右下角补上 1,在第四列填入位置向量 [x, y, z]。 70 | T = np.eye(4) 71 | T[:3, :3] = R 72 | T[:3, 3] = [x, y, z] 73 | 74 | return T --------------------------------------------------------------------------------