Skip to content

Commit 3ff3694

Browse files
author
xudong liu
committed
Merge branch 'liuxd/add_control_tool' into 'master'
add control tool See merge request io/io_dev_tools_ros2!3
2 parents cd136e8 + 42ece3d commit 3ff3694

9 files changed

Lines changed: 763 additions & 64 deletions

File tree

io_control/README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# io_control
2+
io控制相关工具
3+
4+
## io_control_joint
5+
周期性发布joint command
6+
```bash
7+
python3 <your_package_dir>/src/io_dev_tools_ros2/io_control/script/io_control_joint.py
8+
```

io_control/config/tool.yml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
rate: 100
2+
joint_target: "/io_teleop/target_joint_from_mocap"
3+
joint_cmd: "/io_teleop/joint_cmd"
4+
joint_state: "/io_teleop/joint_states"
5+
ee_target: "/io_teleop/target_ee_poses"
6+
ee_state: "/io_teleop/state_ee_poses"
7+
control_type: "joint"
8+
control_joints:
9+
# type sine step ramp
10+
# waist_yaw_joint:
11+
# type: "sine"
12+
# magnitude: 0.5
13+
# frequence: 0.2
14+
waist_roll_joint:
15+
type: "sine"
16+
magnitude: 0.5
17+
frequence: 0.2
18+
waist_pitch_joint:
19+
type: "sine"
20+
magnitude: 0.5
21+
frequence: 0.2
22+
23+
24+
control_ee:
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
#!/usr/bin/env python3
2+
import rclpy
3+
from rclpy.node import Node
4+
5+
import numpy as np
6+
import threading
7+
import os
8+
import yaml
9+
import time
10+
import math
11+
12+
import geometry_msgs.msg
13+
import sensor_msgs.msg
14+
15+
16+
def sort_list(list_target, list_source, list_in):
17+
assert set(list_target) <= set(list_source)
18+
mapping = dict(zip(list_source, list_in))
19+
return np.array([mapping[i] for i in list_target])
20+
21+
22+
def jpos_to_msg(q, name_list):
23+
msg = sensor_msgs.msg.JointState()
24+
msg.name = name_list
25+
msg.position = q
26+
return msg
27+
28+
29+
def msg_to_jpos(msg, name_list):
30+
return sort_list(name_list, msg.name, msg.position)
31+
32+
33+
class ControlROS(Node):
34+
def __init__(self, controller_file) -> None:
35+
super().__init__("robot_control_tool")
36+
37+
with open(controller_file, "r", encoding="utf-8") as file:
38+
config = yaml.safe_load(file)
39+
self.control_joint = config["control_joints"]
40+
self.joint_name = self.control_joint.keys()
41+
self.joint_command = None
42+
self.joint_command_stamp = None
43+
self.joint_state = None
44+
self.init_flag = False
45+
self.msg = None
46+
self.dt = 1 / config["rate"]
47+
self.t = 0
48+
49+
# ROS2
50+
self.rate = self.create_rate(config["rate"])
51+
self.joint_state_sub = self.create_subscription(
52+
sensor_msgs.msg.JointState,
53+
config["joint_state"],
54+
self.joint_state_callback,
55+
10,
56+
)
57+
self.ee_state_sub = self.create_subscription(
58+
geometry_msgs.msg.PoseArray, config["ee_state"], self.ee_state_callback, 10
59+
)
60+
61+
self.joint_cmd_pub = self.create_publisher(
62+
sensor_msgs.msg.JointState, config["joint_cmd"], 10
63+
)
64+
65+
update_robot_cmd = threading.Thread(target=self.update_robot_cmd)
66+
update_robot_cmd.daemon = True
67+
update_robot_cmd.start()
68+
69+
def joint_state_callback(self, msg):
70+
self.joint_state = np.array(msg_to_jpos(msg, self.joint_name))
71+
if not self.init_flag:
72+
self.joint_command_stamp = list(self.joint_state)
73+
self.joint_command = list(self.joint_state)
74+
self.init_flag = True
75+
76+
def ee_state_callback(self, msg):
77+
pass
78+
79+
def update_robot_cmd(self):
80+
while rclpy.ok():
81+
if not self.init_flag:
82+
continue
83+
# pub joint command
84+
if self.msg is not None:
85+
self.msg.header.stamp = self.get_clock().now().to_msg()
86+
self.joint_cmd_pub.publish(self.msg)
87+
self.t += self.dt
88+
89+
for idx, joint in enumerate(self.control_joint.values()):
90+
mag = joint["magnitude"]
91+
f = joint["frequence"]
92+
if joint["type"] == "sine":
93+
self.joint_command[idx] = self.joint_command_stamp[
94+
idx
95+
] + mag * math.sin(2 * math.pi * f * self.t)
96+
if joint["type"] == "step":
97+
self.joint_command[idx] = self.joint_command_stamp[idx] + mag * (
98+
int(self.t * f * 2) % 2 * -2 + 1
99+
)
100+
if joint["type"] == "ramp":
101+
self.joint_command[idx] = (
102+
self.joint_command_stamp[idx]
103+
+ 2 * mag * abs((self.t * f % 1) / 0.5 - 1)
104+
- mag
105+
)
106+
self.msg = jpos_to_msg(self.joint_command, self.joint_name)
107+
108+
self.rate.sleep()
109+
110+
111+
def main(args=None):
112+
rclpy.init(args=args)
113+
114+
config_file = os.path.join(os.path.dirname(__file__), "../config/" + "tool.yml")
115+
control_ros = ControlROS(config_file)
116+
117+
rclpy.spin(control_ros)
118+
119+
control_ros.destroy_node()
120+
rclpy.shutdown()
121+
122+
123+
if __name__ == "__main__":
124+
main()

io_mocap/README.md

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,25 @@ io数据相关工具
33

44
## visulization launch
55
用于io数据数据可视化
6-
```
6+
```bash
77
source install/setup.bash
88
```
99

1010
io动捕数据可视化
11-
```
11+
```bash
1212
ros2 launch io_mocap human_vis.launch.py
1313
```
1414
手部外骨骼数据可视化
15-
```
15+
```bash
1616
ros2 launch io_mocap exoskeleton_vis.launch.py
1717
```
1818

19-
## xsens io data adapt
19+
## xsens to io mocap data adapt(offline)
2020
xsens数据转化为io数据,并将转化后数据以/io_fusion/tf对外发布
21+
```bash
22+
python3 <your_package_dir>/src/io_dev_tools_ros2/io_mocap/script/xsens_io_adapter_offline.py <your_xsen_file_path>
2123
```
22-
python3 <your_package_dir>/src/io_dev_tools_ros2/io_mocap/script/xsens_io_adapter_offline.py
23-
```
24-
```
25-
ros2 launch io_mocap human_vis.launch.py
24+
## pico tracker to io mocap data adapt(online)
25+
```bash
26+
python3 src/io_dev_tools_ros2/io_mocap/script/pico_io_adapter_online.py
2627
```

0 commit comments

Comments
 (0)