Coppeliasim-Python provides users an easy tool to manipulate robots in CoppeliaSim with SpaceMouse (3D Mouse).
- hidapi python package.
pip install hidapi - udev system:
sudo apt-get install libhidapi-dev
udev rules: In order for hidapi to open the device without sudo, we need to do the following steps. First of all, create a rule file xx-spacemouse.rules under the folder /etc/udev/rules.d/ (Replace xx with a number larger than 50).
sudo touch /etc/udev/rules.d/77-spacemouse.rules
echo "KERNEL==\"hidraw*\", ATTRS{idVendor}==\"256f\", ATTRS{idProduct}==\"c62e\", MODE=\"0666\", GROUP=\"plugdev\"" > /etc/udev/rules.d/77-spacemouse.rules
echo "SUBSYSTEM==\"usb\", ATTRS{idVendor}==\"256f\", ATTRS{idProduct}==\"c62e\", MODE=\"0666\", GROUP=\"plugdev\"" >> /etc/udev/rules.d/77-spacemouse.rulesThen we need to reload the defined udev rule to take effect. Reload can be done through:
$ sudo udevadm control --reload-rulesGet vendor_id and product_id of your Spacemouse.
import hid
hid.enumerate()The python code above will print all HID information, just locate the information about SpaceMouse.
$ python common/spacemouse.py- Open
example/iiwa7.tttwith CoppeliaSim. - Start simulation.
$ python test/simTest.py- KUKA LBR iiwa 7 R800;
- Robotiq85;
- SpaceMouse Wireless;
- real_env (main threading): Get observations, send commands to child threading, and recording videos, actions and observations.
- iiwaPy3 (Child threading): Execute commands, and update shared memory.
- robotiq85 (Child threading): Execute commands, and update shared memory.
- multirealsense (Multi child threading): Execute commands, and update shared memory.
- spacemouse (main threading): Update shared memory.
- keyboard (main threading): Update stage (stage means how many parts that the whole episode can be separated.)
In demo_real_robot.py, c refers to starting recording a new episode, s refers to ending one episode, and q means quitting the process. There uses data from spacemouse as delta pose and regards the transformed pose as the next step action, then the next step action will call execute_actions in real_env.py to control child threading.
Function get_obs from real_env.py will also recall its child threading function to get observations, and finally save them in Dict. After ending one episode, the Dict will be saved in the shared memory.
In order to run the data collection code, execute the example command below:
python demo_real_robot.py -o "data/test_data" --robot_ip "172.31.1.147" --robot_port 30001The saved data form is like below:
- data
- action
- timestamps
- stage
- eef_rot
- eef_pos
- joints_pos
- meta
- episode_ends
- videos
How to obtain target_pose/action?
# current EEF pose (without any transformation)
target_pose
# spacemouse states
sm_state = sm.get_motion_state_transformed()
## scale spacemouse states
dpos = (
sm_state[:3] * (env.max_pos_speed / frequency) * pos_sensitivity
)
drot_xyz = (
sm_state[3:]
* (env.max_rot_speed / frequency)
* np.array([1, 1, -1])
* rot_sensitivity
)
## spacemouse euler -> quat
drot = st.Rotation.from_euler("xyz", drot_xyz)
# target EEF pos = current EEF pos + dpos
target_pose[:3] += dpos
# target EEF rot = drot * current EEF rot quat
target_pose[3:] = (
drot * st.Rotation.from_euler("zyx", target_pose[3:])
).as_euler("zyx")The final target_pose is our next step action, and then we send this command to instruct remoter to move, and final reply an actual EEF pose to client. Below is a example of target pose and difference between actual EEF pose and target pose.
[614.42 -2.24 318.24 3.14 -0. 3.14] | [-0.03 0.24 0.55 -0. -0. 0. ]
[614.42 -1.88 319.11 3.14 -0. 3.14] | [-0.05 0.26 0.56 -0. -0. 0. ]
[614.42 -1.5 319.98 3.14 -0. 3.14] | [-0.03 0.26 0.68 0. 0. 0. ]
[614.42 -1.12 320.8 3.14 -0. 3.14] | [ 0.01 0.26 0.67 -0. 0. 0. ]
[614.42 -0.74 321.56 3.14 -0. 3.14] | [ 0.02 0.27 0.51 -0. 0. 0. ]
[614.42 -0.38 322.31 3.14 -0. 3.14] | [ 0.02 0.27 0.46 0. -0. 0. ]
[614.42 -0.05 322.92 3.14 -0. 3.14] | [ 0.02 0.2 0.42 -0. 0. 0. ]
[614.42 0.19 323.39 3.14 -0. 3.14] | [-0.04 0.17 0.32 -0. -0. 0. ]
[614.42 0.34 323.67 3.14 -0. 3.14] | [-0.06 0.18 0.25 -0. -0. 0. ]
Add some supplement files in diffusion_policy. (Before doing this, make sure you've already read README.md of diffusion_policy. )
[KUKA-Controller] $ cp codebase/sup_files/dataset/real_lift_image_dataset.py codebase/diffusion_policy/diffusion_policy/dataset
[KUKA-Controller] $ cp codebase/sup_files/config/task/real_pusht_image.yaml codebase/diffusion_policy/diffusion_policy/dataset/config/taskThe modify the config files including specific task name and dataset path. For example, if you decide to train your model with train_diffusion_transformer_real_hybrid_workspace.yaml, first you need to replace task: real_pusht_image with task: real_pusht_image, then replace dataset_path with your desired path in real_pusht_image.yaml.
Just use Diffusion Policy to train that model with our collected data.
[KUKA-Controller/codebase/diffusion_policy] $ python train.py --config-dir=. --config-name=<ws_cfg_file>The inference loop can be demomstrated below:
# load chechpoint
# checkpoint to policy
# Policy control loop
## get observations
## run inference
## convert policy action to env actions
## clip action
## execute actionspython eval_real_robot.py --input_path <ckpt_path> --output_path <opt_dir>Synchronize the Speend of Remoter and Client
Assume that we have below in remoter:
Assume that we have below in client,
- Implement base robot controlling class.
- Implement SpaceMouse API to control iiwa.
- thread to listen SpaceMouse
- Dof controlling
- Button controlling, i.e restart or grip
- callback
- grip controlling
- reset
- Real world. (Real machine control)
- SpaceMouse
- RealSense Camera
- Gripper
- Data Collection
NOT IMPORTANT:
- Implement keyboard control.
- Robot, Gripper, data collector, every of these parts need to hybrid from threading.