From 1197f66f90e26a4428e954f19968c163fd5d1ecf Mon Sep 17 00:00:00 2001 From: haotian <2421912570@qq.com> Date: Tue, 8 Jul 2025 17:29:02 +0800 Subject: [PATCH] first commit --- LICENSE | 29 ++ README zh.md | 121 +++++ README.md | 118 +++++ doc/运行教程.md | 21 + example/b2/camera/camera_opencv.py | 51 ++ example/b2/camera/capture_image.py | 51 ++ example/b2/high_level/b2_sport_client.py | 105 +++++ example/b2/low_level/b2_stand_example.py | 175 +++++++ example/b2/low_level/unitree_legged_const.py | 20 + example/b2w/camera/camera_opencv.py | 51 ++ example/b2w/camera/capture_image.py | 51 ++ example/b2w/high_level/b2w_sport_client.py | 101 ++++ example/b2w/low_level/b2w_stand_example.py | 196 ++++++++ example/b2w/low_level/unitree_legged_const.py | 24 + example/g1/audio/g1_audio_client_example.py | 44 ++ .../g1/high_level/g1_arm5_sdk_dds_example.py | 192 ++++++++ .../g1/high_level/g1_arm7_sdk_dds_example.py | 194 ++++++++ .../g1/high_level/g1_arm_action_example.py | 141 ++++++ .../g1/high_level/g1_loco_client_example.py | 117 +++++ example/g1/low_level/g1_low_level_example.py | 205 ++++++++ example/g1/readme.md | 5 + example/go2/front_camera/camera_opencv.py | 41 ++ example/go2/front_camera/capture_image.py | 30 ++ example/go2/high_level/go2_sport_client.py | 170 +++++++ example/go2/high_level/go2_utlidar_switch.py | 39 ++ example/go2/low_level/go2_stand_example.py | 176 +++++++ example/go2/low_level/unitree_legged_const.py | 20 + example/go2w/high_level/go2w_sport_client.py | 99 ++++ example/go2w/low_level/go2w_stand_example.py | 196 ++++++++ .../go2w/low_level/unitree_legged_const.py | 24 + .../h1/high_level/h1_loco_client_example.py | 96 ++++ example/h1/low_level/h1_low_level_example.py | 167 +++++++ example/h1/low_level/unitree_legged_const.py | 5 + .../h1_2/low_level/h1_2_low_level_example.py | 201 ++++++++ example/helloworld/publisher.py | 28 ++ example/helloworld/subscriber.py | 20 + example/helloworld/user_data.py | 9 + .../motionSwitcher/motion_switcher_example.py | 36 ++ .../obstacles_avoid/obstacles_avoid_move.py | 35 ++ .../obstacles_avoid/obstacles_avoid_switch.py | 94 ++++ example/vui_client/vui_client_example.py | 77 +++ .../wireless_controller.py | 131 +++++ pyproject.toml | 3 + setup.py | 21 + unitree_sdk2py/__init__.py | 10 + .../b2/back_video/back_video_api.py | 16 + .../b2/back_video/back_video_client.py | 23 + .../b2/front_video/front_video_api.py | 16 + .../b2/front_video/front_video_client.py | 23 + .../b2/robot_state/robot_state_api.py | 25 + .../b2/robot_state/robot_state_client.py | 84 ++++ unitree_sdk2py/b2/sport/sport_api.py | 58 +++ unitree_sdk2py/b2/sport/sport_client.py | 241 ++++++++++ unitree_sdk2py/b2/vui/vui_api.py | 21 + unitree_sdk2py/b2/vui/vui_client.py | 86 ++++ .../comm/motion_switcher/__init__.py | 0 .../motion_switcher/motion_switcher_api.py | 29 ++ .../motion_switcher/motion_switcher_client.py | 51 ++ unitree_sdk2py/core/__init__.py | 0 unitree_sdk2py/core/channel.py | 290 ++++++++++++ unitree_sdk2py/core/channel_config.py | 25 + unitree_sdk2py/core/channel_name.py | 34 ++ unitree_sdk2py/g1/arm/g1_arm_action_api.py | 19 + unitree_sdk2py/g1/arm/g1_arm_action_client.py | 56 +++ unitree_sdk2py/g1/audio/g1_audio_api.py | 24 + unitree_sdk2py/g1/audio/g1_audio_client.py | 62 +++ unitree_sdk2py/g1/loco/g1_loco_api.py | 32 ++ unitree_sdk2py/g1/loco/g1_loco_client.py | 127 +++++ unitree_sdk2py/go2/__init__.py | 0 .../go2/obstacles_avoid/__init__.py | 0 .../obstacles_avoid/obstacles_avoid_api.py | 19 + .../obstacles_avoid/obstacles_avoid_client.py | 60 +++ unitree_sdk2py/go2/robot_state/__init__.py | 0 .../go2/robot_state/robot_state_api.py | 25 + .../go2/robot_state/robot_state_client.py | 84 ++++ unitree_sdk2py/go2/sport/__init__.py | 0 unitree_sdk2py/go2/sport/sport_api.py | 74 +++ unitree_sdk2py/go2/sport/sport_client.py | 446 ++++++++++++++++++ unitree_sdk2py/go2/video/__init__.py | 0 unitree_sdk2py/go2/video/video_api.py | 16 + unitree_sdk2py/go2/video/video_client.py | 23 + unitree_sdk2py/go2/vui/__init__.py | 0 unitree_sdk2py/go2/vui/vui_api.py | 21 + unitree_sdk2py/go2/vui/vui_client.py | 86 ++++ unitree_sdk2py/h1/loco/h1_loco_api.py | 31 ++ unitree_sdk2py/h1/loco/h1_loco_client.py | 83 ++++ unitree_sdk2py/idl/__init__.py | 12 + .../idl/builtin_interfaces/__init__.py | 9 + .../idl/builtin_interfaces/msg/__init__.py | 9 + .../idl/builtin_interfaces/msg/dds_/_Time_.py | 28 ++ .../builtin_interfaces/msg/dds_/__init__.py | 9 + unitree_sdk2py/idl/default.py | 268 +++++++++++ unitree_sdk2py/idl/geometry_msgs/__init__.py | 9 + .../idl/geometry_msgs/msg/__init__.py | 9 + .../idl/geometry_msgs/msg/dds_/_Point32_.py | 29 ++ .../geometry_msgs/msg/dds_/_PointStamped_.py | 31 ++ .../idl/geometry_msgs/msg/dds_/_Point_.py | 29 ++ .../idl/geometry_msgs/msg/dds_/_Pose2D_.py | 29 ++ .../geometry_msgs/msg/dds_/_PoseStamped_.py | 32 ++ .../msg/dds_/_PoseWithCovarianceStamped_.py | 32 ++ .../msg/dds_/_PoseWithCovariance_.py | 28 ++ .../idl/geometry_msgs/msg/dds_/_Pose_.py | 28 ++ .../msg/dds_/_QuaternionStamped_.py | 32 ++ .../geometry_msgs/msg/dds_/_Quaternion_.py | 30 ++ .../geometry_msgs/msg/dds_/_TwistStamped_.py | 32 ++ .../msg/dds_/_TwistWithCovarianceStamped_.py | 32 ++ .../msg/dds_/_TwistWithCovariance_.py | 28 ++ .../idl/geometry_msgs/msg/dds_/_Twist_.py | 28 ++ .../idl/geometry_msgs/msg/dds_/_Vector3_.py | 29 ++ .../idl/geometry_msgs/msg/dds_/__init__.py | 23 + unitree_sdk2py/idl/nav_msgs/__init__.py | 9 + unitree_sdk2py/idl/nav_msgs/msg/__init__.py | 9 + .../idl/nav_msgs/msg/dds_/_MapMetaData_.py | 35 ++ .../idl/nav_msgs/msg/dds_/_OccupancyGrid_.py | 33 ++ .../idl/nav_msgs/msg/dds_/_Odometry_.py | 35 ++ .../idl/nav_msgs/msg/dds_/__init__.py | 11 + unitree_sdk2py/idl/sensor_msgs/__init__.py | 9 + .../idl/sensor_msgs/msg/__init__.py | 9 + .../dds_/PointField_Constants/_PointField_.py | 28 ++ .../msg/dds_/PointField_Constants/__init__.py | 9 + .../idl/sensor_msgs/msg/dds_/_PointCloud2_.py | 39 ++ .../idl/sensor_msgs/msg/dds_/_PointField_.py | 30 ++ .../idl/sensor_msgs/msg/dds_/__init__.py | 11 + unitree_sdk2py/idl/std_msgs/__init__.py | 9 + unitree_sdk2py/idl/std_msgs/msg/__init__.py | 9 + .../idl/std_msgs/msg/dds_/_Header_.py | 32 ++ .../idl/std_msgs/msg/dds_/_String_.py | 27 ++ .../idl/std_msgs/msg/dds_/__init__.py | 10 + unitree_sdk2py/idl/unitree_api/__init__.py | 9 + .../idl/unitree_api/msg/__init__.py | 9 + .../unitree_api/msg/dds_/_RequestHeader_.py | 29 ++ .../unitree_api/msg/dds_/_RequestIdentity_.py | 28 ++ .../unitree_api/msg/dds_/_RequestLease_.py | 27 ++ .../unitree_api/msg/dds_/_RequestPolicy_.py | 28 ++ .../idl/unitree_api/msg/dds_/_Request_.py | 28 ++ .../unitree_api/msg/dds_/_ResponseHeader_.py | 28 ++ .../unitree_api/msg/dds_/_ResponseStatus_.py | 27 ++ .../idl/unitree_api/msg/dds_/_Response_.py | 28 ++ .../idl/unitree_api/msg/dds_/__init__.py | 16 + unitree_sdk2py/idl/unitree_go/__init__.py | 9 + unitree_sdk2py/idl/unitree_go/msg/__init__.py | 9 + .../idl/unitree_go/msg/dds_/_AudioData_.py | 28 ++ .../idl/unitree_go/msg/dds_/_BmsCmd_.py | 28 ++ .../idl/unitree_go/msg/dds_/_BmsState_.py | 35 ++ .../idl/unitree_go/msg/dds_/_Error_.py | 28 ++ .../msg/dds_/_Go2FrontVideoData_.py | 30 ++ .../idl/unitree_go/msg/dds_/_HeightMap_.py | 33 ++ .../idl/unitree_go/msg/dds_/_IMUState_.py | 31 ++ .../unitree_go/msg/dds_/_InterfaceConfig_.py | 29 ++ .../idl/unitree_go/msg/dds_/_LidarState_.py | 43 ++ .../idl/unitree_go/msg/dds_/_LowCmd_.py | 40 ++ .../idl/unitree_go/msg/dds_/_LowState_.py | 48 ++ .../idl/unitree_go/msg/dds_/_MotorCmd_.py | 33 ++ .../idl/unitree_go/msg/dds_/_MotorCmds_.py | 23 + .../idl/unitree_go/msg/dds_/_MotorState_.py | 37 ++ .../idl/unitree_go/msg/dds_/_MotorStates_.py | 23 + .../idl/unitree_go/msg/dds_/_PathPoint_.py | 33 ++ .../idl/unitree_go/msg/dds_/_Req_.py | 28 ++ .../idl/unitree_go/msg/dds_/_Res_.py | 29 ++ .../unitree_go/msg/dds_/_SportModeState_.py | 42 ++ .../idl/unitree_go/msg/dds_/_TimeSpec_.py | 28 ++ .../idl/unitree_go/msg/dds_/_UwbState_.py | 43 ++ .../idl/unitree_go/msg/dds_/_UwbSwitch_.py | 27 ++ .../msg/dds_/_WirelessController_.py | 31 ++ .../idl/unitree_go/msg/dds_/__init__.py | 31 ++ unitree_sdk2py/idl/unitree_hg/.idlpy_manifest | 43 ++ unitree_sdk2py/idl/unitree_hg/__init__.py | 9 + .../idl/unitree_hg/msg/.idlpy_manifest | 43 ++ unitree_sdk2py/idl/unitree_hg/msg/__init__.py | 9 + .../idl/unitree_hg/msg/dds_/.idlpy_manifest | 43 ++ .../idl/unitree_hg/msg/dds_/_BmsCmd_.py | 28 ++ .../idl/unitree_hg/msg/dds_/_BmsState_.py | 39 ++ .../idl/unitree_hg/msg/dds_/_HandCmd_.py | 28 ++ .../idl/unitree_hg/msg/dds_/_HandState_.py | 35 ++ .../idl/unitree_hg/msg/dds_/_IMUState_.py | 31 ++ .../idl/unitree_hg/msg/dds_/_LowCmd_.py | 31 ++ .../idl/unitree_hg/msg/dds_/_LowState_.py | 35 ++ .../unitree_hg/msg/dds_/_MainBoardState_.py | 30 ++ .../idl/unitree_hg/msg/dds_/_MotorCmd_.py | 33 ++ .../idl/unitree_hg/msg/dds_/_MotorState_.py | 36 ++ .../unitree_hg/msg/dds_/_PressSensorState_.py | 30 ++ .../idl/unitree_hg/msg/dds_/__init__.py | 19 + unitree_sdk2py/rpc/__init__.py | 0 unitree_sdk2py/rpc/client.py | 89 ++++ unitree_sdk2py/rpc/client_base.py | 93 ++++ unitree_sdk2py/rpc/client_stub.py | 69 +++ unitree_sdk2py/rpc/internal.py | 31 ++ unitree_sdk2py/rpc/lease_client.py | 113 +++++ unitree_sdk2py/rpc/lease_server.py | 151 ++++++ unitree_sdk2py/rpc/request_future.py | 46 ++ unitree_sdk2py/rpc/server.py | 122 +++++ unitree_sdk2py/rpc/server_base.py | 32 ++ unitree_sdk2py/rpc/server_stub.py | 78 +++ .../client/obstacles_avoid_client_example.py | 91 ++++ .../client/robot_service_client_example.py | 50 ++ .../test/client/sport_client_example.py | 109 +++++ .../test/client/video_client_example.py | 26 + .../test/client/vui_client_example.py | 74 +++ unitree_sdk2py/test/crc/test_crc.py | 27 ++ unitree_sdk2py/test/helloworld/helloworld.py | 6 + unitree_sdk2py/test/helloworld/publisher.py | 22 + unitree_sdk2py/test/helloworld/subscriber.py | 19 + .../test/lowlevel/lowlevel_control.py | 51 ++ unitree_sdk2py/test/lowlevel/read_lowstate.py | 24 + unitree_sdk2py/test/lowlevel/sub_lowstate.py | 15 + .../test/lowlevel/unitree_go2_const.py | 20 + unitree_sdk2py/test/rpc/test_api.py | 9 + .../test/rpc/test_client_example.py | 62 +++ .../test/rpc/test_server_example.py | 45 ++ unitree_sdk2py/utils/__init__.py | 0 unitree_sdk2py/utils/bqueue.py | 58 +++ unitree_sdk2py/utils/clib_lookup.py | 17 + unitree_sdk2py/utils/crc.py | 228 +++++++++ unitree_sdk2py/utils/future.py | 104 ++++ unitree_sdk2py/utils/hz_sample.py | 24 + unitree_sdk2py/utils/joystick.py | 251 ++++++++++ unitree_sdk2py/utils/lib/crc_aarch64.so | Bin 0 -> 7928 bytes unitree_sdk2py/utils/lib/crc_amd64.so | Bin 0 -> 15136 bytes unitree_sdk2py/utils/singleton.py | 11 + unitree_sdk2py/utils/thread.py | 83 ++++ unitree_sdk2py/utils/timerfd.py | 45 ++ 221 files changed, 11102 insertions(+) create mode 100644 LICENSE create mode 100644 README zh.md create mode 100644 README.md create mode 100644 doc/运行教程.md create mode 100644 example/b2/camera/camera_opencv.py create mode 100644 example/b2/camera/capture_image.py create mode 100644 example/b2/high_level/b2_sport_client.py create mode 100644 example/b2/low_level/b2_stand_example.py create mode 100644 example/b2/low_level/unitree_legged_const.py create mode 100644 example/b2w/camera/camera_opencv.py create mode 100644 example/b2w/camera/capture_image.py create mode 100644 example/b2w/high_level/b2w_sport_client.py create mode 100644 example/b2w/low_level/b2w_stand_example.py create mode 100644 example/b2w/low_level/unitree_legged_const.py create mode 100644 example/g1/audio/g1_audio_client_example.py create mode 100644 example/g1/high_level/g1_arm5_sdk_dds_example.py create mode 100644 example/g1/high_level/g1_arm7_sdk_dds_example.py create mode 100644 example/g1/high_level/g1_arm_action_example.py create mode 100644 example/g1/high_level/g1_loco_client_example.py create mode 100644 example/g1/low_level/g1_low_level_example.py create mode 100644 example/g1/readme.md create mode 100644 example/go2/front_camera/camera_opencv.py create mode 100644 example/go2/front_camera/capture_image.py create mode 100644 example/go2/high_level/go2_sport_client.py create mode 100644 example/go2/high_level/go2_utlidar_switch.py create mode 100644 example/go2/low_level/go2_stand_example.py create mode 100644 example/go2/low_level/unitree_legged_const.py create mode 100644 example/go2w/high_level/go2w_sport_client.py create mode 100644 example/go2w/low_level/go2w_stand_example.py create mode 100644 example/go2w/low_level/unitree_legged_const.py create mode 100644 example/h1/high_level/h1_loco_client_example.py create mode 100644 example/h1/low_level/h1_low_level_example.py create mode 100644 example/h1/low_level/unitree_legged_const.py create mode 100644 example/h1_2/low_level/h1_2_low_level_example.py create mode 100644 example/helloworld/publisher.py create mode 100644 example/helloworld/subscriber.py create mode 100644 example/helloworld/user_data.py create mode 100644 example/motionSwitcher/motion_switcher_example.py create mode 100644 example/obstacles_avoid/obstacles_avoid_move.py create mode 100644 example/obstacles_avoid/obstacles_avoid_switch.py create mode 100644 example/vui_client/vui_client_example.py create mode 100644 example/wireless_controller/wireless_controller.py create mode 100644 pyproject.toml create mode 100644 setup.py create mode 100644 unitree_sdk2py/__init__.py create mode 100644 unitree_sdk2py/b2/back_video/back_video_api.py create mode 100644 unitree_sdk2py/b2/back_video/back_video_client.py create mode 100644 unitree_sdk2py/b2/front_video/front_video_api.py create mode 100644 unitree_sdk2py/b2/front_video/front_video_client.py create mode 100644 unitree_sdk2py/b2/robot_state/robot_state_api.py create mode 100644 unitree_sdk2py/b2/robot_state/robot_state_client.py create mode 100644 unitree_sdk2py/b2/sport/sport_api.py create mode 100644 unitree_sdk2py/b2/sport/sport_client.py create mode 100644 unitree_sdk2py/b2/vui/vui_api.py create mode 100644 unitree_sdk2py/b2/vui/vui_client.py create mode 100644 unitree_sdk2py/comm/motion_switcher/__init__.py create mode 100644 unitree_sdk2py/comm/motion_switcher/motion_switcher_api.py create mode 100644 unitree_sdk2py/comm/motion_switcher/motion_switcher_client.py create mode 100644 unitree_sdk2py/core/__init__.py create mode 100644 unitree_sdk2py/core/channel.py create mode 100644 unitree_sdk2py/core/channel_config.py create mode 100644 unitree_sdk2py/core/channel_name.py create mode 100644 unitree_sdk2py/g1/arm/g1_arm_action_api.py create mode 100644 unitree_sdk2py/g1/arm/g1_arm_action_client.py create mode 100644 unitree_sdk2py/g1/audio/g1_audio_api.py create mode 100644 unitree_sdk2py/g1/audio/g1_audio_client.py create mode 100644 unitree_sdk2py/g1/loco/g1_loco_api.py create mode 100644 unitree_sdk2py/g1/loco/g1_loco_client.py create mode 100644 unitree_sdk2py/go2/__init__.py create mode 100644 unitree_sdk2py/go2/obstacles_avoid/__init__.py create mode 100644 unitree_sdk2py/go2/obstacles_avoid/obstacles_avoid_api.py create mode 100644 unitree_sdk2py/go2/obstacles_avoid/obstacles_avoid_client.py create mode 100644 unitree_sdk2py/go2/robot_state/__init__.py create mode 100644 unitree_sdk2py/go2/robot_state/robot_state_api.py create mode 100644 unitree_sdk2py/go2/robot_state/robot_state_client.py create mode 100644 unitree_sdk2py/go2/sport/__init__.py create mode 100644 unitree_sdk2py/go2/sport/sport_api.py create mode 100644 unitree_sdk2py/go2/sport/sport_client.py create mode 100644 unitree_sdk2py/go2/video/__init__.py create mode 100644 unitree_sdk2py/go2/video/video_api.py create mode 100644 unitree_sdk2py/go2/video/video_client.py create mode 100644 unitree_sdk2py/go2/vui/__init__.py create mode 100644 unitree_sdk2py/go2/vui/vui_api.py create mode 100644 unitree_sdk2py/go2/vui/vui_client.py create mode 100644 unitree_sdk2py/h1/loco/h1_loco_api.py create mode 100644 unitree_sdk2py/h1/loco/h1_loco_client.py create mode 100644 unitree_sdk2py/idl/__init__.py create mode 100644 unitree_sdk2py/idl/builtin_interfaces/__init__.py create mode 100644 unitree_sdk2py/idl/builtin_interfaces/msg/__init__.py create mode 100644 unitree_sdk2py/idl/builtin_interfaces/msg/dds_/_Time_.py create mode 100644 unitree_sdk2py/idl/builtin_interfaces/msg/dds_/__init__.py create mode 100644 unitree_sdk2py/idl/default.py create mode 100644 unitree_sdk2py/idl/geometry_msgs/__init__.py create mode 100644 unitree_sdk2py/idl/geometry_msgs/msg/__init__.py create mode 100644 unitree_sdk2py/idl/geometry_msgs/msg/dds_/_Point32_.py create mode 100644 unitree_sdk2py/idl/geometry_msgs/msg/dds_/_PointStamped_.py create mode 100644 unitree_sdk2py/idl/geometry_msgs/msg/dds_/_Point_.py create mode 100644 unitree_sdk2py/idl/geometry_msgs/msg/dds_/_Pose2D_.py create mode 100644 unitree_sdk2py/idl/geometry_msgs/msg/dds_/_PoseStamped_.py create mode 100644 unitree_sdk2py/idl/geometry_msgs/msg/dds_/_PoseWithCovarianceStamped_.py create mode 100644 unitree_sdk2py/idl/geometry_msgs/msg/dds_/_PoseWithCovariance_.py create mode 100644 unitree_sdk2py/idl/geometry_msgs/msg/dds_/_Pose_.py create mode 100644 unitree_sdk2py/idl/geometry_msgs/msg/dds_/_QuaternionStamped_.py create mode 100644 unitree_sdk2py/idl/geometry_msgs/msg/dds_/_Quaternion_.py create mode 100644 unitree_sdk2py/idl/geometry_msgs/msg/dds_/_TwistStamped_.py create mode 100644 unitree_sdk2py/idl/geometry_msgs/msg/dds_/_TwistWithCovarianceStamped_.py create mode 100644 unitree_sdk2py/idl/geometry_msgs/msg/dds_/_TwistWithCovariance_.py create mode 100644 unitree_sdk2py/idl/geometry_msgs/msg/dds_/_Twist_.py create mode 100644 unitree_sdk2py/idl/geometry_msgs/msg/dds_/_Vector3_.py create mode 100644 unitree_sdk2py/idl/geometry_msgs/msg/dds_/__init__.py create mode 100644 unitree_sdk2py/idl/nav_msgs/__init__.py create mode 100644 unitree_sdk2py/idl/nav_msgs/msg/__init__.py create mode 100644 unitree_sdk2py/idl/nav_msgs/msg/dds_/_MapMetaData_.py create mode 100644 unitree_sdk2py/idl/nav_msgs/msg/dds_/_OccupancyGrid_.py create mode 100644 unitree_sdk2py/idl/nav_msgs/msg/dds_/_Odometry_.py create mode 100644 unitree_sdk2py/idl/nav_msgs/msg/dds_/__init__.py create mode 100644 unitree_sdk2py/idl/sensor_msgs/__init__.py create mode 100644 unitree_sdk2py/idl/sensor_msgs/msg/__init__.py create mode 100644 unitree_sdk2py/idl/sensor_msgs/msg/dds_/PointField_Constants/_PointField_.py create mode 100644 unitree_sdk2py/idl/sensor_msgs/msg/dds_/PointField_Constants/__init__.py create mode 100644 unitree_sdk2py/idl/sensor_msgs/msg/dds_/_PointCloud2_.py create mode 100644 unitree_sdk2py/idl/sensor_msgs/msg/dds_/_PointField_.py create mode 100644 unitree_sdk2py/idl/sensor_msgs/msg/dds_/__init__.py create mode 100644 unitree_sdk2py/idl/std_msgs/__init__.py create mode 100644 unitree_sdk2py/idl/std_msgs/msg/__init__.py create mode 100644 unitree_sdk2py/idl/std_msgs/msg/dds_/_Header_.py create mode 100644 unitree_sdk2py/idl/std_msgs/msg/dds_/_String_.py create mode 100644 unitree_sdk2py/idl/std_msgs/msg/dds_/__init__.py create mode 100644 unitree_sdk2py/idl/unitree_api/__init__.py create mode 100644 unitree_sdk2py/idl/unitree_api/msg/__init__.py create mode 100644 unitree_sdk2py/idl/unitree_api/msg/dds_/_RequestHeader_.py create mode 100644 unitree_sdk2py/idl/unitree_api/msg/dds_/_RequestIdentity_.py create mode 100644 unitree_sdk2py/idl/unitree_api/msg/dds_/_RequestLease_.py create mode 100644 unitree_sdk2py/idl/unitree_api/msg/dds_/_RequestPolicy_.py create mode 100644 unitree_sdk2py/idl/unitree_api/msg/dds_/_Request_.py create mode 100644 unitree_sdk2py/idl/unitree_api/msg/dds_/_ResponseHeader_.py create mode 100644 unitree_sdk2py/idl/unitree_api/msg/dds_/_ResponseStatus_.py create mode 100644 unitree_sdk2py/idl/unitree_api/msg/dds_/_Response_.py create mode 100644 unitree_sdk2py/idl/unitree_api/msg/dds_/__init__.py create mode 100644 unitree_sdk2py/idl/unitree_go/__init__.py create mode 100644 unitree_sdk2py/idl/unitree_go/msg/__init__.py create mode 100644 unitree_sdk2py/idl/unitree_go/msg/dds_/_AudioData_.py create mode 100644 unitree_sdk2py/idl/unitree_go/msg/dds_/_BmsCmd_.py create mode 100644 unitree_sdk2py/idl/unitree_go/msg/dds_/_BmsState_.py create mode 100644 unitree_sdk2py/idl/unitree_go/msg/dds_/_Error_.py create mode 100644 unitree_sdk2py/idl/unitree_go/msg/dds_/_Go2FrontVideoData_.py create mode 100644 unitree_sdk2py/idl/unitree_go/msg/dds_/_HeightMap_.py create mode 100644 unitree_sdk2py/idl/unitree_go/msg/dds_/_IMUState_.py create mode 100644 unitree_sdk2py/idl/unitree_go/msg/dds_/_InterfaceConfig_.py create mode 100644 unitree_sdk2py/idl/unitree_go/msg/dds_/_LidarState_.py create mode 100644 unitree_sdk2py/idl/unitree_go/msg/dds_/_LowCmd_.py create mode 100644 unitree_sdk2py/idl/unitree_go/msg/dds_/_LowState_.py create mode 100644 unitree_sdk2py/idl/unitree_go/msg/dds_/_MotorCmd_.py create mode 100644 unitree_sdk2py/idl/unitree_go/msg/dds_/_MotorCmds_.py create mode 100644 unitree_sdk2py/idl/unitree_go/msg/dds_/_MotorState_.py create mode 100644 unitree_sdk2py/idl/unitree_go/msg/dds_/_MotorStates_.py create mode 100644 unitree_sdk2py/idl/unitree_go/msg/dds_/_PathPoint_.py create mode 100644 unitree_sdk2py/idl/unitree_go/msg/dds_/_Req_.py create mode 100644 unitree_sdk2py/idl/unitree_go/msg/dds_/_Res_.py create mode 100644 unitree_sdk2py/idl/unitree_go/msg/dds_/_SportModeState_.py create mode 100644 unitree_sdk2py/idl/unitree_go/msg/dds_/_TimeSpec_.py create mode 100644 unitree_sdk2py/idl/unitree_go/msg/dds_/_UwbState_.py create mode 100644 unitree_sdk2py/idl/unitree_go/msg/dds_/_UwbSwitch_.py create mode 100644 unitree_sdk2py/idl/unitree_go/msg/dds_/_WirelessController_.py create mode 100644 unitree_sdk2py/idl/unitree_go/msg/dds_/__init__.py create mode 100644 unitree_sdk2py/idl/unitree_hg/.idlpy_manifest create mode 100644 unitree_sdk2py/idl/unitree_hg/__init__.py create mode 100644 unitree_sdk2py/idl/unitree_hg/msg/.idlpy_manifest create mode 100644 unitree_sdk2py/idl/unitree_hg/msg/__init__.py create mode 100644 unitree_sdk2py/idl/unitree_hg/msg/dds_/.idlpy_manifest create mode 100644 unitree_sdk2py/idl/unitree_hg/msg/dds_/_BmsCmd_.py create mode 100644 unitree_sdk2py/idl/unitree_hg/msg/dds_/_BmsState_.py create mode 100644 unitree_sdk2py/idl/unitree_hg/msg/dds_/_HandCmd_.py create mode 100644 unitree_sdk2py/idl/unitree_hg/msg/dds_/_HandState_.py create mode 100644 unitree_sdk2py/idl/unitree_hg/msg/dds_/_IMUState_.py create mode 100644 unitree_sdk2py/idl/unitree_hg/msg/dds_/_LowCmd_.py create mode 100644 unitree_sdk2py/idl/unitree_hg/msg/dds_/_LowState_.py create mode 100644 unitree_sdk2py/idl/unitree_hg/msg/dds_/_MainBoardState_.py create mode 100644 unitree_sdk2py/idl/unitree_hg/msg/dds_/_MotorCmd_.py create mode 100644 unitree_sdk2py/idl/unitree_hg/msg/dds_/_MotorState_.py create mode 100644 unitree_sdk2py/idl/unitree_hg/msg/dds_/_PressSensorState_.py create mode 100644 unitree_sdk2py/idl/unitree_hg/msg/dds_/__init__.py create mode 100644 unitree_sdk2py/rpc/__init__.py create mode 100644 unitree_sdk2py/rpc/client.py create mode 100644 unitree_sdk2py/rpc/client_base.py create mode 100644 unitree_sdk2py/rpc/client_stub.py create mode 100644 unitree_sdk2py/rpc/internal.py create mode 100644 unitree_sdk2py/rpc/lease_client.py create mode 100644 unitree_sdk2py/rpc/lease_server.py create mode 100644 unitree_sdk2py/rpc/request_future.py create mode 100644 unitree_sdk2py/rpc/server.py create mode 100644 unitree_sdk2py/rpc/server_base.py create mode 100644 unitree_sdk2py/rpc/server_stub.py create mode 100644 unitree_sdk2py/test/client/obstacles_avoid_client_example.py create mode 100644 unitree_sdk2py/test/client/robot_service_client_example.py create mode 100644 unitree_sdk2py/test/client/sport_client_example.py create mode 100644 unitree_sdk2py/test/client/video_client_example.py create mode 100644 unitree_sdk2py/test/client/vui_client_example.py create mode 100644 unitree_sdk2py/test/crc/test_crc.py create mode 100644 unitree_sdk2py/test/helloworld/helloworld.py create mode 100644 unitree_sdk2py/test/helloworld/publisher.py create mode 100644 unitree_sdk2py/test/helloworld/subscriber.py create mode 100644 unitree_sdk2py/test/lowlevel/lowlevel_control.py create mode 100644 unitree_sdk2py/test/lowlevel/read_lowstate.py create mode 100644 unitree_sdk2py/test/lowlevel/sub_lowstate.py create mode 100644 unitree_sdk2py/test/lowlevel/unitree_go2_const.py create mode 100644 unitree_sdk2py/test/rpc/test_api.py create mode 100644 unitree_sdk2py/test/rpc/test_client_example.py create mode 100644 unitree_sdk2py/test/rpc/test_server_example.py create mode 100644 unitree_sdk2py/utils/__init__.py create mode 100644 unitree_sdk2py/utils/bqueue.py create mode 100644 unitree_sdk2py/utils/clib_lookup.py create mode 100644 unitree_sdk2py/utils/crc.py create mode 100644 unitree_sdk2py/utils/future.py create mode 100644 unitree_sdk2py/utils/hz_sample.py create mode 100644 unitree_sdk2py/utils/joystick.py create mode 100644 unitree_sdk2py/utils/lib/crc_aarch64.so create mode 100644 unitree_sdk2py/utils/lib/crc_amd64.so create mode 100644 unitree_sdk2py/utils/singleton.py create mode 100644 unitree_sdk2py/utils/thread.py create mode 100644 unitree_sdk2py/utils/timerfd.py diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..42d2e64 --- /dev/null +++ b/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2016-2024 HangZhou YuShu TECHNOLOGY CO.,LTD. ("Unitree Robotics") +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README zh.md b/README zh.md new file mode 100644 index 0000000..a7e6a8c --- /dev/null +++ b/README zh.md @@ -0,0 +1,121 @@ +# unitree_sdk2_python +unitree_sdk2 python 接口 + +# 安装 +## 依赖 +- python>=3.8 +- cyclonedds==0.10.2 +- numpy +- opencv-python + +## 安装 unitree_sdk2_python +在终端中执行: +```bash +cd ~ +sudo apt install python3-pip +git clone https://github.com/unitreerobotics/unitree_sdk2_python.git +cd unitree_sdk2_python +pip3 install -e . +``` +## FAQ +##### 1. `pip3 install -e .` 遇到报错 +```bash +Could not locate cyclonedds. Try to set CYCLONEDDS_HOME or CMAKE_PREFIX_PATH +``` +该错误提示找不到 cyclonedds 路径。首先编译安装cyclonedds: +```bash +cd ~ +git clone https://github.com/eclipse-cyclonedds/cyclonedds -b releases/0.10.x +cd cyclonedds && mkdir build install && cd build +cmake .. -DCMAKE_INSTALL_PREFIX=../install +cmake --build . --target install +``` +进入 unitree_sdk2_python 目录,设置 `CYCLONEDDS_HOME` 为刚刚编译好的 cyclonedds 所在路径,再安装 unitree_sdk2_python +```bash +cd ~/unitree_sdk2_python +export CYCLONEDDS_HOME="~/cyclonedds/install" +pip3 install -e . +``` + +详细见: +https://pypi.org/project/cyclonedds/#installing-with-pre-built-binaries + +# 使用 +python sdk2 接口与 unitree_skd2的接口保持一致,通过请求响应或订阅发布topic实现机器人的状态获取和控制。相应的例程位于`/example`目录下。在运行例程前,需要根据文档 https://support.unitree.com/home/zh/developer/Quick_start 配置好机器人的网络连接。 +## DDS通讯 +在终端中执行: +```bash +python3 ./example/helloworld/publisher.py +``` +打开新的终端,执行: +```bash +python3 ./example/helloworld/subscriber.py +``` +可以看到终端输出的数据信息。`publisher.py` 和 `subscriber.py` 传输的数据定义在 `user_data.py` 中,用户可以根据需要自行定义需要传输的数据结构。 + +## 高层状态和控制 +高层接口的数据结构和控制方式与unitree_sdk2一致。具体可见:https://support.unitree.com/home/zh/developer/sports_services +### 高层状态 +终端中执行: +```bash +python3 ./example/high_level/read_highstate.py enp2s0 +``` +其中 `enp2s0` 为机器人所连接的网卡名称,请根据实际情况修改。 +### 高层控制 +终端中执行: +```bash +python3 ./example/high_level/sportmode_test.py enp2s0 +``` +其中 `enp2s0` 为机器人所连接的网卡名称,请根据实际情况修改。 +该例程提供了几种测试方法,可根据测试需要选择: +```python +test.StandUpDown() # 站立趴下 +# test.VelocityMove() # 速度控制 +# test.BalanceAttitude() # 姿态控制 +# test.TrajectoryFollow() # 轨迹跟踪 +# test.SpecialMotions() # 特殊动作 + +``` +## 底层状态和控制 +底层接口的数据结构和控制方式与unitree_sdk2一致。具体可见:https://support.unitree.com/home/zh/developer/Basic_services +### 底层状态 +终端中执行: +```bash +python3 ./example/low_level/lowlevel_control.py enp2s0 +``` +其中 `enp2s0` 为机器人所连接的网卡名称,请根据实际情况修改。程序会输出右前腿hip关节的状态、IMU和电池电压信息。 + +### 底层电机控制 +首先使用 app 关闭高层运动服务(sport_mode),否则会导致指令冲突。 +终端中执行: +```bash +python3 ./example/low_level/lowlevel_control.py enp2s0 +``` +其中 `enp2s0` 为机器人所连接的网卡名称,请根据实际情况修改。左后腿 hip 关节会保持在0角度 (安全起见,这里设置 kp=10, kd=1),左后腿 calf 关节将持续输出 1Nm 的转矩。 + +## 遥控器状态获取 +终端中执行: +```bash +python3 ./example/wireless_controller/wireless_controller.py enp2s0 +``` +其中 `enp2s0` 为机器人所连接的网卡名称,请根据实际情况修改。 +终端将输出每一个按键的状态。对于遥控器按键的定义和数据结构可见: https://support.unitree.com/home/zh/developer/Get_remote_control_status + +## 前置摄像头 +使用opencv获取前置摄像头(确保在有图形界面的系统下运行, 按 ESC 退出程序): +```bash +python3 ./example/front_camera/camera_opencv.py enp2s0 +``` +其中 `enp2s0` 为机器人所连接的网卡名称,请根据实际情况修改。 + +## 避障开关 +```bash +python3 ./example/obstacles_avoid_switch/obstacles_avoid_switch.py enp2s0 +``` +其中 `enp2s0` 为机器人所连接的网卡名称,请根据实际情况修改。机器人将循环开启和关闭避障功能。关于避障服务,详细见 https://support.unitree.com/home/zh/developer/ObstaclesAvoidClient + +## 灯光音量控制 +```bash +python3 ./example/vui_client/vui_client_example.py enp2s0 +``` +其中 `enp2s0` 为机器人所连接的网卡名称,请根据实际情况修改。机器人将循环调节音量和灯光亮度。该接口详细见 https://support.unitree.com/home/zh/developer/VuiClient diff --git a/README.md b/README.md new file mode 100644 index 0000000..fb799c2 --- /dev/null +++ b/README.md @@ -0,0 +1,118 @@ +# unitree_sdk2_python +Python interface for unitree sdk2 + +# Installation +## Dependencies +- Python >= 3.8 +- cyclonedds == 0.10.2 +- numpy +- opencv-python +## Install unitree_sdk2_python + +```bash +pip install unitree_sdk2py +``` + +### Installing from source +Execute the following commands in the terminal: +```bash +cd ~ +sudo apt install python3-pip +git clone https://github.com/unitreerobotics/unitree_sdk2_python.git +cd unitree_sdk2_python +pip3 install -e . +``` +## FAQ +##### 1. Error when `pip3 install -e .`: +```bash +Could not locate cyclonedds. Try to set CYCLONEDDS_HOME or CMAKE_PREFIX_PATH +``` +This error mentions that the cyclonedds path could not be found. First compile and install cyclonedds: + +```bash +cd ~ +git clone https://github.com/eclipse-cyclonedds/cyclonedds -b releases/0.10.x +cd cyclonedds && mkdir build install && cd build +cmake .. -DCMAKE_INSTALL_PREFIX=../install +cmake --build . --target install +``` +Enter the unitree_sdk2_python directory, set `CYCLONEDDS_HOME` to the path of the cyclonedds you just compiled, and then install unitree_sdk2_python. +```bash +cd ~/unitree_sdk2_python +export CYCLONEDDS_HOME="~/cyclonedds/install" +pip3 install -e . +``` +For details, see: https://pypi.org/project/cyclonedds/#installing-with-pre-built-binaries + +# Usage +The Python sdk2 interface maintains consistency with the unitree_sdk2 interface, achieving robot status acquisition and control through request-response or topic subscription/publishing. Example programs are located in the `/example` directory. Before running the examples, configure the robot's network connection as per the instructions in the document at https://support.unitree.com/home/en/developer/Quick_start. +## DDS Communication +In the terminal, execute: +```bash +python3 ./example/helloworld/publisher.py +``` +Open a new terminal and execute: +```bash +python3 ./example/helloworld/subscriber.py +``` +You will see the data output in the terminal. The data structure transmitted between `publisher.py` and `subscriber.py` is defined in `user_data.py`, and users can define the required data structure as needed. +## High-Level Status and Control +The high-level interface maintains consistency with unitree_sdk2 in terms of data structure and control methods. For detailed information, refer to https://support.unitree.com/home/en/developer/sports_services. +### High-Level Status +Execute the following command in the terminal: +```bash +python3 ./example/high_level/read_highstate.py enp2s0 +``` +Replace `enp2s0` with the name of the network interface to which the robot is connected,. +### High-Level Control +Execute the following command in the terminal: +```bash +python3 ./example/high_level/sportmode_test.py enp2s0 +``` +Replace `enp2s0` with the name of the network interface to which the robot is connected. This example program provides several test methods, and you can choose the required tests as follows: +```python +test.StandUpDown() # Stand up and lie down +# test.VelocityMove() # Velocity control +# test.BalanceAttitude() # Attitude control +# test.TrajectoryFollow() # Trajectory tracking +# test.SpecialMotions() # Special motions +``` +## Low-Level Status and Control +The low-level interface maintains consistency with unitree_sdk2 in terms of data structure and control methods. For detailed information, refer to https://support.unitree.com/home/en/developer/Basic_services. +### Low-Level Status +Execute the following command in the terminal: +```bash +python3 ./example/low_level/lowlevel_control.py enp2s0 +``` +Replace `enp2s0` with the name of the network interface to which the robot is connected. The program will output the state of the right front leg hip joint, IMU, and battery voltage. +### Low-Level Motor Control +First, use the app to turn off the high-level motion service (sport_mode) to prevent conflicting instructions. +Execute the following command in the terminal: +```bash +python3 ./example/low_level/lowlevel_control.py enp2s0 +``` +Replace `enp2s0` with the name of the network interface to which the robot is connected. The left hind leg hip joint will maintain a 0-degree position (for safety, set kp=10, kd=1), and the left hind leg calf joint will continuously output 1Nm of torque. +## Wireless Controller Status +Execute the following command in the terminal: +```bash +python3 ./example/wireless_controller/wireless_controller.py enp2s0 +``` +Replace `enp2s0` with the name of the network interface to which the robot is connected. The terminal will output the status of each key. For the definition and data structure of the remote control keys, refer to https://support.unitree.com/home/en/developer/Get_remote_control_status. +## Front Camera +Use OpenCV to obtain the front camera (ensure to run on a system with a graphical interface, and press ESC to exit the program): +```bash +python3 ./example/front_camera/camera_opencv.py enp2s0 +``` +Replace `enp2s0` with the name of the network interface to which the robot is connected. + +## Obstacle Avoidance Switch +```bash +python3 ./example/obstacles_avoid_switch/obstacles_avoid_switch.py enp2s0 +``` +Replace `enp2s0` with the name of the network interface to which the robot is connected. The robot will cycle obstacle avoidance on and off. For details on the obstacle avoidance service, see https://support.unitree.com/home/en/developer/ObstaclesAvoidClient + +## Light and volume control +```bash +python3 ./example/vui_client/vui_client_example.py enp2s0 +``` +Replace `enp2s0` with the name of the network interface to which the robot is connected.T he robot will cycle the volume and light brightness. The interface is detailed at https://support.unitree.com/home/en/developer/VuiClient \ No newline at end of file diff --git a/doc/运行教程.md b/doc/运行教程.md new file mode 100644 index 0000000..f430c82 --- /dev/null +++ b/doc/运行教程.md @@ -0,0 +1,21 @@ +# 1. 机器人进入调试模式 +- G1 处于悬挂状态 和 阻尼状态(L2+B) +- 同时按下遥控器的L2+R2组合键,G1进入调试模式。 +- 此时按下L2+A, G1的双臂会摆出特定姿势。 +- 再按L2+B,手臂会落回去。以此来判断是否进入调试模式 + +# 2.配置网络 +- 机器人默认ip 192.168.123.161 +- 服务系统需要和机器人在同一网段下--推荐ip192.168.123.99 +- 验证网络是否联通--ping 192.168.123.161 + +# 3.安装unitree_sdk2_python +- 下载zip包--https://github.com/unitreerobotics/unitree_sdk2_python# 并解压缩 +- 进入解压缩后的文件中, pip3 install -e . + +# 4.python环境 +- conda activate unitree_sdk2_python +# 4.测试机器人程序 +- python example/g1/audio/g1_audio_client_example.py enp46s0, enp46s0为和机器人再同一网段的网卡名。 + + diff --git a/example/b2/camera/camera_opencv.py b/example/b2/camera/camera_opencv.py new file mode 100644 index 0000000..3fafcef --- /dev/null +++ b/example/b2/camera/camera_opencv.py @@ -0,0 +1,51 @@ +from unitree_sdk2py.core.channel import ChannelFactoryInitialize +from unitree_sdk2py.b2.front_video.front_video_client import FrontVideoClient +from unitree_sdk2py.b2.back_video.back_video_client import BackVideoClient +import cv2 +import numpy as np +import sys + +def display_image(window_name, data): + # If data is a list, we need to convert it to a bytes object + if isinstance(data, list): + data = bytes(data) + + # Now convert to numpy image + image_data = np.frombuffer(data, dtype=np.uint8) + image = cv2.imdecode(image_data, cv2.IMREAD_COLOR) + if image is not None: + cv2.imshow(window_name, image) + +if __name__ == "__main__": + if len(sys.argv) > 1: + ChannelFactoryInitialize(0, sys.argv[1]) + else: + ChannelFactoryInitialize(0) + + frontCameraClient = FrontVideoClient() # Create a front camera video client + frontCameraClient.SetTimeout(3.0) + frontCameraClient.Init() + + backCameraClient = BackVideoClient() # Create a back camera video client + backCameraClient.SetTimeout(3.0) + backCameraClient.Init() + + # Loop to continuously fetch images + while True: + # Get front camera image + front_code, front_data = frontCameraClient.GetImageSample() + if front_code == 0: + display_image("Front Camera", front_data) + + # Get back camera image + back_code, back_data = backCameraClient.GetImageSample() + if back_code == 0: + display_image("Back Camera", back_data) + + # Press ESC to stop + if cv2.waitKey(20) == 27: + break + + # Clean up windows + cv2.destroyAllWindows() + diff --git a/example/b2/camera/capture_image.py b/example/b2/camera/capture_image.py new file mode 100644 index 0000000..dcfaad6 --- /dev/null +++ b/example/b2/camera/capture_image.py @@ -0,0 +1,51 @@ +import time +import os +import sys + +from unitree_sdk2py.core.channel import ChannelFactoryInitialize +from unitree_sdk2py.b2.front_video.front_video_client import FrontVideoClient +from unitree_sdk2py.b2.back_video.back_video_client import BackVideoClient + +if __name__ == "__main__": + if len(sys.argv) > 1: + ChannelFactoryInitialize(0, sys.argv[1]) + else: + ChannelFactoryInitialize(0) + + # 创建前置相机客户端 + front_client = FrontVideoClient() + front_client.SetTimeout(3.0) + front_client.Init() + + # 创建后置相机客户端 + back_client = BackVideoClient() + back_client.SetTimeout(3.0) + back_client.Init() + + print("##################Get Front Camera Image###################") + # 获取前置相机图像 + front_code, front_data = front_client.GetImageSample() + + if front_code != 0: + print("Get front camera image error. Code:", front_code) + else: + front_image_name = "./front_img.jpg" + print("Front Image Saved as:", front_image_name) + + with open(front_image_name, "+wb") as f: + f.write(bytes(front_data)) + + print("##################Get Back Camera Image###################") + # 获取后置相机图像 + back_code, back_data = back_client.GetImageSample() + + if back_code != 0: + print("Get back camera image error. Code:", back_code) + else: + back_image_name = "./back_img.jpg" + print("Back Image Saved as:", back_image_name) + + with open(back_image_name, "+wb") as f: + f.write(bytes(back_data)) + + time.sleep(1) diff --git a/example/b2/high_level/b2_sport_client.py b/example/b2/high_level/b2_sport_client.py new file mode 100644 index 0000000..695d28e --- /dev/null +++ b/example/b2/high_level/b2_sport_client.py @@ -0,0 +1,105 @@ +import time +import sys +from unitree_sdk2py.core.channel import ChannelSubscriber, ChannelFactoryInitialize +from unitree_sdk2py.b2.sport.sport_client import SportClient +import math +from dataclasses import dataclass + +@dataclass +class TestOption: + name: str + id: int + +option_list = [ + TestOption(name="damp", id=0), + TestOption(name="stand_up", id=1), + TestOption(name="stand_down", id=2), + TestOption(name="move forward", id=3), + TestOption(name="move lateral", id=4), + TestOption(name="move rotate", id=5), + TestOption(name="stop_move", id=6), + TestOption(name="switch_gait", id=7), + TestOption(name="switch_gait", id=8), + TestOption(name="recovery", id=9), + TestOption(name="balanced stand", id=10) +] + +class UserInterface: + def __init__(self): + self.test_option_ = None + + def convert_to_int(self, input_str): + try: + return int(input_str) + except ValueError: + return None + + def terminal_handle(self): + input_str = input("Enter id or name: \n") + + if input_str == "list": + self.test_option_.name = None + self.test_option_.id = None + for option in option_list: + print(f"{option.name}, id: {option.id}") + return + + for option in option_list: + if input_str == option.name or self.convert_to_int(input_str) == option.id: + self.test_option_.name = option.name + self.test_option_.id = option.id + print(f"Test: {self.test_option_.name}, test_id: {self.test_option_.id}") + return + + print("No matching test option found.") + +if __name__ == "__main__": + + if len(sys.argv) < 2: + print(f"Usage: python3 {sys.argv[0]} networkInterface") + sys.exit(-1) + + print("WARNING: Please ensure there are no obstacles around the robot while running this example.") + input("Press Enter to continue...") + + ChannelFactoryInitialize(0, sys.argv[1]) + + test_option = TestOption(name=None, id=None) + user_interface = UserInterface() + user_interface.test_option_ = test_option + + sport_client = SportClient() + sport_client.SetTimeout(10.0) + sport_client.Init() + + print("Input \"list\" to list all test option ...") + + while True: + user_interface.terminal_handle() + + print(f"Updated Test Option: Name = {test_option.name}, ID = {test_option.id}") + + if test_option.id == 0: + sport_client.Damp() + elif test_option.id == 1: + sport_client.StandUp() + elif test_option.id == 2: + sport_client.StandDown() + elif test_option.id == 3: + sport_client.Move(0.3,0,0) + elif test_option.id == 4: + sport_client.Move(0,0.3,0) + elif test_option.id == 5: + sport_client.Move(0,0,0.5) + elif test_option.id == 6: + sport_client.StopMove() + elif test_option.id == 7: + sport_client.SwitchGait(0) + elif test_option.id == 8: + sport_client.SwitchGait(1) + elif test_option.id == 9: + sport_client.RecoveryStand() + elif test_option.id == 10: + sport_client.BalanceStand() + + time.sleep(1) diff --git a/example/b2/low_level/b2_stand_example.py b/example/b2/low_level/b2_stand_example.py new file mode 100644 index 0000000..a091630 --- /dev/null +++ b/example/b2/low_level/b2_stand_example.py @@ -0,0 +1,175 @@ +import time +import sys + +from unitree_sdk2py.core.channel import ChannelPublisher, ChannelFactoryInitialize +from unitree_sdk2py.core.channel import ChannelSubscriber, ChannelFactoryInitialize +from unitree_sdk2py.idl.default import unitree_go_msg_dds__LowCmd_ +from unitree_sdk2py.idl.default import unitree_go_msg_dds__LowState_ +from unitree_sdk2py.idl.unitree_go.msg.dds_ import LowCmd_ +from unitree_sdk2py.idl.unitree_go.msg.dds_ import LowState_ +from unitree_sdk2py.utils.thread import RecurrentThread +import unitree_legged_const as b2 +from unitree_sdk2py.comm.motion_switcher.motion_switcher_client import MotionSwitcherClient +from unitree_sdk2py.b2.sport.sport_client import SportClient + +from unitree_sdk2py.utils.crc import CRC + +class Custom: + def __init__(self): + self.Kp = 1000.0 + self.Kd = 10.0 + self.time_consume = 0 + self.rate_count = 0 + self.sin_count = 0 + self.motiontime = 0 + self.dt = 0.002 + + self.low_cmd = unitree_go_msg_dds__LowCmd_() + self.low_state = None + + self.targetPos_1 = [0.0, 1.36, -2.65, 0.0, 1.36, -2.65, + -0.2, 1.36, -2.65, 0.2, 1.36, -2.65] + + self.targetPos_2 = [0.0, 0.67, -1.3, 0.0, 0.67, -1.3, + 0.0, 0.67, -1.3, 0.0, 0.67, -1.3] + + self.targetPos_3 = [-0.5, 1.36, -2.65, 0.5, 1.36, -2.65, + -0.5, 1.36, -2.65, 0.5, 1.36, -2.65] + + self.startPos = [0.0] * 12 + self.duration_1 = 500 + self.duration_2 = 900 + self.duration_3 = 1000 + self.duration_4 = 900 + self.percent_1 = 0 + self.percent_2 = 0 + self.percent_3 = 0 + self.percent_4 = 0 + + self.firstRun = True + self.done = False + + # thread handling + self.lowCmdWriteThreadPtr = None + + self.crc = CRC() + + def Init(self): + self.InitLowCmd() + + # create publisher # + self.lowcmd_publisher = ChannelPublisher("rt/lowcmd", LowCmd_) + self.lowcmd_publisher.Init() + + # create subscriber # + self.lowstate_subscriber = ChannelSubscriber("rt/lowstate", LowState_) + self.lowstate_subscriber.Init(self.LowStateMessageHandler, 10) + + self.sc = SportClient() + self.sc.SetTimeout(5.0) + self.sc.Init() + + self.msc = MotionSwitcherClient() + self.msc.SetTimeout(5.0) + self.msc.Init() + + status, result = self.msc.CheckMode() + while result['name']: + self.sc.StandDown() + self.msc.ReleaseMode() + status, result = self.msc.CheckMode() + time.sleep(1) + + + def Start(self): + self.lowCmdWriteThreadPtr = RecurrentThread( + interval=0.002, target=self.LowCmdWrite, name="writebasiccmd" + ) + self.lowCmdWriteThreadPtr.Start() + + def InitLowCmd(self): + self.low_cmd.head[0] = 0xFE + self.low_cmd.head[1] = 0xEF + self.low_cmd.level_flag = 0xFF + self.low_cmd.gpio = 0 + for i in range(20): + self.low_cmd.motor_cmd[i].mode = 0x01 + self.low_cmd.motor_cmd[i].q= b2.PosStopF + self.low_cmd.motor_cmd[i].kp = 0 + self.low_cmd.motor_cmd[i].dq = b2.VelStopF + self.low_cmd.motor_cmd[i].kd = 0 + self.low_cmd.motor_cmd[i].tau = 0 + + def LowStateMessageHandler(self, msg: LowState_): + self.low_state = msg + + def LowCmdWrite(self): + + if self.firstRun: + for i in range(12): + self.startPos[i] = self.low_state.motor_state[i].q + self.firstRun = False + + self.percent_1 += 1.0 / self.duration_1 + self.percent_1 = min(self.percent_1, 1) + if self.percent_1 < 1: + for i in range(12): + self.low_cmd.motor_cmd[i].q = (1 - self.percent_1) * self.startPos[i] + self.percent_1 * self.targetPos_1[i] + self.low_cmd.motor_cmd[i].dq = 0 + self.low_cmd.motor_cmd[i].kp = self.Kp + self.low_cmd.motor_cmd[i].kd = self.Kd + self.low_cmd.motor_cmd[i].tau = 0 + + if (self.percent_1 == 1) and (self.percent_2 <= 1): + self.percent_2 += 1.0 / self.duration_2 + self.percent_2 = min(self.percent_2, 1) + for i in range(12): + self.low_cmd.motor_cmd[i].q = (1 - self.percent_2) * self.targetPos_1[i] + self.percent_2 * self.targetPos_2[i] + self.low_cmd.motor_cmd[i].dq = 0 + self.low_cmd.motor_cmd[i].kp = self.Kp + self.low_cmd.motor_cmd[i].kd = self.Kd + self.low_cmd.motor_cmd[i].tau = 0 + + if (self.percent_1 == 1) and (self.percent_2 == 1) and (self.percent_3 < 1): + self.percent_3 += 1.0 / self.duration_3 + self.percent_3 = min(self.percent_3, 1) + for i in range(12): + self.low_cmd.motor_cmd[i].q = self.targetPos_2[i] + self.low_cmd.motor_cmd[i].dq = 0 + self.low_cmd.motor_cmd[i].kp = self.Kp + self.low_cmd.motor_cmd[i].kd = self.Kd + self.low_cmd.motor_cmd[i].tau = 0 + + if (self.percent_1 == 1) and (self.percent_2 == 1) and (self.percent_3 == 1) and (self.percent_4 <= 1): + self.percent_4 += 1.0 / self.duration_4 + self.percent_4 = min(self.percent_4, 1) + for i in range(12): + self.low_cmd.motor_cmd[i].q = (1 - self.percent_4) * self.targetPos_2[i] + self.percent_4 * self.targetPos_3[i] + self.low_cmd.motor_cmd[i].dq = 0 + self.low_cmd.motor_cmd[i].kp = self.Kp + self.low_cmd.motor_cmd[i].kd = self.Kd + self.low_cmd.motor_cmd[i].tau = 0 + + self.low_cmd.crc = self.crc.Crc(self.low_cmd) + self.lowcmd_publisher.Write(self.low_cmd) + +if __name__ == '__main__': + + print("WARNING: Please ensure there are no obstacles around the robot while running this example.") + input("Press Enter to continue...") + + if len(sys.argv)>1: + ChannelFactoryInitialize(0, sys.argv[1]) + else: + ChannelFactoryInitialize(0) + + custom = Custom() + custom.Init() + custom.Start() + + while True: + if custom.percent_4 == 1.0: + time.sleep(1) + print("Done!") + sys.exit(-1) + time.sleep(1) \ No newline at end of file diff --git a/example/b2/low_level/unitree_legged_const.py b/example/b2/low_level/unitree_legged_const.py new file mode 100644 index 0000000..153a051 --- /dev/null +++ b/example/b2/low_level/unitree_legged_const.py @@ -0,0 +1,20 @@ +LegID = { + "FR_0": 0, # Front right hip + "FR_1": 1, # Front right thigh + "FR_2": 2, # Front right calf + "FL_0": 3, + "FL_1": 4, + "FL_2": 5, + "RR_0": 6, + "RR_1": 7, + "RR_2": 8, + "RL_0": 9, + "RL_1": 10, + "RL_2": 11, +} + +HIGHLEVEL = 0xEE +LOWLEVEL = 0xFF +TRIGERLEVEL = 0xF0 +PosStopF = 2.146e9 +VelStopF = 16000.0 diff --git a/example/b2w/camera/camera_opencv.py b/example/b2w/camera/camera_opencv.py new file mode 100644 index 0000000..3fafcef --- /dev/null +++ b/example/b2w/camera/camera_opencv.py @@ -0,0 +1,51 @@ +from unitree_sdk2py.core.channel import ChannelFactoryInitialize +from unitree_sdk2py.b2.front_video.front_video_client import FrontVideoClient +from unitree_sdk2py.b2.back_video.back_video_client import BackVideoClient +import cv2 +import numpy as np +import sys + +def display_image(window_name, data): + # If data is a list, we need to convert it to a bytes object + if isinstance(data, list): + data = bytes(data) + + # Now convert to numpy image + image_data = np.frombuffer(data, dtype=np.uint8) + image = cv2.imdecode(image_data, cv2.IMREAD_COLOR) + if image is not None: + cv2.imshow(window_name, image) + +if __name__ == "__main__": + if len(sys.argv) > 1: + ChannelFactoryInitialize(0, sys.argv[1]) + else: + ChannelFactoryInitialize(0) + + frontCameraClient = FrontVideoClient() # Create a front camera video client + frontCameraClient.SetTimeout(3.0) + frontCameraClient.Init() + + backCameraClient = BackVideoClient() # Create a back camera video client + backCameraClient.SetTimeout(3.0) + backCameraClient.Init() + + # Loop to continuously fetch images + while True: + # Get front camera image + front_code, front_data = frontCameraClient.GetImageSample() + if front_code == 0: + display_image("Front Camera", front_data) + + # Get back camera image + back_code, back_data = backCameraClient.GetImageSample() + if back_code == 0: + display_image("Back Camera", back_data) + + # Press ESC to stop + if cv2.waitKey(20) == 27: + break + + # Clean up windows + cv2.destroyAllWindows() + diff --git a/example/b2w/camera/capture_image.py b/example/b2w/camera/capture_image.py new file mode 100644 index 0000000..dcfaad6 --- /dev/null +++ b/example/b2w/camera/capture_image.py @@ -0,0 +1,51 @@ +import time +import os +import sys + +from unitree_sdk2py.core.channel import ChannelFactoryInitialize +from unitree_sdk2py.b2.front_video.front_video_client import FrontVideoClient +from unitree_sdk2py.b2.back_video.back_video_client import BackVideoClient + +if __name__ == "__main__": + if len(sys.argv) > 1: + ChannelFactoryInitialize(0, sys.argv[1]) + else: + ChannelFactoryInitialize(0) + + # 创建前置相机客户端 + front_client = FrontVideoClient() + front_client.SetTimeout(3.0) + front_client.Init() + + # 创建后置相机客户端 + back_client = BackVideoClient() + back_client.SetTimeout(3.0) + back_client.Init() + + print("##################Get Front Camera Image###################") + # 获取前置相机图像 + front_code, front_data = front_client.GetImageSample() + + if front_code != 0: + print("Get front camera image error. Code:", front_code) + else: + front_image_name = "./front_img.jpg" + print("Front Image Saved as:", front_image_name) + + with open(front_image_name, "+wb") as f: + f.write(bytes(front_data)) + + print("##################Get Back Camera Image###################") + # 获取后置相机图像 + back_code, back_data = back_client.GetImageSample() + + if back_code != 0: + print("Get back camera image error. Code:", back_code) + else: + back_image_name = "./back_img.jpg" + print("Back Image Saved as:", back_image_name) + + with open(back_image_name, "+wb") as f: + f.write(bytes(back_data)) + + time.sleep(1) diff --git a/example/b2w/high_level/b2w_sport_client.py b/example/b2w/high_level/b2w_sport_client.py new file mode 100644 index 0000000..e324f75 --- /dev/null +++ b/example/b2w/high_level/b2w_sport_client.py @@ -0,0 +1,101 @@ +import time +import sys +from unitree_sdk2py.core.channel import ChannelSubscriber, ChannelFactoryInitialize +from unitree_sdk2py.b2.sport.sport_client import SportClient +import math +from dataclasses import dataclass + +@dataclass +class TestOption: + name: str + id: int + +option_list = [ + TestOption(name="damp", id=0), + TestOption(name="stand_up", id=1), + TestOption(name="stand_down", id=2), + TestOption(name="move forward", id=3), + TestOption(name="move lateral", id=4), + TestOption(name="move rotate", id=5), + TestOption(name="stop_move", id=6), + TestOption(name="switch_gait", id=7), + TestOption(name="switch_gait", id=8), + TestOption(name="recovery", id=9) +] + +class UserInterface: + def __init__(self): + self.test_option_ = None + + def convert_to_int(self, input_str): + try: + return int(input_str) + except ValueError: + return None + + def terminal_handle(self): + input_str = input("Enter id or name: \n") + + if input_str == "list": + self.test_option_.name = None + self.test_option_.id = None + for option in option_list: + print(f"name: {option.name}, id: {option.id}") + return + + for option in option_list: + if input_str == option.name or self.convert_to_int(input_str) == option.id: + self.test_option_.name = option.name + self.test_option_.id = option.id + print(f"Test: {self.test_option_.name}, test_id: {self.test_option_.id}") + return + + print("No matching test option found.") + +if __name__ == "__main__": + if len(sys.argv) < 2: + print(f"Usage: python3 {sys.argv[0]} networkInterface") + sys.exit(-1) + + print("WARNING: Please ensure there are no obstacles around the robot while running this example.") + input("Press Enter to continue...") + + ChannelFactoryInitialize(0, sys.argv[1]) + + test_option = TestOption(name=None, id=None) + user_interface = UserInterface() + user_interface.test_option_ = test_option + + sport_client = SportClient() + sport_client.SetTimeout(10.0) + sport_client.Init() + + print("Input \"list\" to list all test option ...") + + while True: + user_interface.terminal_handle() + + print(f"Updated Test Option: Name = {test_option.name}, ID = {test_option.id}\n") + + if test_option.id == 0: + sport_client.Damp() + elif test_option.id == 1: + sport_client.StandUp() + elif test_option.id == 2: + sport_client.StandDown() + elif test_option.id == 3: + sport_client.Move(0.3,0,0) + elif test_option.id == 4: + sport_client.Move(0,0.3,0) + elif test_option.id == 5: + sport_client.Move(0,0,0.5) + elif test_option.id == 6: + sport_client.StopMove() + elif test_option.id == 7: + sport_client.SwitchGait(0) + elif test_option.id == 8: + sport_client.SwitchGait(1) + elif test_option.id == 9: + sport_client.RecoveryStand() + + time.sleep(1) diff --git a/example/b2w/low_level/b2w_stand_example.py b/example/b2w/low_level/b2w_stand_example.py new file mode 100644 index 0000000..b535059 --- /dev/null +++ b/example/b2w/low_level/b2w_stand_example.py @@ -0,0 +1,196 @@ +import time +import sys + +from unitree_sdk2py.core.channel import ChannelPublisher, ChannelFactoryInitialize +from unitree_sdk2py.core.channel import ChannelSubscriber, ChannelFactoryInitialize +from unitree_sdk2py.idl.default import unitree_go_msg_dds__LowCmd_ +from unitree_sdk2py.idl.default import unitree_go_msg_dds__LowState_ +from unitree_sdk2py.idl.unitree_go.msg.dds_ import LowCmd_ +from unitree_sdk2py.idl.unitree_go.msg.dds_ import LowState_ +from unitree_sdk2py.utils.crc import CRC +from unitree_sdk2py.utils.thread import RecurrentThread +import unitree_legged_const as b2w +from unitree_sdk2py.comm.motion_switcher.motion_switcher_client import MotionSwitcherClient +from unitree_sdk2py.b2.sport.sport_client import SportClient + +class Custom: + def __init__(self): + self.Kp = 1000.0 + self.Kd = 10.0 + self.time_consume = 0 + self.rate_count = 0 + self.sin_count = 0 + self.motiontime = 0 + self.dt = 0.002 + + self.low_cmd = unitree_go_msg_dds__LowCmd_() + self.low_state = None + + self.targetPos_1 = [0.0, 1.36, -2.65, 0.0, 1.36, -2.65, + -0.2, 1.36, -2.65, 0.2, 1.36, -2.65] + + self.targetPos_2 = [0.0, 0.67, -1.3, 0.0, 0.67, -1.3, + 0.0, 0.67, -1.3, 0.0, 0.67, -1.3] + + self.targetPos_3 = [-0.65, 1.36, -2.65, 0.65, 1.36, -2.65, + -0.65, 1.36, -2.65, 0.65, 1.36, -2.65] + + self.startPos = [0.0] * 12 + self.duration_1 = 800 + self.duration_2 = 800 + self.duration_3 = 2000 + self.duration_4 = 1500 + self.percent_1 = 0 + self.percent_2 = 0 + self.percent_3 = 0 + self.percent_4 = 0 + + self.firstRun = True + self.done = False + + # thread handling + self.lowCmdWriteThreadPtr = None + + self.crc = CRC() + + def Init(self): + self.InitLowCmd() + + # create publisher # + self.lowcmd_publisher = ChannelPublisher("rt/lowcmd", LowCmd_) + self.lowcmd_publisher.Init() + + # create subscriber # + self.lowstate_subscriber = ChannelSubscriber("rt/lowstate", LowState_) + self.lowstate_subscriber.Init(self.LowStateMessageHandler, 10) + + self.sc = SportClient() + self.sc.SetTimeout(5.0) + self.sc.Init() + + self.msc = MotionSwitcherClient() + self.msc.SetTimeout(5.0) + self.msc.Init() + + status, result = self.msc.CheckMode() + while result['name']: + self.sc.StandDown() + self.msc.ReleaseMode() + status, result = self.msc.CheckMode() + time.sleep(1) + + def Start(self): + self.lowCmdWriteThreadPtr = RecurrentThread( + name="writebasiccmd", interval=self.dt, target=self.LowCmdWrite, + ) + self.lowCmdWriteThreadPtr.Start() + + def InitLowCmd(self): + self.low_cmd.head[0] = 0xFE + self.low_cmd.head[1] = 0xEF + self.low_cmd.level_flag = 0xFF + self.low_cmd.gpio = 0 + for i in range(20): + self.low_cmd.motor_cmd[i].mode = 0x01 # (PMSM) mode + self.low_cmd.motor_cmd[i].q = b2w.PosStopF + self.low_cmd.motor_cmd[i].kp = 0 + self.low_cmd.motor_cmd[i].dq = b2w.VelStopF + self.low_cmd.motor_cmd[i].kd = 0 + self.low_cmd.motor_cmd[i].tau = 0 + + def LowStateMessageHandler(self, msg: LowState_): + self.low_state = msg + + def LowCmdWrite(self): + if self.firstRun: + for i in range(12): + self.startPos[i] = self.low_state.motor_state[i].q + self.firstRun = False + + self.percent_1 += 1.0 / self.duration_1 + self.percent_1 = min(self.percent_1, 1) + if self.percent_1 < 1: + for i in range(12): + self.low_cmd.motor_cmd[i].q = (1 - self.percent_1) * self.startPos[i] + self.percent_1 * self.targetPos_1[i] + self.low_cmd.motor_cmd[i].dq = 0 + self.low_cmd.motor_cmd[i].kp = self.Kp + self.low_cmd.motor_cmd[i].kd = self.Kd + self.low_cmd.motor_cmd[i].tau = 0 + + if (self.percent_1 == 1) and (self.percent_2 <= 1): + self.percent_2 += 1.0 / self.duration_2 + self.percent_2 = min(self.percent_2, 1) + for i in range(12): + self.low_cmd.motor_cmd[i].q = (1 - self.percent_2) * self.targetPos_1[i] + self.percent_2 * self.targetPos_2[i] + self.low_cmd.motor_cmd[i].dq = 0 + self.low_cmd.motor_cmd[i].kp = self.Kp + self.low_cmd.motor_cmd[i].kd = self.Kd + self.low_cmd.motor_cmd[i].tau = 0 + + if (self.percent_1 == 1) and (self.percent_2 == 1) and (self.percent_3 < 1): + self.percent_3 += 1.0 / self.duration_3 + self.percent_3 = min(self.percent_3, 1) + for i in range(12): + self.low_cmd.motor_cmd[i].q = self.targetPos_2[i] + self.low_cmd.motor_cmd[i].dq = 0 + self.low_cmd.motor_cmd[i].kp = self.Kp + self.low_cmd.motor_cmd[i].kd = self.Kd + self.low_cmd.motor_cmd[i].tau = 0 + + if self.percent_3 < 0.4: + for i in range(12, 16): + self.low_cmd.motor_cmd[i].q = 0 + self.low_cmd.motor_cmd[i].kp = 0 + self.low_cmd.motor_cmd[i].dq = 3 + self.low_cmd.motor_cmd[i].kd = self.Kd + self.low_cmd.motor_cmd[i].tau = 0 + + if 0.4 <= self.percent_3 < 0.8: + for i in range(12, 16): + self.low_cmd.motor_cmd[i].q = 0 + self.low_cmd.motor_cmd[i].kp = 0 + self.low_cmd.motor_cmd[i].dq = -3 + self.low_cmd.motor_cmd[i].kd = self.Kd + self.low_cmd.motor_cmd[i].tau = 0 + + if self.percent_3 >= 0.8: + for i in range(12, 16): + self.low_cmd.motor_cmd[i].q = 0 + self.low_cmd.motor_cmd[i].kp = 0 + self.low_cmd.motor_cmd[i].dq = 0 + self.low_cmd.motor_cmd[i].kd = self.Kd + self.low_cmd.motor_cmd[i].tau = 0 + + if (self.percent_1 == 1) and (self.percent_2 == 1) and (self.percent_3 == 1) and (self.percent_4 <= 1): + self.percent_4 += 1.0 / self.duration_4 + self.percent_4 = min(self.percent_4, 1) + for i in range(12): + self.low_cmd.motor_cmd[i].q = (1 - self.percent_4) * self.targetPos_2[i] + self.percent_4 * self.targetPos_3[i] + self.low_cmd.motor_cmd[i].dq = 0 + self.low_cmd.motor_cmd[i].kp = self.Kp + self.low_cmd.motor_cmd[i].kd = self.Kd + self.low_cmd.motor_cmd[i].tau = 0 + + self.low_cmd.crc = self.crc.Crc(self.low_cmd) + self.lowcmd_publisher.Write(self.low_cmd) + +if __name__ == '__main__': + + print("WARNING: Please ensure there are no obstacles around the robot while running this example.") + input("Press Enter to continue...") + + if len(sys.argv)>1: + ChannelFactoryInitialize(0, sys.argv[1]) + else: + ChannelFactoryInitialize(0) + + custom = Custom() + custom.Init() + custom.Start() + + while True: + if custom.percent_4 == 1.0: + time.sleep(1) + print("Done!") + sys.exit(-1) + time.sleep(1) \ No newline at end of file diff --git a/example/b2w/low_level/unitree_legged_const.py b/example/b2w/low_level/unitree_legged_const.py new file mode 100644 index 0000000..7943e31 --- /dev/null +++ b/example/b2w/low_level/unitree_legged_const.py @@ -0,0 +1,24 @@ +LegID = { + "FR_0": 0, # Front right hip + "FR_1": 1, # Front right thigh + "FR_2": 2, # Front right calf + "FL_0": 3, + "FL_1": 4, + "FL_2": 5, + "RR_0": 6, + "RR_1": 7, + "RR_2": 8, + "RL_0": 9, + "RL_1": 10, + "RL_2": 11, + "FR_w": 12, # Front right wheel + "FL_w": 13, # Front left wheel + "RR_w": 14, # Rear right wheel + "RL_w": 15, # Rear left wheel +} + +HIGHLEVEL = 0xEE +LOWLEVEL = 0xFF +TRIGERLEVEL = 0xF0 +PosStopF = 2.146e9 +VelStopF = 16000.0 diff --git a/example/g1/audio/g1_audio_client_example.py b/example/g1/audio/g1_audio_client_example.py new file mode 100644 index 0000000..6e0cc25 --- /dev/null +++ b/example/g1/audio/g1_audio_client_example.py @@ -0,0 +1,44 @@ +import time +import sys +from unitree_sdk2py.core.channel import ChannelSubscriber, ChannelFactoryInitialize +from unitree_sdk2py.g1.audio.g1_audio_client import AudioClient +from unitree_sdk2py.g1.loco.g1_loco_client import LocoClient + +if __name__ == "__main__": + if len(sys.argv) < 2: + print(f"Usage: python3 {sys.argv[0]} networkInterface") + sys.exit(-1) + + ChannelFactoryInitialize(0, sys.argv[1]) + + audio_client = AudioClient() + audio_client.SetTimeout(10.0) + audio_client.Init() + + sport_client = LocoClient() + sport_client.SetTimeout(10.0) + sport_client.Init() + + ret = audio_client.GetVolume() + print("debug GetVolume: ",ret) + + audio_client.SetVolume(85) + + ret = audio_client.GetVolume() + print("debug GetVolume: ",ret) + + sport_client.WaveHand() + + audio_client.TtsMaker("大家好!我是宇树科技人形机器人。语音开发测试例程运行成功! 很高兴认识你!",0) + time.sleep(8) + audio_client.TtsMaker("接下来测试灯带开发例程!",0) + time.sleep(1) + audio_client.LedControl(255,0,0) + time.sleep(1) + audio_client.LedControl(0,255,0) + time.sleep(1) + audio_client.LedControl(0,0,255) + + time.sleep(3) + audio_client.TtsMaker("测试完毕,谢谢大家!",0) + diff --git a/example/g1/high_level/g1_arm5_sdk_dds_example.py b/example/g1/high_level/g1_arm5_sdk_dds_example.py new file mode 100644 index 0000000..6090807 --- /dev/null +++ b/example/g1/high_level/g1_arm5_sdk_dds_example.py @@ -0,0 +1,192 @@ +import time +import sys + +from unitree_sdk2py.core.channel import ChannelPublisher, ChannelFactoryInitialize +from unitree_sdk2py.core.channel import ChannelSubscriber, ChannelFactoryInitialize +from unitree_sdk2py.idl.default import unitree_hg_msg_dds__LowCmd_ +from unitree_sdk2py.idl.default import unitree_hg_msg_dds__LowState_ +from unitree_sdk2py.idl.unitree_hg.msg.dds_ import LowCmd_ +from unitree_sdk2py.idl.unitree_hg.msg.dds_ import LowState_ +from unitree_sdk2py.utils.crc import CRC +from unitree_sdk2py.utils.thread import RecurrentThread +from unitree_sdk2py.comm.motion_switcher.motion_switcher_client import MotionSwitcherClient + +import numpy as np + +kPi = 3.141592654 +kPi_2 = 1.57079632 + +class G1JointIndex: + # Left leg + LeftHipPitch = 0 + LeftHipRoll = 1 + LeftHipYaw = 2 + LeftKnee = 3 + LeftAnklePitch = 4 + LeftAnkleB = 4 + LeftAnkleRoll = 5 + LeftAnkleA = 5 + + # Right leg + RightHipPitch = 6 + RightHipRoll = 7 + RightHipYaw = 8 + RightKnee = 9 + RightAnklePitch = 10 + RightAnkleB = 10 + RightAnkleRoll = 11 + RightAnkleA = 11 + + WaistYaw = 12 + WaistRoll = 13 # NOTE: INVALID for g1 23dof/29dof with waist locked + WaistA = 13 # NOTE: INVALID for g1 23dof/29dof with waist locked + WaistPitch = 14 # NOTE: INVALID for g1 23dof/29dof with waist locked + WaistB = 14 # NOTE: INVALID for g1 23dof/29dof with waist locked + + # Left arm + LeftShoulderPitch = 15 + LeftShoulderRoll = 16 + LeftShoulderYaw = 17 + LeftElbow = 18 + LeftWristRoll = 19 + LeftWristPitch = 20 # NOTE: INVALID for g1 23dof + LeftWristYaw = 21 # NOTE: INVALID for g1 23dof + + # Right arm + RightShoulderPitch = 22 + RightShoulderRoll = 23 + RightShoulderYaw = 24 + RightElbow = 25 + RightWristRoll = 26 + RightWristPitch = 27 # NOTE: INVALID for g1 23dof + RightWristYaw = 28 # NOTE: INVALID for g1 23dof + + kNotUsedJoint = 29 # NOTE: Weight + +class Custom: + def __init__(self): + self.time_ = 0.0 + self.control_dt_ = 0.02 + self.duration_ = 3.0 + self.counter_ = 0 + self.weight = 0. + self.weight_rate = 0.2 + self.kp = 60. + self.kd = 1.5 + self.dq = 0. + self.tau_ff = 0. + self.mode_machine_ = 0 + self.low_cmd = unitree_hg_msg_dds__LowCmd_() + self.low_state = None + self.first_update_low_state = False + self.crc = CRC() + self.done = False + + self.target_pos = [ + 0.0, kPi_2, 0.0, kPi_2, 0.0, + 0.0, -kPi_2, 0.0, kPi_2, 0.0, + 0.0, 0.0, 0.0 + ] + + self.arm_joints = [ + G1JointIndex.LeftShoulderPitch, G1JointIndex.LeftShoulderRoll, + G1JointIndex.LeftShoulderYaw, G1JointIndex.LeftElbow, + G1JointIndex.LeftWristRoll, + G1JointIndex.RightShoulderPitch, G1JointIndex.RightShoulderRoll, + G1JointIndex.RightShoulderYaw, G1JointIndex.RightElbow, + G1JointIndex.RightWristRoll, + G1JointIndex.WaistYaw, + G1JointIndex.WaistRoll, + G1JointIndex.WaistPitch + ] + + def Init(self): + # create publisher # + self.arm_sdk_publisher = ChannelPublisher("rt/arm_sdk", LowCmd_) + self.arm_sdk_publisher.Init() + + # create subscriber # + self.lowstate_subscriber = ChannelSubscriber("rt/lowstate", LowState_) + self.lowstate_subscriber.Init(self.LowStateHandler, 10) + + def Start(self): + self.lowCmdWriteThreadPtr = RecurrentThread( + interval=self.control_dt_, target=self.LowCmdWrite, name="control" + ) + while self.first_update_low_state == False: + time.sleep(1) + + if self.first_update_low_state == True: + self.lowCmdWriteThreadPtr.Start() + + def LowStateHandler(self, msg: LowState_): + self.low_state = msg + + if self.first_update_low_state == False: + self.first_update_low_state = True + + def LowCmdWrite(self): + self.time_ += self.control_dt_ + + if self.time_ < self.duration_ : + # [Stage 1]: set robot to zero posture + self.low_cmd.motor_cmd[G1JointIndex.kNotUsedJoint].q = 1 # 1:Enable arm_sdk, 0:Disable arm_sdk + for i,joint in enumerate(self.arm_joints): + ratio = np.clip(self.time_ / self.duration_, 0.0, 1.0) + self.low_cmd.motor_cmd[joint].tau = 0. + self.low_cmd.motor_cmd[joint].q = (1.0 - ratio) * self.low_state.motor_state[joint].q + self.low_cmd.motor_cmd[joint].dq = 0. + self.low_cmd.motor_cmd[joint].kp = self.kp + self.low_cmd.motor_cmd[joint].kd = self.kd + + elif self.time_ < self.duration_ * 3 : + # [Stage 2]: lift arms up + for i,joint in enumerate(self.arm_joints): + ratio = np.clip((self.time_ - self.duration_) / (self.duration_ * 2), 0.0, 1.0) + self.low_cmd.motor_cmd[joint].tau = 0. + self.low_cmd.motor_cmd[joint].q = ratio * self.target_pos[i] + (1.0 - ratio) * self.low_state.motor_state[joint].q + self.low_cmd.motor_cmd[joint].dq = 0. + self.low_cmd.motor_cmd[joint].kp = self.kp + self.low_cmd.motor_cmd[joint].kd = self.kd + + elif self.time_ < self.duration_ * 6 : + # [Stage 3]: set robot back to zero posture + for i,joint in enumerate(self.arm_joints): + ratio = np.clip((self.time_ - self.duration_*3) / (self.duration_ * 3), 0.0, 1.0) + self.low_cmd.motor_cmd[joint].tau = 0. + self.low_cmd.motor_cmd[joint].q = (1.0 - ratio) * self.low_state.motor_state[joint].q + self.low_cmd.motor_cmd[joint].dq = 0. + self.low_cmd.motor_cmd[joint].kp = self.kp + self.low_cmd.motor_cmd[joint].kd = self.kd + + elif self.time_ < self.duration_ * 7 : + # [Stage 4]: release arm_sdk + for i,joint in enumerate(self.arm_joints): + ratio = np.clip((self.time_ - self.duration_*6) / (self.duration_), 0.0, 1.0) + self.low_cmd.motor_cmd[G1JointIndex.kNotUsedJoint].q = (1 - ratio) # 1:Enable arm_sdk, 0:Disable arm_sdk + + else: + self.done = True + + self.low_cmd.crc = self.crc.Crc(self.low_cmd) + self.arm_sdk_publisher.Write(self.low_cmd) + +if __name__ == '__main__': + + print("WARNING: Please ensure there are no obstacles around the robot while running this example.") + input("Press Enter to continue...") + + if len(sys.argv)>1: + ChannelFactoryInitialize(0, sys.argv[1]) + else: + ChannelFactoryInitialize(0) + + custom = Custom() + custom.Init() + custom.Start() + + while True: + time.sleep(1) + if custom.done: + print("Done!") + sys.exit(-1) \ No newline at end of file diff --git a/example/g1/high_level/g1_arm7_sdk_dds_example.py b/example/g1/high_level/g1_arm7_sdk_dds_example.py new file mode 100644 index 0000000..6ced14f --- /dev/null +++ b/example/g1/high_level/g1_arm7_sdk_dds_example.py @@ -0,0 +1,194 @@ +import time +import sys + +from unitree_sdk2py.core.channel import ChannelPublisher, ChannelFactoryInitialize +from unitree_sdk2py.core.channel import ChannelSubscriber, ChannelFactoryInitialize +from unitree_sdk2py.idl.default import unitree_hg_msg_dds__LowCmd_ +from unitree_sdk2py.idl.default import unitree_hg_msg_dds__LowState_ +from unitree_sdk2py.idl.unitree_hg.msg.dds_ import LowCmd_ +from unitree_sdk2py.idl.unitree_hg.msg.dds_ import LowState_ +from unitree_sdk2py.utils.crc import CRC +from unitree_sdk2py.utils.thread import RecurrentThread +from unitree_sdk2py.comm.motion_switcher.motion_switcher_client import MotionSwitcherClient + +import numpy as np + +kPi = 3.141592654 +kPi_2 = 1.57079632 + +class G1JointIndex: + # Left leg + LeftHipPitch = 0 + LeftHipRoll = 1 + LeftHipYaw = 2 + LeftKnee = 3 + LeftAnklePitch = 4 + LeftAnkleB = 4 + LeftAnkleRoll = 5 + LeftAnkleA = 5 + + # Right leg + RightHipPitch = 6 + RightHipRoll = 7 + RightHipYaw = 8 + RightKnee = 9 + RightAnklePitch = 10 + RightAnkleB = 10 + RightAnkleRoll = 11 + RightAnkleA = 11 + + WaistYaw = 12 + WaistRoll = 13 # NOTE: INVALID for g1 23dof/29dof with waist locked + WaistA = 13 # NOTE: INVALID for g1 23dof/29dof with waist locked + WaistPitch = 14 # NOTE: INVALID for g1 23dof/29dof with waist locked + WaistB = 14 # NOTE: INVALID for g1 23dof/29dof with waist locked + + # Left arm + LeftShoulderPitch = 15 + LeftShoulderRoll = 16 + LeftShoulderYaw = 17 + LeftElbow = 18 + LeftWristRoll = 19 + LeftWristPitch = 20 # NOTE: INVALID for g1 23dof + LeftWristYaw = 21 # NOTE: INVALID for g1 23dof + + # Right arm + RightShoulderPitch = 22 + RightShoulderRoll = 23 + RightShoulderYaw = 24 + RightElbow = 25 + RightWristRoll = 26 + RightWristPitch = 27 # NOTE: INVALID for g1 23dof + RightWristYaw = 28 # NOTE: INVALID for g1 23dof + + kNotUsedJoint = 29 # NOTE: Weight + +class Custom: + def __init__(self): + self.time_ = 0.0 + self.control_dt_ = 0.02 + self.duration_ = 3.0 + self.counter_ = 0 + self.weight = 0. + self.weight_rate = 0.2 + self.kp = 60. + self.kd = 1.5 + self.dq = 0. + self.tau_ff = 0. + self.mode_machine_ = 0 + self.low_cmd = unitree_hg_msg_dds__LowCmd_() + self.low_state = None + self.first_update_low_state = False + self.crc = CRC() + self.done = False + + self.target_pos = [ + 0., kPi_2, 0., kPi_2, 0., 0., 0., + 0., -kPi_2, 0., kPi_2, 0., 0., 0., + 0, 0, 0 + ] + + self.arm_joints = [ + G1JointIndex.LeftShoulderPitch, G1JointIndex.LeftShoulderRoll, + G1JointIndex.LeftShoulderYaw, G1JointIndex.LeftElbow, + G1JointIndex.LeftWristRoll, G1JointIndex.LeftWristPitch, + G1JointIndex.LeftWristYaw, + G1JointIndex.RightShoulderPitch, G1JointIndex.RightShoulderRoll, + G1JointIndex.RightShoulderYaw, G1JointIndex.RightElbow, + G1JointIndex.RightWristRoll, G1JointIndex.RightWristPitch, + G1JointIndex.RightWristYaw, + G1JointIndex.WaistYaw, + G1JointIndex.WaistRoll, + G1JointIndex.WaistPitch + ] + + def Init(self): + # create publisher # + self.arm_sdk_publisher = ChannelPublisher("rt/arm_sdk", LowCmd_) + self.arm_sdk_publisher.Init() + + # create subscriber # + self.lowstate_subscriber = ChannelSubscriber("rt/lowstate", LowState_) + self.lowstate_subscriber.Init(self.LowStateHandler, 10) + + def Start(self): + self.lowCmdWriteThreadPtr = RecurrentThread( + interval=self.control_dt_, target=self.LowCmdWrite, name="control" + ) + while self.first_update_low_state == False: + time.sleep(1) + + if self.first_update_low_state == True: + self.lowCmdWriteThreadPtr.Start() + + def LowStateHandler(self, msg: LowState_): + self.low_state = msg + + if self.first_update_low_state == False: + self.first_update_low_state = True + + def LowCmdWrite(self): + self.time_ += self.control_dt_ + + if self.time_ < self.duration_ : + # [Stage 1]: set robot to zero posture + self.low_cmd.motor_cmd[G1JointIndex.kNotUsedJoint].q = 1 # 1:Enable arm_sdk, 0:Disable arm_sdk + for i,joint in enumerate(self.arm_joints): + ratio = np.clip(self.time_ / self.duration_, 0.0, 1.0) + self.low_cmd.motor_cmd[joint].tau = 0. + self.low_cmd.motor_cmd[joint].q = (1.0 - ratio) * self.low_state.motor_state[joint].q + self.low_cmd.motor_cmd[joint].dq = 0. + self.low_cmd.motor_cmd[joint].kp = self.kp + self.low_cmd.motor_cmd[joint].kd = self.kd + + elif self.time_ < self.duration_ * 3 : + # [Stage 2]: lift arms up + for i,joint in enumerate(self.arm_joints): + ratio = np.clip((self.time_ - self.duration_) / (self.duration_ * 2), 0.0, 1.0) + self.low_cmd.motor_cmd[joint].tau = 0. + self.low_cmd.motor_cmd[joint].q = ratio * self.target_pos[i] + (1.0 - ratio) * self.low_state.motor_state[joint].q + self.low_cmd.motor_cmd[joint].dq = 0. + self.low_cmd.motor_cmd[joint].kp = self.kp + self.low_cmd.motor_cmd[joint].kd = self.kd + + elif self.time_ < self.duration_ * 6 : + # [Stage 3]: set robot back to zero posture + for i,joint in enumerate(self.arm_joints): + ratio = np.clip((self.time_ - self.duration_*3) / (self.duration_ * 3), 0.0, 1.0) + self.low_cmd.motor_cmd[joint].tau = 0. + self.low_cmd.motor_cmd[joint].q = (1.0 - ratio) * self.low_state.motor_state[joint].q + self.low_cmd.motor_cmd[joint].dq = 0. + self.low_cmd.motor_cmd[joint].kp = self.kp + self.low_cmd.motor_cmd[joint].kd = self.kd + + elif self.time_ < self.duration_ * 7 : + # [Stage 4]: release arm_sdk + for i,joint in enumerate(self.arm_joints): + ratio = np.clip((self.time_ - self.duration_*6) / (self.duration_), 0.0, 1.0) + self.low_cmd.motor_cmd[G1JointIndex.kNotUsedJoint].q = (1 - ratio) # 1:Enable arm_sdk, 0:Disable arm_sdk + + else: + self.done = True + + self.low_cmd.crc = self.crc.Crc(self.low_cmd) + self.arm_sdk_publisher.Write(self.low_cmd) + +if __name__ == '__main__': + + print("WARNING: Please ensure there are no obstacles around the robot while running this example.") + input("Press Enter to continue...") + + if len(sys.argv)>1: + ChannelFactoryInitialize(0, sys.argv[1]) + else: + ChannelFactoryInitialize(0) + + custom = Custom() + custom.Init() + custom.Start() + + while True: + time.sleep(1) + if custom.done: + print("Done!") + sys.exit(-1) \ No newline at end of file diff --git a/example/g1/high_level/g1_arm_action_example.py b/example/g1/high_level/g1_arm_action_example.py new file mode 100644 index 0000000..7b0c289 --- /dev/null +++ b/example/g1/high_level/g1_arm_action_example.py @@ -0,0 +1,141 @@ +import time +import sys +from unitree_sdk2py.core.channel import ChannelSubscriber, ChannelFactoryInitialize +from unitree_sdk2py.g1.arm.g1_arm_action_client import G1ArmActionClient +from unitree_sdk2py.g1.arm.g1_arm_action_client import action_map +from dataclasses import dataclass + +@dataclass +class TestOption: + name: str + id: int + +option_list = [ + TestOption(name="release arm", id=0), + TestOption(name="shake hand", id=1), + TestOption(name="high five", id=2), + TestOption(name="hug", id=3), + TestOption(name="high wave", id=4), + TestOption(name="clap", id=5), + TestOption(name="face wave", id=6), + TestOption(name="left kiss", id=7), + TestOption(name="heart", id=8), + TestOption(name="right heart", id=9), + TestOption(name="hands up", id=10), + TestOption(name="x-ray", id=11), + TestOption(name="right hand up", id=12), + TestOption(name="reject", id=13), + TestOption(name="right kiss", id=14), + TestOption(name="two-hand kiss", id=15), + +] + +class UserInterface: + def __init__(self): + self.test_option_ = None + + def convert_to_int(self, input_str): + try: + return int(input_str) + except ValueError: + return None + + def terminal_handle(self): + input_str = input("Enter id or name: \n") + + if input_str == "list": + self.test_option_.name = None + self.test_option_.id = None + for option in option_list: + print(f"{option.name}, id: {option.id}") + return + + for option in option_list: + if input_str == option.name or self.convert_to_int(input_str) == option.id: + self.test_option_.name = option.name + self.test_option_.id = option.id + print(f"Test: {self.test_option_.name}, test_id: {self.test_option_.id}") + return + + print("No matching test option found.") + + +if __name__ == "__main__": + if len(sys.argv) < 2: + print(f"Usage: python3 {sys.argv[0]} networkInterface") + sys.exit(-1) + + print("WARNING: Please ensure there are no obstacles around the robot while running this example.") + input("Press Enter to continue...") + + ChannelFactoryInitialize(0, sys.argv[1]) + + test_option = TestOption(name=None, id=None) + user_interface = UserInterface() + user_interface.test_option_ = test_option + + armAction_client = G1ArmActionClient() + armAction_client.SetTimeout(10.0) + armAction_client.Init() + + # actionList = armAction_client.GetActionList() + # print("actionList\n",actionList) + + print("Input \"list\" to list all test option ...") + while True: + user_interface.terminal_handle() + + print(f"Updated Test Option: Name = {test_option.name}, ID = {test_option.id}") + + if test_option.id == 0: + armAction_client.ExecuteAction(action_map.get("release arm")) + elif test_option.id == 1: + armAction_client.ExecuteAction(action_map.get("shake hand")) + time.sleep(2) + armAction_client.ExecuteAction(action_map.get("release arm")) + elif test_option.id == 2: + armAction_client.ExecuteAction(action_map.get("high five")) + time.sleep(2) + armAction_client.ExecuteAction(action_map.get("release arm")) + elif test_option.id == 3: + armAction_client.ExecuteAction(action_map.get("hug")) + time.sleep(2) + armAction_client.ExecuteAction(action_map.get("release arm")) + elif test_option.id == 4: + armAction_client.ExecuteAction(action_map.get("high wave")) + elif test_option.id == 5: + armAction_client.ExecuteAction(action_map.get("clap")) + elif test_option.id == 6: + armAction_client.ExecuteAction(action_map.get("face wave")) + elif test_option.id == 7: + armAction_client.ExecuteAction(action_map.get("left kiss")) + elif test_option.id == 8: + armAction_client.ExecuteAction(action_map.get("heart")) + time.sleep(2) + armAction_client.ExecuteAction(action_map.get("release arm")) + elif test_option.id == 9: + armAction_client.ExecuteAction(action_map.get("right heart")) + time.sleep(2) + armAction_client.ExecuteAction(action_map.get("release arm")) + elif test_option.id == 10: + armAction_client.ExecuteAction(action_map.get("hands up")) + time.sleep(2) + armAction_client.ExecuteAction(action_map.get("release arm")) + elif test_option.id == 11: + armAction_client.ExecuteAction(action_map.get("x-ray")) + time.sleep(2) + armAction_client.ExecuteAction(action_map.get("release arm")) + elif test_option.id == 12: + armAction_client.ExecuteAction(action_map.get("right hand up")) + time.sleep(2) + armAction_client.ExecuteAction(action_map.get("release arm")) + elif test_option.id == 13: + armAction_client.ExecuteAction(action_map.get("reject")) + time.sleep(2) + armAction_client.ExecuteAction(action_map.get("release arm")) + elif test_option.id == 14: + armAction_client.ExecuteAction(action_map.get("right kiss")) + elif test_option.id == 15: + armAction_client.ExecuteAction(action_map.get("two-hand kiss")) + + time.sleep(1) \ No newline at end of file diff --git a/example/g1/high_level/g1_loco_client_example.py b/example/g1/high_level/g1_loco_client_example.py new file mode 100644 index 0000000..55ee059 --- /dev/null +++ b/example/g1/high_level/g1_loco_client_example.py @@ -0,0 +1,117 @@ +import time +import sys +from unitree_sdk2py.core.channel import ChannelSubscriber, ChannelFactoryInitialize +from unitree_sdk2py.idl.default import unitree_go_msg_dds__SportModeState_ +from unitree_sdk2py.idl.unitree_go.msg.dds_ import SportModeState_ +from unitree_sdk2py.g1.loco.g1_loco_client import LocoClient +import math +from dataclasses import dataclass + +@dataclass +class TestOption: + name: str + id: int + +option_list = [ + TestOption(name="damp", id=0), + TestOption(name="Squat2StandUp", id=1), + TestOption(name="StandUp2Squat", id=2), + TestOption(name="move forward", id=3), + TestOption(name="move lateral", id=4), + TestOption(name="move rotate", id=5), + TestOption(name="low stand", id=6), + TestOption(name="high stand", id=7), + TestOption(name="zero torque", id=8), + TestOption(name="wave hand1", id=9), # wave hand without turning around + TestOption(name="wave hand2", id=10), # wave hand and trun around + TestOption(name="shake hand", id=11), + TestOption(name="Lie2StandUp", id=12), +] + +class UserInterface: + def __init__(self): + self.test_option_ = None + + def convert_to_int(self, input_str): + try: + return int(input_str) + except ValueError: + return None + + def terminal_handle(self): + input_str = input("Enter id or name: \n") + + if input_str == "list": + self.test_option_.name = None + self.test_option_.id = None + for option in option_list: + print(f"{option.name}, id: {option.id}") + return + + for option in option_list: + if input_str == option.name or self.convert_to_int(input_str) == option.id: + self.test_option_.name = option.name + self.test_option_.id = option.id + print(f"Test: {self.test_option_.name}, test_id: {self.test_option_.id}") + return + + print("No matching test option found.") + +if __name__ == "__main__": + if len(sys.argv) < 2: + print(f"Usage: python3 {sys.argv[0]} networkInterface") + sys.exit(-1) + + print("WARNING: Please ensure there are no obstacles around the robot while running this example.") + input("Press Enter to continue...") + + ChannelFactoryInitialize(0, sys.argv[1]) + + test_option = TestOption(name=None, id=None) + user_interface = UserInterface() + user_interface.test_option_ = test_option + + sport_client = LocoClient() + sport_client.SetTimeout(10.0) + sport_client.Init() + + print("Input \"list\" to list all test option ...") + while True: + user_interface.terminal_handle() + + print(f"Updated Test Option: Name = {test_option.name}, ID = {test_option.id}") + + if test_option.id == 0: + sport_client.Damp() + elif test_option.id == 1: + sport_client.Damp() + time.sleep(0.5) + sport_client.Squat2StandUp() + elif test_option.id == 2: + sport_client.StandUp2Squat() + elif test_option.id == 3: + sport_client.Move(0.3,0,0) + elif test_option.id == 4: + sport_client.Move(0,0.3,0) + elif test_option.id == 5: + sport_client.Move(0,0,0.3) + elif test_option.id == 6: + sport_client.LowStand() + elif test_option.id == 7: + sport_client.HighStand() + elif test_option.id == 8: + sport_client.ZeroTorque() + elif test_option.id == 9: + sport_client.WaveHand() + elif test_option.id == 10: + sport_client.WaveHand(True) + elif test_option.id == 11: + sport_client.ShakeHand() + time.sleep(3) + sport_client.ShakeHand() + elif test_option.id == 12: + sport_client.Damp() + time.sleep(0.5) + sport_client.Lie2StandUp() # When using the Lie2StandUp function, ensure that the robot faces up and the ground is hard, flat and rough. + + time.sleep(1) \ No newline at end of file diff --git a/example/g1/low_level/g1_low_level_example.py b/example/g1/low_level/g1_low_level_example.py new file mode 100644 index 0000000..382e863 --- /dev/null +++ b/example/g1/low_level/g1_low_level_example.py @@ -0,0 +1,205 @@ +import time +import sys + +from unitree_sdk2py.core.channel import ChannelPublisher, ChannelFactoryInitialize +from unitree_sdk2py.core.channel import ChannelSubscriber, ChannelFactoryInitialize +from unitree_sdk2py.idl.default import unitree_hg_msg_dds__LowCmd_ +from unitree_sdk2py.idl.default import unitree_hg_msg_dds__LowState_ +from unitree_sdk2py.idl.unitree_hg.msg.dds_ import LowCmd_ +from unitree_sdk2py.idl.unitree_hg.msg.dds_ import LowState_ +from unitree_sdk2py.utils.crc import CRC +from unitree_sdk2py.utils.thread import RecurrentThread +from unitree_sdk2py.comm.motion_switcher.motion_switcher_client import MotionSwitcherClient + +import numpy as np + +G1_NUM_MOTOR = 29 + +Kp = [ + 60, 60, 60, 100, 40, 40, # legs + 60, 60, 60, 100, 40, 40, # legs + 60, 40, 40, # waist + 40, 40, 40, 40, 40, 40, 40, # arms + 40, 40, 40, 40, 40, 40, 40 # arms +] + +Kd = [ + 1, 1, 1, 2, 1, 1, # legs + 1, 1, 1, 2, 1, 1, # legs + 1, 1, 1, # waist + 1, 1, 1, 1, 1, 1, 1, # arms + 1, 1, 1, 1, 1, 1, 1 # arms +] + +class G1JointIndex: + LeftHipPitch = 0 + LeftHipRoll = 1 + LeftHipYaw = 2 + LeftKnee = 3 + LeftAnklePitch = 4 + LeftAnkleB = 4 + LeftAnkleRoll = 5 + LeftAnkleA = 5 + RightHipPitch = 6 + RightHipRoll = 7 + RightHipYaw = 8 + RightKnee = 9 + RightAnklePitch = 10 + RightAnkleB = 10 + RightAnkleRoll = 11 + RightAnkleA = 11 + WaistYaw = 12 + WaistRoll = 13 # NOTE: INVALID for g1 23dof/29dof with waist locked + WaistA = 13 # NOTE: INVALID for g1 23dof/29dof with waist locked + WaistPitch = 14 # NOTE: INVALID for g1 23dof/29dof with waist locked + WaistB = 14 # NOTE: INVALID for g1 23dof/29dof with waist locked + LeftShoulderPitch = 15 + LeftShoulderRoll = 16 + LeftShoulderYaw = 17 + LeftElbow = 18 + LeftWristRoll = 19 + LeftWristPitch = 20 # NOTE: INVALID for g1 23dof + LeftWristYaw = 21 # NOTE: INVALID for g1 23dof + RightShoulderPitch = 22 + RightShoulderRoll = 23 + RightShoulderYaw = 24 + RightElbow = 25 + RightWristRoll = 26 + RightWristPitch = 27 # NOTE: INVALID for g1 23dof + RightWristYaw = 28 # NOTE: INVALID for g1 23dof + + +class Mode: + PR = 0 # Series Control for Pitch/Roll Joints + AB = 1 # Parallel Control for A/B Joints + +class Custom: + def __init__(self): + self.time_ = 0.0 + self.control_dt_ = 0.002 # [2ms] + self.duration_ = 3.0 # [3 s] + self.counter_ = 0 + self.mode_pr_ = Mode.PR + self.mode_machine_ = 0 + self.low_cmd = unitree_hg_msg_dds__LowCmd_() + self.low_state = None + self.update_mode_machine_ = False + self.crc = CRC() + + def Init(self): + self.msc = MotionSwitcherClient() + self.msc.SetTimeout(5.0) + self.msc.Init() + + status, result = self.msc.CheckMode() + while result['name']: + self.msc.ReleaseMode() + status, result = self.msc.CheckMode() + time.sleep(1) + + # create publisher # + self.lowcmd_publisher_ = ChannelPublisher("rt/lowcmd", LowCmd_) + self.lowcmd_publisher_.Init() + + # create subscriber # + self.lowstate_subscriber = ChannelSubscriber("rt/lowstate", LowState_) + self.lowstate_subscriber.Init(self.LowStateHandler, 10) + + def Start(self): + self.lowCmdWriteThreadPtr = RecurrentThread( + interval=self.control_dt_, target=self.LowCmdWrite, name="control" + ) + while self.update_mode_machine_ == False: + time.sleep(1) + + if self.update_mode_machine_ == True: + self.lowCmdWriteThreadPtr.Start() + + def LowStateHandler(self, msg: LowState_): + self.low_state = msg + + if self.update_mode_machine_ == False: + self.mode_machine_ = self.low_state.mode_machine + self.update_mode_machine_ = True + + self.counter_ +=1 + if (self.counter_ % 500 == 0) : + self.counter_ = 0 + print(self.low_state.imu_state.rpy) + + def LowCmdWrite(self): + self.time_ += self.control_dt_ + + if self.time_ < self.duration_ : + # [Stage 1]: set robot to zero posture + for i in range(G1_NUM_MOTOR): + ratio = np.clip(self.time_ / self.duration_, 0.0, 1.0) + self.low_cmd.mode_pr = Mode.PR + self.low_cmd.mode_machine = self.mode_machine_ + self.low_cmd.motor_cmd[i].mode = 1 # 1:Enable, 0:Disable + self.low_cmd.motor_cmd[i].tau = 0. + self.low_cmd.motor_cmd[i].q = (1.0 - ratio) * self.low_state.motor_state[i].q + self.low_cmd.motor_cmd[i].dq = 0. + self.low_cmd.motor_cmd[i].kp = Kp[i] + self.low_cmd.motor_cmd[i].kd = Kd[i] + + elif self.time_ < self.duration_ * 2 : + # [Stage 2]: swing ankle using PR mode + max_P = np.pi * 30.0 / 180.0 + max_R = np.pi * 10.0 / 180.0 + t = self.time_ - self.duration_ + L_P_des = max_P * np.sin(2.0 * np.pi * t) + L_R_des = max_R * np.sin(2.0 * np.pi * t) + R_P_des = max_P * np.sin(2.0 * np.pi * t) + R_R_des = -max_R * np.sin(2.0 * np.pi * t) + + self.low_cmd.mode_pr = Mode.PR + self.low_cmd.mode_machine = self.mode_machine_ + self.low_cmd.motor_cmd[G1JointIndex.LeftAnklePitch].q = L_P_des + self.low_cmd.motor_cmd[G1JointIndex.LeftAnkleRoll].q = L_R_des + self.low_cmd.motor_cmd[G1JointIndex.RightAnklePitch].q = R_P_des + self.low_cmd.motor_cmd[G1JointIndex.RightAnkleRoll].q = R_R_des + + else : + # [Stage 3]: swing ankle using AB mode + max_A = np.pi * 30.0 / 180.0 + max_B = np.pi * 10.0 / 180.0 + t = self.time_ - self.duration_ * 2 + L_A_des = max_A * np.sin(2.0 * np.pi * t) + L_B_des = max_B * np.sin(2.0 * np.pi * t + np.pi) + R_A_des = -max_A * np.sin(2.0 * np.pi * t) + R_B_des = -max_B * np.sin(2.0 * np.pi * t + np.pi) + + self.low_cmd.mode_pr = Mode.AB + self.low_cmd.mode_machine = self.mode_machine_ + self.low_cmd.motor_cmd[G1JointIndex.LeftAnkleA].q = L_A_des + self.low_cmd.motor_cmd[G1JointIndex.LeftAnkleB].q = L_B_des + self.low_cmd.motor_cmd[G1JointIndex.RightAnkleA].q = R_A_des + self.low_cmd.motor_cmd[G1JointIndex.RightAnkleB].q = R_B_des + + max_WristYaw = np.pi * 30.0 / 180.0 + L_WristYaw_des = max_WristYaw * np.sin(2.0 * np.pi * t) + R_WristYaw_des = max_WristYaw * np.sin(2.0 * np.pi * t) + self.low_cmd.motor_cmd[G1JointIndex.LeftWristRoll].q = L_WristYaw_des + self.low_cmd.motor_cmd[G1JointIndex.RightWristRoll].q = R_WristYaw_des + + + self.low_cmd.crc = self.crc.Crc(self.low_cmd) + self.lowcmd_publisher_.Write(self.low_cmd) + +if __name__ == '__main__': + + print("WARNING: Please ensure there are no obstacles around the robot while running this example.") + input("Press Enter to continue...") + + if len(sys.argv)>1: + ChannelFactoryInitialize(0, sys.argv[1]) + else: + ChannelFactoryInitialize(0) + + custom = Custom() + custom.Init() + custom.Start() + + while True: + time.sleep(1) \ No newline at end of file diff --git a/example/g1/readme.md b/example/g1/readme.md new file mode 100644 index 0000000..9fb7900 --- /dev/null +++ b/example/g1/readme.md @@ -0,0 +1,5 @@ +This example is a test of Unitree G1/H1-2 robot. + +**Note:** +idl/unitree_go is used for Unitree Go2/B2/H1/B2w/Go2w robots +idl/unitree_hg is used for Unitree G1/H1-2 robots diff --git a/example/go2/front_camera/camera_opencv.py b/example/go2/front_camera/camera_opencv.py new file mode 100644 index 0000000..9d98839 --- /dev/null +++ b/example/go2/front_camera/camera_opencv.py @@ -0,0 +1,41 @@ +from unitree_sdk2py.core.channel import ChannelFactoryInitialize +from unitree_sdk2py.go2.video.video_client import VideoClient +import cv2 +import numpy as np +import sys + + +if __name__ == "__main__": + if len(sys.argv)>1: + ChannelFactoryInitialize(0, sys.argv[1]) + else: + ChannelFactoryInitialize(0) + + client = VideoClient() # Create a video client + client.SetTimeout(3.0) + client.Init() + + code, data = client.GetImageSample() + + # Request normal when code==0 + while code == 0: + # Get Image data from Go2 robot + code, data = client.GetImageSample() + + # Convert to numpy image + image_data = np.frombuffer(bytes(data), dtype=np.uint8) + image = cv2.imdecode(image_data, cv2.IMREAD_COLOR) + + # Display image + cv2.imshow("front_camera", image) + # Press ESC to stop + if cv2.waitKey(20) == 27: + break + + if code != 0: + print("Get image sample error. code:", code) + else: + # Capture an image + cv2.imwrite("front_image.jpg", image) + + cv2.destroyWindow("front_camera") diff --git a/example/go2/front_camera/capture_image.py b/example/go2/front_camera/capture_image.py new file mode 100644 index 0000000..1e85643 --- /dev/null +++ b/example/go2/front_camera/capture_image.py @@ -0,0 +1,30 @@ +import time +import os +import sys + +from unitree_sdk2py.core.channel import ChannelFactoryInitialize +from unitree_sdk2py.go2.video.video_client import VideoClient + +if __name__ == "__main__": + if len(sys.argv)>1: + ChannelFactoryInitialize(0, sys.argv[1]) + else: + ChannelFactoryInitialize(0) + + client = VideoClient() + client.SetTimeout(3.0) + client.Init() + + print("##################GetImageSample###################") + code, data = client.GetImageSample() + + if code != 0: + print("get image sample error. code:", code) + else: + imageName = "./img.jpg" + print("ImageName:", imageName) + + with open(imageName, "+wb") as f: + f.write(bytes(data)) + + time.sleep(1) diff --git a/example/go2/high_level/go2_sport_client.py b/example/go2/high_level/go2_sport_client.py new file mode 100644 index 0000000..b14d79d --- /dev/null +++ b/example/go2/high_level/go2_sport_client.py @@ -0,0 +1,170 @@ +import time +import sys +from unitree_sdk2py.core.channel import ChannelSubscriber, ChannelFactoryInitialize +from unitree_sdk2py.idl.default import unitree_go_msg_dds__SportModeState_ +from unitree_sdk2py.idl.unitree_go.msg.dds_ import SportModeState_ +from unitree_sdk2py.go2.sport.sport_client import ( + SportClient, + PathPoint, + SPORT_PATH_POINT_SIZE, +) +import math +from dataclasses import dataclass + +@dataclass +class TestOption: + name: str + id: int + +option_list = [ + TestOption(name="damp", id=0), + TestOption(name="stand_up", id=1), + TestOption(name="stand_down", id=2), + TestOption(name="move forward", id=3), + TestOption(name="move lateral", id=4), + TestOption(name="move rotate", id=5), + TestOption(name="stop_move", id=6), + TestOption(name="switch_gait", id=7), + TestOption(name="switch_gait", id=8), + TestOption(name="balanced stand", id=9), + TestOption(name="recovery", id=10), + TestOption(name="recovery", id=10), + TestOption(name="left flip", id=11), + TestOption(name="back flip", id=12), + TestOption(name="free walk", id=13), + TestOption(name="free bound", id=14), + TestOption(name="free avoid", id=15), + TestOption(name="walk stair", id=16), + TestOption(name="walk upright", id=17), + TestOption(name="cross step", id=18), + TestOption(name="free jump", id=19) +] + +class UserInterface: + def __init__(self): + self.test_option_ = None + + def convert_to_int(self, input_str): + try: + return int(input_str) + except ValueError: + return None + + def terminal_handle(self): + input_str = input("Enter id or name: \n") + + if input_str == "list": + self.test_option_.name = None + self.test_option_.id = None + for option in option_list: + print(f"{option.name}, id: {option.id}") + return + + for option in option_list: + if input_str == option.name or self.convert_to_int(input_str) == option.id: + self.test_option_.name = option.name + self.test_option_.id = option.id + print(f"Test: {self.test_option_.name}, test_id: {self.test_option_.id}") + return + + print("No matching test option found.") + +if __name__ == "__main__": + + if len(sys.argv) < 2: + print(f"Usage: python3 {sys.argv[0]} networkInterface") + sys.exit(-1) + + print("WARNING: Please ensure there are no obstacles around the robot while running this example.") + input("Press Enter to continue...") + + ChannelFactoryInitialize(0, sys.argv[1]) + + test_option = TestOption(name=None, id=None) + user_interface = UserInterface() + user_interface.test_option_ = test_option + + sport_client = SportClient() + sport_client.SetTimeout(10.0) + sport_client.Init() + while True: + + user_interface.terminal_handle() + + print(f"Updated Test Option: Name = {test_option.name}, ID = {test_option.id}\n") + + if test_option.id == 0: + sport_client.Damp() + elif test_option.id == 1: + sport_client.StandUp() + elif test_option.id == 2: + sport_client.StandDown() + elif test_option.id == 3: + sport_client.Move(0.3,0,0) + elif test_option.id == 4: + sport_client.Move(0,0.3,0) + elif test_option.id == 5: + sport_client.Move(0,0,0.5) + elif test_option.id == 6: + sport_client.StopMove() + elif test_option.id == 7: + sport_client.SwitchGait(0) + elif test_option.id == 8: + sport_client.SwitchGait(1) + elif test_option.id == 9: + sport_client.BalanceStand() + elif test_option.id == 10: + sport_client.RecoveryStand() + elif test_option.id == 11: + ret = sport_client.LeftFlip() + print("ret: ",ret) + elif test_option.id == 12: + ret = sport_client.BackFlip() + print("ret: ",ret) + elif test_option.id == 13: + ret = sport_client.FreeWalk(True) + print("ret: ",ret) + elif test_option.id == 14: + ret = sport_client.FreeBound(True) + print("ret: ",ret) + time.sleep(2) + ret = sport_client.FreeBound(False) + print("ret: ",ret) + elif test_option.id == 14: + ret = sport_client.FreeBound(True) + print("ret: ",ret) + time.sleep(2) + ret = sport_client.FreeBound(False) + print("ret: ",ret) + elif test_option.id == 15: + ret = sport_client.FreeAvoid(True) + print("ret: ",ret) + time.sleep(2) + ret = sport_client.FreeAvoid(False) + print("ret: ",ret) + elif test_option.id == 16: + ret = sport_client.WalkStair(True) + print("ret: ",ret) + time.sleep(10) + ret = sport_client.WalkStair(False) + print("ret: ",ret) + elif test_option.id == 17: + ret = sport_client.WalkUpright(True) + print("ret: ",ret) + time.sleep(4) + ret = sport_client.WalkUpright(False) + print("ret: ",ret) + elif test_option.id == 18: + ret = sport_client.CrossStep(True) + print("ret: ",ret) + time.sleep(4) + ret = sport_client.CrossStep(False) + print("ret: ",ret) + elif test_option.id == 19: + ret = sport_client.FreeJump(True) + print("ret: ",ret) + time.sleep(4) + ret = sport_client.FreeJump(False) + print("ret: ",ret) + + time.sleep(1) diff --git a/example/go2/high_level/go2_utlidar_switch.py b/example/go2/high_level/go2_utlidar_switch.py new file mode 100644 index 0000000..09e0ce9 --- /dev/null +++ b/example/go2/high_level/go2_utlidar_switch.py @@ -0,0 +1,39 @@ +import time +import sys + +from unitree_sdk2py.core.channel import ChannelPublisher, ChannelFactoryInitialize +from unitree_sdk2py.core.channel import ChannelSubscriber, ChannelFactoryInitialize +from unitree_sdk2py.idl.std_msgs.msg.dds_ import String_ +from unitree_sdk2py.idl.default import std_msgs_msg_dds__String_ + +class Custom: + def __init__(self): + # create publisher # + self.publisher = ChannelPublisher("rt/utlidar/switch", String_) + self.publisher.Init() + self.low_cmd = std_msgs_msg_dds__String_() + + def go2_utlidar_switch(self,status): + if status == "OFF": + self.low_cmd.data = "OFF" + elif status == "ON": + self.low_cmd.data = "ON" + + self.publisher.Write(self.low_cmd) + + +if __name__ == '__main__': + + print("WARNING: Please ensure there are no obstacles around the robot while running this example.") + input("Press Enter to continue...") + + if len(sys.argv)>1: + ChannelFactoryInitialize(0, sys.argv[1]) + else: + ChannelFactoryInitialize(0) + + custom = Custom() + custom.go2_utlidar_switch("OFF") + + + diff --git a/example/go2/low_level/go2_stand_example.py b/example/go2/low_level/go2_stand_example.py new file mode 100644 index 0000000..f2241ce --- /dev/null +++ b/example/go2/low_level/go2_stand_example.py @@ -0,0 +1,176 @@ +import time +import sys + +from unitree_sdk2py.core.channel import ChannelPublisher, ChannelFactoryInitialize +from unitree_sdk2py.core.channel import ChannelSubscriber, ChannelFactoryInitialize +from unitree_sdk2py.idl.default import unitree_go_msg_dds__LowCmd_ +from unitree_sdk2py.idl.default import unitree_go_msg_dds__LowState_ +from unitree_sdk2py.idl.unitree_go.msg.dds_ import LowCmd_ +from unitree_sdk2py.idl.unitree_go.msg.dds_ import LowState_ +from unitree_sdk2py.utils.crc import CRC +from unitree_sdk2py.utils.thread import RecurrentThread +import unitree_legged_const as go2 +from unitree_sdk2py.comm.motion_switcher.motion_switcher_client import MotionSwitcherClient +from unitree_sdk2py.go2.sport.sport_client import SportClient + +class Custom: + def __init__(self): + self.Kp = 60.0 + self.Kd = 5.0 + self.time_consume = 0 + self.rate_count = 0 + self.sin_count = 0 + self.motiontime = 0 + self.dt = 0.002 # 0.001~0.01 + + self.low_cmd = unitree_go_msg_dds__LowCmd_() + self.low_state = None + + self._targetPos_1 = [0.0, 1.36, -2.65, 0.0, 1.36, -2.65, + -0.2, 1.36, -2.65, 0.2, 1.36, -2.65] + self._targetPos_2 = [0.0, 0.67, -1.3, 0.0, 0.67, -1.3, + 0.0, 0.67, -1.3, 0.0, 0.67, -1.3] + self._targetPos_3 = [-0.35, 1.36, -2.65, 0.35, 1.36, -2.65, + -0.5, 1.36, -2.65, 0.5, 1.36, -2.65] + + self.startPos = [0.0] * 12 + self.duration_1 = 500 + self.duration_2 = 500 + self.duration_3 = 1000 + self.duration_4 = 900 + self.percent_1 = 0 + self.percent_2 = 0 + self.percent_3 = 0 + self.percent_4 = 0 + + self.firstRun = True + self.done = False + + # thread handling + self.lowCmdWriteThreadPtr = None + + self.crc = CRC() + + # Public methods + def Init(self): + self.InitLowCmd() + + # create publisher # + self.lowcmd_publisher = ChannelPublisher("rt/lowcmd", LowCmd_) + self.lowcmd_publisher.Init() + + # create subscriber # + self.lowstate_subscriber = ChannelSubscriber("rt/lowstate", LowState_) + self.lowstate_subscriber.Init(self.LowStateMessageHandler, 10) + + self.sc = SportClient() + self.sc.SetTimeout(5.0) + self.sc.Init() + + self.msc = MotionSwitcherClient() + self.msc.SetTimeout(5.0) + self.msc.Init() + + status, result = self.msc.CheckMode() + while result['name']: + self.sc.StandDown() + self.msc.ReleaseMode() + status, result = self.msc.CheckMode() + time.sleep(1) + + def Start(self): + self.lowCmdWriteThreadPtr = RecurrentThread( + interval=0.002, target=self.LowCmdWrite, name="writebasiccmd" + ) + self.lowCmdWriteThreadPtr.Start() + + # Private methods + def InitLowCmd(self): + self.low_cmd.head[0]=0xFE + self.low_cmd.head[1]=0xEF + self.low_cmd.level_flag = 0xFF + self.low_cmd.gpio = 0 + for i in range(20): + self.low_cmd.motor_cmd[i].mode = 0x01 # (PMSM) mode + self.low_cmd.motor_cmd[i].q= go2.PosStopF + self.low_cmd.motor_cmd[i].kp = 0 + self.low_cmd.motor_cmd[i].dq = go2.VelStopF + self.low_cmd.motor_cmd[i].kd = 0 + self.low_cmd.motor_cmd[i].tau = 0 + + def LowStateMessageHandler(self, msg: LowState_): + self.low_state = msg + # print("FR_0 motor state: ", msg.motor_state[go2.LegID["FR_0"]]) + # print("IMU state: ", msg.imu_state) + # print("Battery state: voltage: ", msg.power_v, "current: ", msg.power_a) + + def LowCmdWrite(self): + + if self.firstRun: + for i in range(12): + self.startPos[i] = self.low_state.motor_state[i].q + self.firstRun = False + + self.percent_1 += 1.0 / self.duration_1 + self.percent_1 = min(self.percent_1, 1) + if self.percent_1 < 1: + for i in range(12): + self.low_cmd.motor_cmd[i].q = (1 - self.percent_1) * self.startPos[i] + self.percent_1 * self._targetPos_1[i] + self.low_cmd.motor_cmd[i].dq = 0 + self.low_cmd.motor_cmd[i].kp = self.Kp + self.low_cmd.motor_cmd[i].kd = self.Kd + self.low_cmd.motor_cmd[i].tau = 0 + + if (self.percent_1 == 1) and (self.percent_2 <= 1): + self.percent_2 += 1.0 / self.duration_2 + self.percent_2 = min(self.percent_2, 1) + for i in range(12): + self.low_cmd.motor_cmd[i].q = (1 - self.percent_2) * self._targetPos_1[i] + self.percent_2 * self._targetPos_2[i] + self.low_cmd.motor_cmd[i].dq = 0 + self.low_cmd.motor_cmd[i].kp = self.Kp + self.low_cmd.motor_cmd[i].kd = self.Kd + self.low_cmd.motor_cmd[i].tau = 0 + + if (self.percent_1 == 1) and (self.percent_2 == 1) and (self.percent_3 < 1): + self.percent_3 += 1.0 / self.duration_3 + self.percent_3 = min(self.percent_3, 1) + for i in range(12): + self.low_cmd.motor_cmd[i].q = self._targetPos_2[i] + self.low_cmd.motor_cmd[i].dq = 0 + self.low_cmd.motor_cmd[i].kp = self.Kp + self.low_cmd.motor_cmd[i].kd = self.Kd + self.low_cmd.motor_cmd[i].tau = 0 + + if (self.percent_1 == 1) and (self.percent_2 == 1) and (self.percent_3 == 1) and (self.percent_4 <= 1): + self.percent_4 += 1.0 / self.duration_4 + self.percent_4 = min(self.percent_4, 1) + for i in range(12): + self.low_cmd.motor_cmd[i].q = (1 - self.percent_4) * self._targetPos_2[i] + self.percent_4 * self._targetPos_3[i] + self.low_cmd.motor_cmd[i].dq = 0 + self.low_cmd.motor_cmd[i].kp = self.Kp + self.low_cmd.motor_cmd[i].kd = self.Kd + self.low_cmd.motor_cmd[i].tau = 0 + + self.low_cmd.crc = self.crc.Crc(self.low_cmd) + self.lowcmd_publisher.Write(self.low_cmd) + +if __name__ == '__main__': + + print("WARNING: Please ensure there are no obstacles around the robot while running this example.") + input("Press Enter to continue...") + + if len(sys.argv)>1: + ChannelFactoryInitialize(0, sys.argv[1]) + else: + ChannelFactoryInitialize(0) + + custom = Custom() + custom.Init() + custom.Start() + + while True: + if custom.percent_4 == 1.0: + time.sleep(1) + print("Done!") + sys.exit(-1) + time.sleep(1) \ No newline at end of file diff --git a/example/go2/low_level/unitree_legged_const.py b/example/go2/low_level/unitree_legged_const.py new file mode 100644 index 0000000..153a051 --- /dev/null +++ b/example/go2/low_level/unitree_legged_const.py @@ -0,0 +1,20 @@ +LegID = { + "FR_0": 0, # Front right hip + "FR_1": 1, # Front right thigh + "FR_2": 2, # Front right calf + "FL_0": 3, + "FL_1": 4, + "FL_2": 5, + "RR_0": 6, + "RR_1": 7, + "RR_2": 8, + "RL_0": 9, + "RL_1": 10, + "RL_2": 11, +} + +HIGHLEVEL = 0xEE +LOWLEVEL = 0xFF +TRIGERLEVEL = 0xF0 +PosStopF = 2.146e9 +VelStopF = 16000.0 diff --git a/example/go2w/high_level/go2w_sport_client.py b/example/go2w/high_level/go2w_sport_client.py new file mode 100644 index 0000000..824a882 --- /dev/null +++ b/example/go2w/high_level/go2w_sport_client.py @@ -0,0 +1,99 @@ +import time +import sys +from unitree_sdk2py.core.channel import ChannelSubscriber, ChannelFactoryInitialize +from unitree_sdk2py.idl.default import unitree_go_msg_dds__SportModeState_ +from unitree_sdk2py.idl.unitree_go.msg.dds_ import SportModeState_ +from unitree_sdk2py.go2.sport.sport_client import SportClient +import math +from dataclasses import dataclass + +@dataclass +class TestOption: + name: str + id: int + +option_list = [ + TestOption(name="damp", id=0), + TestOption(name="stand_up", id=1), + TestOption(name="stand_down", id=2), + TestOption(name="move", id=3), + TestOption(name="stop_move", id=4), + TestOption(name="speed_level", id=5), + TestOption(name="switch_gait", id=6), + TestOption(name="get_state", id=7), + TestOption(name="recovery", id=8), + TestOption(name="balance", id=9) +] + +class UserInterface: + def __init__(self): + self.test_option_ = None + + def convert_to_int(self, input_str): + try: + return int(input_str) + except ValueError: + return None + + def terminal_handle(self): + input_str = input("Enter id or name: \n") + + if input_str == "list": + self.test_option_.name = None + self.test_option_.id = None + for option in option_list: + print(f"{option.name}, id: {option.id}") + return + + for option in option_list: + if input_str == option.name or self.convert_to_int(input_str) == option.id: + self.test_option_.name = option.name + self.test_option_.id = option.id + print(f"Test: {self.test_option_.name}, test_id: {self.test_option_.id}") + return + + print("No matching test option found.") + +if __name__ == "__main__": + if len(sys.argv) < 2: + print(f"Usage: python3 {sys.argv[0]} networkInterface") + sys.exit(-1) + + print("WARNING: Please ensure there are no obstacles around the robot while running this example.") + input("Press Enter to continue...") + + ChannelFactoryInitialize(0, sys.argv[1]) + + test_option = TestOption(name=None, id=None) + user_interface = UserInterface() + user_interface.test_option_ = test_option + + sport_client = SportClient() + sport_client.SetTimeout(10.0) + sport_client.Init() + + while True: + user_interface.terminal_handle() + + print(f"Updated Test Option: Name = {test_option.name}, ID = {test_option.id}\n") + + if test_option.id == 0: + sport_client.Damp() + elif test_option.id == 1: + sport_client.StandUp() + elif test_option.id == 2: + sport_client.StandDown() + elif test_option.id == 3: + sport_client.Move(0.5,0,0) + elif test_option.id == 4: + sport_client.StopMove() + elif test_option.id == 5: + sport_client.SpeedLevel(1) + elif test_option.id == 6: + sport_client.SwitchGait(1) + elif test_option.id == 8: + sport_client.RecoveryStand() + elif test_option.id == 9: + sport_client.BalanceStand() + + time.sleep(1) diff --git a/example/go2w/low_level/go2w_stand_example.py b/example/go2w/low_level/go2w_stand_example.py new file mode 100644 index 0000000..e3a54de --- /dev/null +++ b/example/go2w/low_level/go2w_stand_example.py @@ -0,0 +1,196 @@ +import time +import sys + +from unitree_sdk2py.core.channel import ChannelPublisher, ChannelFactoryInitialize +from unitree_sdk2py.core.channel import ChannelSubscriber, ChannelFactoryInitialize +from unitree_sdk2py.idl.default import unitree_go_msg_dds__LowCmd_ +from unitree_sdk2py.idl.default import unitree_go_msg_dds__LowState_ +from unitree_sdk2py.idl.unitree_go.msg.dds_ import LowCmd_ +from unitree_sdk2py.idl.unitree_go.msg.dds_ import LowState_ +from unitree_sdk2py.utils.crc import CRC +from unitree_sdk2py.utils.thread import RecurrentThread +import unitree_legged_const as go2w +from unitree_sdk2py.go2.robot_state.robot_state_client import RobotStateClient +from unitree_sdk2py.comm.motion_switcher.motion_switcher_client import MotionSwitcherClient +from unitree_sdk2py.go2.sport.sport_client import SportClient + +class Custom: + def __init__(self): + self.Kp = 70.0 + self.Kd = 5.0 + self.time_consume = 0 + self.rate_count = 0 + self.sin_count = 0 + self.motiontime = 0 + self.dt = 0.002 + + self.low_cmd = unitree_go_msg_dds__LowCmd_() + self.low_state = None + + self.targetPos_1 = [0.0, 1.36, -2.65, 0.0, 1.36, -2.65, + -0.2, 1.36, -2.65, 0.2, 1.36, -2.65] + + self.targetPos_2 = [0.0, 0.67, -1.3, 0.0, 0.67, -1.3, + 0.0, 0.67, -1.3, 0.0, 0.67, -1.3] + + self.targetPos_3 = [-0.35, 1.36, -2.65, 0.35, 1.36, -2.65, + -0.5, 1.36, -2.65, 0.5, 1.36, -2.65] + + self.startPos = [0.0] * 12 + self.duration_1 = 500 + self.duration_2 = 500 + self.duration_3 = 2000 + self.duration_4 = 900 + self.percent_1 = 0 + self.percent_2 = 0 + self.percent_3 = 0 + self.percent_4 = 0 + + self.firstRun = True + self.done = False + + # thread handling + self.lowCmdWriteThreadPtr = None + + self.crc = CRC() + + # Public methods + def Init(self): + self.InitLowCmd() + + # create publisher # + self.lowcmd_publisher = ChannelPublisher("rt/lowcmd", LowCmd_) + self.lowcmd_publisher.Init() + + # create subscriber # + self.lowstate_subscriber = ChannelSubscriber("rt/lowstate", LowState_) + self.lowstate_subscriber.Init(self.LowStateMessageHandler, 10) + + self.sc = SportClient() + self.sc.SetTimeout(5.0) + self.sc.Init() + + self.msc = MotionSwitcherClient() + self.msc.SetTimeout(5.0) + self.msc.Init() + + status, result = self.msc.CheckMode() + while result['name']: + self.sc.StandUp() + self.sc.StandDown() + self.msc.ReleaseMode() + status, result = self.msc.CheckMode() + time.sleep(1) + + def Start(self): + self.lowCmdWriteThreadPtr = RecurrentThread( + name="writebasiccmd", interval=0.002, target=self.LowCmdWrite, + ) + self.lowCmdWriteThreadPtr.Start() + + def InitLowCmd(self): + self.low_cmd.head[0] = 0xFE + self.low_cmd.head[1] = 0xEF + self.low_cmd.level_flag = 0xFF + self.low_cmd.gpio = 0 + for i in range(20): + self.low_cmd.motor_cmd[i].mode = 0x01 + self.low_cmd.motor_cmd[i].q= go2w.PosStopF + self.low_cmd.motor_cmd[i].kp = 0 + self.low_cmd.motor_cmd[i].dq = go2w.VelStopF + self.low_cmd.motor_cmd[i].kd = 0 + self.low_cmd.motor_cmd[i].tau = 0 + + def LowStateMessageHandler(self, msg: LowState_): + self.low_state = msg + + def LowCmdWrite(self): + if self.firstRun: + for i in range(12): + self.startPos[i] = self.low_state.motor_state[i].q + self.firstRun = False + + self.percent_1 += 1.0 / self.duration_1 + self.percent_1 = min(self.percent_1, 1) + if self.percent_1 < 1: + for i in range(12): + self.low_cmd.motor_cmd[i].q = (1 - self.percent_1) * self.startPos[i] + self.percent_1 * self.targetPos_1[i] + self.low_cmd.motor_cmd[i].dq = 0 + self.low_cmd.motor_cmd[i].kp = self.Kp + self.low_cmd.motor_cmd[i].kd = self.Kd + self.low_cmd.motor_cmd[i].tau = 0 + + if (self.percent_1 == 1) and (self.percent_2 <= 1): + self.percent_2 += 1.0 / self.duration_2 + self.percent_2 = min(self.percent_2, 1) + for i in range(12): + self.low_cmd.motor_cmd[i].q = (1 - self.percent_2) * self.targetPos_1[i] + self.percent_2 * self.targetPos_2[i] + self.low_cmd.motor_cmd[i].dq = 0 + self.low_cmd.motor_cmd[i].kp = self.Kp + self.low_cmd.motor_cmd[i].kd = self.Kd + self.low_cmd.motor_cmd[i].tau = 0 + + if (self.percent_1 == 1) and (self.percent_2 == 1) and (self.percent_3 < 1): + self.percent_3 += 1.0 / self.duration_3 + self.percent_3 = min(self.percent_3, 1) + for i in range(12): + self.low_cmd.motor_cmd[i].q = self.targetPos_2[i] + self.low_cmd.motor_cmd[i].dq = 0 + self.low_cmd.motor_cmd[i].kp = self.Kp + self.low_cmd.motor_cmd[i].kd = self.Kd + self.low_cmd.motor_cmd[i].tau = 0 + + if self.percent_3 < 0.4: + for i in range(12, 16): + self.low_cmd.motor_cmd[i].q = 0 + self.low_cmd.motor_cmd[i].kp = 0.0 + self.low_cmd.motor_cmd[i].dq = 3 + self.low_cmd.motor_cmd[i].kd = self.Kd + self.low_cmd.motor_cmd[i].tau = 0 + + if 0.4 <= self.percent_3 < 0.8: + for i in range(12, 16): + self.low_cmd.motor_cmd[i].q = 0 + self.low_cmd.motor_cmd[i].kp = 0 + self.low_cmd.motor_cmd[i].dq = -3 + self.low_cmd.motor_cmd[i].kd = self.Kd + self.low_cmd.motor_cmd[i].tau = 0 + + if self.percent_3 >= 0.8: + for i in range(12, 16): + self.low_cmd.motor_cmd[i].q = 0 + self.low_cmd.motor_cmd[i].kp = 0 + self.low_cmd.motor_cmd[i].dq = 0 + self.low_cmd.motor_cmd[i].kd = self.Kd + self.low_cmd.motor_cmd[i].tau = 0 + + if (self.percent_1 == 1) and (self.percent_2 == 1) and (self.percent_3 == 1) and (self.percent_4 <= 1): + self.percent_4 += 1.0 / self.duration_4 + self.percent_4 = min(self.percent_4, 1) + for i in range(12): + self.low_cmd.motor_cmd[i].q = (1 - self.percent_4) * self.targetPos_2[i] + self.percent_4 * self.targetPos_3[i] + self.low_cmd.motor_cmd[i].dq = 0 + self.low_cmd.motor_cmd[i].kp = self.Kp + self.low_cmd.motor_cmd[i].kd = self.Kd + self.low_cmd.motor_cmd[i].tau = 0 + + self.low_cmd.crc = self.crc.Crc(self.low_cmd) + self.lowcmd_publisher.Write(self.low_cmd) + +if __name__ == '__main__': + + if len(sys.argv)>1: + ChannelFactoryInitialize(0, sys.argv[1]) + else: + ChannelFactoryInitialize(0) + + custom = Custom() + custom.Init() + custom.Start() + + while True: + if custom.percent_4 == 1.0: + time.sleep(1) + print("Done!") + sys.exit(-1) + time.sleep(1) \ No newline at end of file diff --git a/example/go2w/low_level/unitree_legged_const.py b/example/go2w/low_level/unitree_legged_const.py new file mode 100644 index 0000000..7943e31 --- /dev/null +++ b/example/go2w/low_level/unitree_legged_const.py @@ -0,0 +1,24 @@ +LegID = { + "FR_0": 0, # Front right hip + "FR_1": 1, # Front right thigh + "FR_2": 2, # Front right calf + "FL_0": 3, + "FL_1": 4, + "FL_2": 5, + "RR_0": 6, + "RR_1": 7, + "RR_2": 8, + "RL_0": 9, + "RL_1": 10, + "RL_2": 11, + "FR_w": 12, # Front right wheel + "FL_w": 13, # Front left wheel + "RR_w": 14, # Rear right wheel + "RL_w": 15, # Rear left wheel +} + +HIGHLEVEL = 0xEE +LOWLEVEL = 0xFF +TRIGERLEVEL = 0xF0 +PosStopF = 2.146e9 +VelStopF = 16000.0 diff --git a/example/h1/high_level/h1_loco_client_example.py b/example/h1/high_level/h1_loco_client_example.py new file mode 100644 index 0000000..4432d8a --- /dev/null +++ b/example/h1/high_level/h1_loco_client_example.py @@ -0,0 +1,96 @@ +import time +import sys +from unitree_sdk2py.core.channel import ChannelSubscriber, ChannelFactoryInitialize +from unitree_sdk2py.idl.default import unitree_go_msg_dds__SportModeState_ +from unitree_sdk2py.idl.unitree_go.msg.dds_ import SportModeState_ +from unitree_sdk2py.h1.loco.h1_loco_client import LocoClient +import math +from dataclasses import dataclass + +@dataclass +class TestOption: + name: str + id: int + +option_list = [ + TestOption(name="damp", id=0), + TestOption(name="stand_up", id=1), + TestOption(name="move forward", id=3), + TestOption(name="move lateral", id=4), + TestOption(name="move rotate", id=5), + TestOption(name="low stand", id=6), + TestOption(name="high stand", id=7), + TestOption(name="zero torque", id=8) +] + +class UserInterface: + def __init__(self): + self.test_option_ = None + + def convert_to_int(self, input_str): + try: + return int(input_str) + except ValueError: + return None + + def terminal_handle(self): + input_str = input("Enter id or name: \n") + + if input_str == "list": + self.test_option_.name = None + self.test_option_.id = None + for option in option_list: + print(f"{option.name}, id: {option.id}") + return + + for option in option_list: + if input_str == option.name or self.convert_to_int(input_str) == option.id: + self.test_option_.name = option.name + self.test_option_.id = option.id + print(f"Test: {self.test_option_.name}, test_id: {self.test_option_.id}") + return + + print("No matching test option found.") + +if __name__ == "__main__": + + print("WARNING: Please ensure there are no obstacles around the robot while running this example.") + input("Press Enter to continue...") + + if len(sys.argv)>1: + ChannelFactoryInitialize(0, sys.argv[1]) + else: + ChannelFactoryInitialize(0) + + test_option = TestOption(name=None, id=None) + user_interface = UserInterface() + user_interface.test_option_ = test_option + + sport_client = LocoClient() + sport_client.SetTimeout(10.0) + sport_client.Init() + + while True: + + user_interface.terminal_handle() + + print(f"Updated Test Option: Name = {test_option.name}, ID = {test_option.id}\n") + + if test_option.id == 0: + sport_client.Damp() + elif test_option.id == 1: + sport_client.StandUp() + elif test_option.id == 3: + sport_client.Move(0.3,0,0) + elif test_option.id == 4: + sport_client.Move(0,0.3,0) + elif test_option.id == 5: + sport_client.Move(0,0,0.3) + elif test_option.id == 6: + sport_client.LowStand() + elif test_option.id == 7: + sport_client.HighStand() + elif test_option.id == 8: + sport_client.ZeroTorque() + + time.sleep(1) \ No newline at end of file diff --git a/example/h1/low_level/h1_low_level_example.py b/example/h1/low_level/h1_low_level_example.py new file mode 100644 index 0000000..51a9111 --- /dev/null +++ b/example/h1/low_level/h1_low_level_example.py @@ -0,0 +1,167 @@ +import time +import sys + +from unitree_sdk2py.core.channel import ChannelPublisher, ChannelFactoryInitialize +from unitree_sdk2py.core.channel import ChannelSubscriber, ChannelFactoryInitialize +from unitree_sdk2py.idl.default import unitree_go_msg_dds__LowCmd_ +from unitree_sdk2py.idl.default import unitree_go_msg_dds__LowState_ +from unitree_sdk2py.idl.unitree_go.msg.dds_ import LowCmd_ +from unitree_sdk2py.idl.unitree_go.msg.dds_ import LowState_ +from unitree_sdk2py.utils.crc import CRC +from unitree_sdk2py.utils.thread import RecurrentThread +from unitree_sdk2py.comm.motion_switcher.motion_switcher_client import MotionSwitcherClient +import unitree_legged_const as h1 +import numpy as np + +H1_NUM_MOTOR = 20 + +class H1JointIndex: + # Right leg + kRightHipYaw = 8 + kRightHipRoll = 0 + kRightHipPitch = 1 + kRightKnee = 2 + kRightAnkle = 11 + # Left leg + kLeftHipYaw = 7 + kLeftHipRoll = 3 + kLeftHipPitch = 4 + kLeftKnee = 5 + kLeftAnkle = 10 + + kWaistYaw = 6 + + kNotUsedJoint = 9 + + # Right arm + kRightShoulderPitch = 12 + kRightShoulderRoll = 13 + kRightShoulderYaw = 14 + kRightElbow = 15 + # Left arm + kLeftShoulderPitch = 16 + kLeftShoulderRoll = 17 + kLeftShoulderYaw = 18 + kLeftElbow = 19 + +class Custom: + def __init__(self): + self.time_ = 0.0 + self.control_dt_ = 0.01 + self.duration_ = 10.0 + self.counter_ = 0 + self.kp_low_ = 60.0 + self.kp_high_ = 200.0 + self.kd_low_ = 1.5 + self.kd_high_ = 5.0 + self.low_cmd = unitree_go_msg_dds__LowCmd_() + self.InitLowCmd() + self.low_state = None + self.crc = CRC() + + def Init(self): + # # create publisher # + self.lowcmd_publisher_ = ChannelPublisher("rt/lowcmd", LowCmd_) + self.lowcmd_publisher_.Init() + + # # create subscriber # + self.lowstate_subscriber = ChannelSubscriber("rt/lowstate", LowState_) + self.lowstate_subscriber.Init(self.LowStateHandler, 10) + + self.msc = MotionSwitcherClient() + self.msc.SetTimeout(5.0) + self.msc.Init() + + status, result = self.msc.CheckMode() + while result['name']: + self.msc.ReleaseMode() + status, result = self.msc.CheckMode() + time.sleep(1) + + self.report_rpy_ptr_ = RecurrentThread( + interval=0.1, target=self.ReportRPY, name="report_rpy" + ) + + self.report_rpy_ptr_.Start() + + def is_weak_motor(self,motor_index): + return motor_index in { + H1JointIndex.kLeftAnkle, + H1JointIndex.kRightAnkle, + H1JointIndex.kRightShoulderPitch, + H1JointIndex.kRightShoulderRoll, + H1JointIndex.kRightShoulderYaw, + H1JointIndex.kRightElbow, + H1JointIndex.kLeftShoulderPitch, + H1JointIndex.kLeftShoulderRoll, + H1JointIndex.kLeftShoulderYaw, + H1JointIndex.kLeftElbow, + } + + def InitLowCmd(self): + self.low_cmd.head[0] = 0xFE + self.low_cmd.head[1] = 0xEF + self.low_cmd.level_flag = 0xFF + self.low_cmd.gpio = 0 + for i in range(H1_NUM_MOTOR): + if self.is_weak_motor(i): + self.low_cmd.motor_cmd[i].mode = 0x01 + else: + self.low_cmd.motor_cmd[i].mode = 0x0A + self.low_cmd.motor_cmd[i].q= h1.PosStopF + self.low_cmd.motor_cmd[i].kp = 0 + self.low_cmd.motor_cmd[i].dq = h1.VelStopF + self.low_cmd.motor_cmd[i].kd = 0 + self.low_cmd.motor_cmd[i].tau = 0 + + def Start(self): + self.lowCmdWriteThreadPtr = RecurrentThread( + interval=self.control_dt_, target=self.LowCmdWrite, name="control" + ) + self.lowCmdWriteThreadPtr.Start() + + def LowStateHandler(self, msg: LowState_): + self.low_state = msg + + def ReportRPY(self): + print("rpy: [",self.low_state.imu_state.rpy[0],", " + ,self.low_state.imu_state.rpy[1],", " + ,self.low_state.imu_state.rpy[2],"]" + ) + + def LowCmdWrite(self): + self.time_ += self.control_dt_ + self.time_ = np.clip(self.time_ , 0.0, self.duration_) + + # set robot to zero posture + for i in range(H1_NUM_MOTOR): + ratio = self.time_ / self.duration_ + self.low_cmd.motor_cmd[i].tau = 0. + self.low_cmd.motor_cmd[i].q = (1.0 - ratio) * self.low_state.motor_state[i].q + self.low_cmd.motor_cmd[i].dq = 0. + self.low_cmd.motor_cmd[i].kp = self.kp_low_ if self.is_weak_motor(i) else self.kp_high_ + self.low_cmd.motor_cmd[i].kd = self.kd_low_ if self.is_weak_motor(i) else self.kd_high_ + + self.low_cmd.crc = self.crc.Crc(self.low_cmd) + self.lowcmd_publisher_.Write(self.low_cmd) + +if __name__ == '__main__': + + print("WARNING: Please ensure there are no obstacles around the robot while running this example.") + input("Press Enter to continue...") + + if len(sys.argv)>1: + ChannelFactoryInitialize(0, sys.argv[1]) + else: + ChannelFactoryInitialize(0) + + custom = Custom() + custom.Init() + custom.Start() + + while True: + if custom.time_ == custom.duration_: + time.sleep(1) + print("Done!") + sys.exit(-1) + time.sleep(1) \ No newline at end of file diff --git a/example/h1/low_level/unitree_legged_const.py b/example/h1/low_level/unitree_legged_const.py new file mode 100644 index 0000000..c9112ea --- /dev/null +++ b/example/h1/low_level/unitree_legged_const.py @@ -0,0 +1,5 @@ +HIGHLEVEL = 0xEE +LOWLEVEL = 0xFF +TRIGERLEVEL = 0xF0 +PosStopF = 2.146e9 +VelStopF = 16000.0 diff --git a/example/h1_2/low_level/h1_2_low_level_example.py b/example/h1_2/low_level/h1_2_low_level_example.py new file mode 100644 index 0000000..0959b32 --- /dev/null +++ b/example/h1_2/low_level/h1_2_low_level_example.py @@ -0,0 +1,201 @@ +import time +import sys + +from unitree_sdk2py.core.channel import ChannelPublisher, ChannelFactoryInitialize +from unitree_sdk2py.core.channel import ChannelSubscriber, ChannelFactoryInitialize +from unitree_sdk2py.idl.default import unitree_hg_msg_dds__LowCmd_ +from unitree_sdk2py.idl.default import unitree_hg_msg_dds__LowState_ +from unitree_sdk2py.idl.unitree_hg.msg.dds_ import LowCmd_ +from unitree_sdk2py.idl.unitree_hg.msg.dds_ import LowState_ +from unitree_sdk2py.utils.crc import CRC +from unitree_sdk2py.utils.thread import RecurrentThread +from unitree_sdk2py.comm.motion_switcher.motion_switcher_client import MotionSwitcherClient + +import numpy as np + +H1_2_NUM_MOTOR = 27 + +class H1_2_JointIndex: + # legs + LeftHipYaw = 0 + LeftHipPitch = 1 + LeftHipRoll = 2 + LeftKnee = 3 + LeftAnklePitch = 4 + LeftAnkleB = 4 + LeftAnkleRoll = 5 + LeftAnkleA = 5 + RightHipYaw = 6 + RightHipPitch = 7 + RightHipRoll = 8 + RightKnee = 9 + RightAnklePitch = 10 + RightAnkleB = 10 + RightAnkleRoll = 11 + RightAnkleA = 11 + # torso + WaistYaw = 12 + # arms + LeftShoulderPitch = 13 + LeftShoulderRoll = 14 + LeftShoulderYaw = 15 + LeftElbow = 16 + LeftWristRoll = 17 + LeftWristPitch = 18 + LeftWristYaw = 19 + RightShoulderPitch = 20 + RightShoulderRoll = 21 + RightShoulderYaw = 22 + RightElbow = 23 + RightWristRoll = 24 + RightWristPitch = 25 + RightWristYaw = 26 + + +class Mode: + PR = 0 # Series Control for Pitch/Roll Joints + AB = 1 # Parallel Control for A/B Joints + +class Custom: + def __init__(self): + self.time_ = 0.0 + self.control_dt_ = 0.002 # [2ms] + self.duration_ = 3.0 # [3 s] + self.counter_ = 0 + self.mode_pr_ = Mode.PR + self.mode_machine_ = 0 + self.low_cmd = unitree_hg_msg_dds__LowCmd_() + self.low_state = None + self.update_mode_machine_ = False + self.crc = CRC() + + def Init(self): + self.msc = MotionSwitcherClient() + self.msc.SetTimeout(5.0) + self.msc.Init() + + status, result = self.msc.CheckMode() + while result['name']: + self.msc.ReleaseMode() + status, result = self.msc.CheckMode() + time.sleep(1) + + # create publisher # + self.lowcmd_publisher_ = ChannelPublisher("rt/lowcmd", LowCmd_) + self.lowcmd_publisher_.Init() + + # create subscriber # + self.lowstate_subscriber = ChannelSubscriber("rt/lowstate", LowState_) + self.lowstate_subscriber.Init(self.LowStateHandler, 10) + + def Start(self): + self.lowCmdWriteThreadPtr = RecurrentThread( + interval=self.control_dt_, target=self.LowCmdWrite, name="control" + ) + while self.update_mode_machine_ == False: + time.sleep(1) + + if self.update_mode_machine_ == True: + self.lowCmdWriteThreadPtr.Start() + + def LowStateHandler(self, msg: LowState_): + self.low_state = msg + + if self.update_mode_machine_ == False: + self.mode_machine_ = self.low_state.mode_machine + self.update_mode_machine_ = True + + self.counter_ +=1 + if (self.counter_ % 500 == 0) : + self.counter_ = 0 + print(self.low_state.imu_state.rpy) + + def LowCmdWrite(self): + self.time_ += self.control_dt_ + self.low_cmd.mode_pr = Mode.PR + self.low_cmd.mode_machine = self.mode_machine_ + for i in range(H1_2_NUM_MOTOR): + ratio = np.clip(self.time_ / self.duration_, 0.0, 1.0) + self.low_cmd.motor_cmd[i].mode = 1 # 1:Enable, 0:Disable + self.low_cmd.motor_cmd[i].tau = 0.0 + self.low_cmd.motor_cmd[i].q = 0.0 + self.low_cmd.motor_cmd[i].dq = 0.0 + self.low_cmd.motor_cmd[i].kp = 100.0 if i < 13 else 50.0 + self.low_cmd.motor_cmd[i].kd = 1.0 + + if self.time_ < self.duration_ : + # [Stage 1]: set robot to zero posture + for i in range(H1_2_NUM_MOTOR): + ratio = np.clip(self.time_ / self.duration_, 0.0, 1.0) + self.low_cmd.mode_pr = Mode.PR + self.low_cmd.mode_machine = self.mode_machine_ + self.low_cmd.motor_cmd[i].mode = 1 # 1:Enable, 0:Disable + self.low_cmd.motor_cmd[i].tau = 0. + self.low_cmd.motor_cmd[i].q = (1.0 - ratio) * self.low_state.motor_state[i].q + self.low_cmd.motor_cmd[i].dq = 0. + self.low_cmd.motor_cmd[i].kp = 100.0 if i < 13 else 50.0 + self.low_cmd.motor_cmd[i].kd = 1.0 + else : + # [Stage 2]: swing ankle using PR mode + max_P = 0.25 + max_R = 0.25 + t = self.time_ - self.duration_ + L_P_des = max_P * np.cos(2.0 * np.pi * t) + L_R_des = max_R * np.sin(2.0 * np.pi * t) + R_P_des = max_P * np.cos(2.0 * np.pi * t) + R_R_des = -max_R * np.sin(2.0 * np.pi * t) + + Kp_Pitch = 80 + Kd_Pitch = 1 + Kp_Roll = 80 + Kd_Roll = 1 + + self.low_cmd.mode_pr = Mode.PR + self.low_cmd.mode_machine = self.mode_machine_ + self.low_cmd.motor_cmd[H1_2_JointIndex.LeftAnklePitch].q = L_P_des + self.low_cmd.motor_cmd[H1_2_JointIndex.LeftAnklePitch].dq = 0 + self.low_cmd.motor_cmd[H1_2_JointIndex.LeftAnklePitch].kp = Kp_Pitch + self.low_cmd.motor_cmd[H1_2_JointIndex.LeftAnklePitch].kd = Kd_Pitch + self.low_cmd.motor_cmd[H1_2_JointIndex.LeftAnkleRoll].q = L_R_des + self.low_cmd.motor_cmd[H1_2_JointIndex.LeftAnkleRoll].dq = 0 + self.low_cmd.motor_cmd[H1_2_JointIndex.LeftAnkleRoll].kp = Kp_Roll + self.low_cmd.motor_cmd[H1_2_JointIndex.LeftAnkleRoll].kd = Kd_Roll + self.low_cmd.motor_cmd[H1_2_JointIndex.RightAnklePitch].q = R_P_des + self.low_cmd.motor_cmd[H1_2_JointIndex.RightAnklePitch].dq = 0 + self.low_cmd.motor_cmd[H1_2_JointIndex.RightAnklePitch].kp = Kp_Pitch + self.low_cmd.motor_cmd[H1_2_JointIndex.RightAnklePitch].kd = Kd_Pitch + self.low_cmd.motor_cmd[H1_2_JointIndex.RightAnkleRoll].q = R_R_des + self.low_cmd.motor_cmd[H1_2_JointIndex.RightAnkleRoll].dq = 0 + self.low_cmd.motor_cmd[H1_2_JointIndex.RightAnkleRoll].kp = Kp_Roll + self.low_cmd.motor_cmd[H1_2_JointIndex.RightAnkleRoll].kd = Kd_Roll + + max_wrist_roll_angle = 0.5; # [rad] + WristRoll_des = max_wrist_roll_angle * np.sin(2.0 * np.pi * t) + self.low_cmd.motor_cmd[H1_2_JointIndex.LeftWristRoll].q = WristRoll_des + self.low_cmd.motor_cmd[H1_2_JointIndex.LeftWristRoll].dq = 0 + self.low_cmd.motor_cmd[H1_2_JointIndex.LeftWristRoll].kp = 50 + self.low_cmd.motor_cmd[H1_2_JointIndex.LeftWristRoll].kd = 1 + self.low_cmd.motor_cmd[H1_2_JointIndex.RightWristRoll].q = WristRoll_des + self.low_cmd.motor_cmd[H1_2_JointIndex.RightWristRoll].dq = 0 + self.low_cmd.motor_cmd[H1_2_JointIndex.RightWristRoll].kp = 50 + self.low_cmd.motor_cmd[H1_2_JointIndex.RightWristRoll].kd = 1 + + self.low_cmd.crc = self.crc.Crc(self.low_cmd) + self.lowcmd_publisher_.Write(self.low_cmd) + +if __name__ == '__main__': + + print("WARNING: Please ensure there are no obstacles around the robot while running this example.") + input("Press Enter to continue...") + + if len(sys.argv)>1: + ChannelFactoryInitialize(0, sys.argv[1]) + else: + ChannelFactoryInitialize(0) + + custom = Custom() + custom.Init() + custom.Start() + + while True: + time.sleep(1) \ No newline at end of file diff --git a/example/helloworld/publisher.py b/example/helloworld/publisher.py new file mode 100644 index 0000000..cfe4f1f --- /dev/null +++ b/example/helloworld/publisher.py @@ -0,0 +1,28 @@ +import time + +from unitree_sdk2py.core.channel import ChannelPublisher, ChannelFactoryInitialize +from user_data import * + + +if __name__ == "__main__": + ChannelFactoryInitialize() + + # Create a publisher to publish the data defined in UserData class + pub = ChannelPublisher("topic", UserData) + pub.Init() + + for i in range(30): + # Create a Userdata message + msg = UserData(" ", 0) + msg.string_data = "Hello world" + msg.float_data = time.time() + + # Publish message + if pub.Write(msg, 0.5): + print("Publish success. msg:", msg) + else: + print("Waitting for subscriber.") + + time.sleep(1) + + pub.Close() diff --git a/example/helloworld/subscriber.py b/example/helloworld/subscriber.py new file mode 100644 index 0000000..a7d0b63 --- /dev/null +++ b/example/helloworld/subscriber.py @@ -0,0 +1,20 @@ +import time + +from unitree_sdk2py.core.channel import ChannelSubscriber, ChannelFactoryInitialize +from user_data import * + + +if __name__ == "__main__": + ChannelFactoryInitialize() + # Create a subscriber to subscribe the data defined in UserData class + sub = ChannelSubscriber("topic", UserData) + sub.Init() + + while True: + msg = sub.Read() + if msg is not None: + print("Subscribe success. msg:", msg) + else: + print("No data subscribed.") + break + sub.Close() diff --git a/example/helloworld/user_data.py b/example/helloworld/user_data.py new file mode 100644 index 0000000..9696ce3 --- /dev/null +++ b/example/helloworld/user_data.py @@ -0,0 +1,9 @@ +from dataclasses import dataclass +from cyclonedds.idl import IdlStruct + + +# This class defines user data consisting of a float data and a string data +@dataclass +class UserData(IdlStruct, typename="UserData"): + string_data: str + float_data: float diff --git a/example/motionSwitcher/motion_switcher_example.py b/example/motionSwitcher/motion_switcher_example.py new file mode 100644 index 0000000..4f39f72 --- /dev/null +++ b/example/motionSwitcher/motion_switcher_example.py @@ -0,0 +1,36 @@ +import time +import sys + +from unitree_sdk2py.core.channel import ChannelFactoryInitialize +from unitree_sdk2py.comm.motion_switcher.motion_switcher_client import MotionSwitcherClient + + +class Custom: + def __init__(self): + self.msc = MotionSwitcherClient() + self.msc.SetTimeout(5.0) + self.msc.Init() + + def selectMode(self,name): + ret = self.msc.SelectMode(name) + return ret + + +if __name__ == '__main__': + + print("WARNING: Please ensure there are no obstacles around the robot while running this example.") + input("Press Enter to continue...") + + if len(sys.argv)>1: + ChannelFactoryInitialize(0, sys.argv[1]) + else: + ChannelFactoryInitialize(0) + + custom = Custom() + selectMode = "ai" + # selectMode = "normal" + # selectMode = "advanced" + # selectMode = "ai-w" # for wheeled robot + ret = custom.selectMode(selectMode) + print("ret: ",ret) + diff --git a/example/obstacles_avoid/obstacles_avoid_move.py b/example/obstacles_avoid/obstacles_avoid_move.py new file mode 100644 index 0000000..284f8ea --- /dev/null +++ b/example/obstacles_avoid/obstacles_avoid_move.py @@ -0,0 +1,35 @@ +import time +import sys + +from unitree_sdk2py.core.channel import ChannelFactoryInitialize +from unitree_sdk2py.go2.obstacles_avoid.obstacles_avoid_client import ObstaclesAvoidClient + +if __name__ == "__main__": + if len(sys.argv)>1: + ChannelFactoryInitialize(0, sys.argv[1]) + else: + ChannelFactoryInitialize(0) + + try: + client = ObstaclesAvoidClient() + client.SetTimeout(3.0) + client.Init() + + while not client.SwitchGet()[1]: + client.SwitchSet(True) + time.sleep(0.1) + + print("obstacles avoid switch on") + + client.UseRemoteCommandFromApi(True) + time.sleep(0.5) + client.Move(0.5, 0.0, 0.0) + time.sleep(1.0) # move 1s + client.Move(0.0, 0.0, 0.0) + client.UseRemoteCommandFromApi(False) + + except KeyboardInterrupt: + client.Move(0.0, 0.0, 0.0) + client.UseRemoteCommandFromApi(False) + print("exit!!") + \ No newline at end of file diff --git a/example/obstacles_avoid/obstacles_avoid_switch.py b/example/obstacles_avoid/obstacles_avoid_switch.py new file mode 100644 index 0000000..eb345c0 --- /dev/null +++ b/example/obstacles_avoid/obstacles_avoid_switch.py @@ -0,0 +1,94 @@ +import time +import sys + +from unitree_sdk2py.core.channel import ChannelFactoryInitialize +from unitree_sdk2py.go2.obstacles_avoid.obstacles_avoid_client import ObstaclesAvoidClient + +if __name__ == "__main__": + if len(sys.argv)>1: + ChannelFactoryInitialize(0, sys.argv[1]) + else: + ChannelFactoryInitialize(0) + + client = ObstaclesAvoidClient() + client.SetTimeout(3.0) + client.Init() + + while True: + print("##################GetServerApiVersion###################") + code, serverAPiVersion = client.GetServerApiVersion() + if code != 0: + print("get server api error. code:", code) + else: + print("get server api version:", serverAPiVersion) + + if serverAPiVersion != client.GetApiVersion(): + print("api version not equal.") + + time.sleep(3) + + print("##################SwitchGet###################") + code, enable = client.SwitchGet() + if code != 0: + print("switch get error. code:", code) + else: + print("switch get success. enable:", enable) + + time.sleep(3) + + print("##################SwitchSet (on)###################") + code = client.SwitchSet(True) + if code != 0: + print("switch set error. code:", code) + else: + print("switch set success.") + + time.sleep(3) + + print("##################SwitchGet###################") + code, enable1 = client.SwitchGet() + if code != 0: + print("switch get error. code:", code) + else: + print("switch get success. enable:", enable1) + + time.sleep(3) + + print("##################SwitchSet (off)###################") + code = client.SwitchSet(False) + if code != 0: + print("switch set error. code:", code) + else: + print("switch set success.") + + time.sleep(3) + + print("##################SwitchGet###################") + code, enable1 = client.SwitchGet() + if code != 0: + print("switch get error. code:", code) + else: + print("switch get success. enable:", enable1) + + time.sleep(3) + + + print("##################SwitchSet (enable)###################") + + code = client.SwitchSet(enable) + if code != 0: + print("switch set error. code:", code) + else: + print("switch set success. enable:", enable) + + time.sleep(3) + + print("##################SwitchGet###################") + code, enable = client.SwitchGet() + if code != 0: + print("switch get error. code:", code) + else: + print("switch get success. enable:", enable) + + time.sleep(3) + \ No newline at end of file diff --git a/example/vui_client/vui_client_example.py b/example/vui_client/vui_client_example.py new file mode 100644 index 0000000..a5e6932 --- /dev/null +++ b/example/vui_client/vui_client_example.py @@ -0,0 +1,77 @@ +import time +import sys + +from unitree_sdk2py.core.channel import ChannelFactoryInitialize +from unitree_sdk2py.go2.vui.vui_client import VuiClient + +if __name__ == "__main__": + if len(sys.argv)>1: + ChannelFactoryInitialize(0, sys.argv[1]) + else: + ChannelFactoryInitialize(0) + + client = VuiClient() + client.SetTimeout(3.0) + client.Init() + + for i in range(1, 11): + print("#################GetBrightness####################") + code, level = client.GetBrightness() + + if code != 0: + print("get brightness error. code:", code) + else: + print("get brightness success. level:", level) + + time.sleep(1) + + print("#################SetBrightness####################") + + code = client.SetBrightness(i) + + if code != 0: + print("set brightness error. code:", code) + else: + print("set brightness success. level:", i) + + time.sleep(1) + + print("#################SetBrightness 0####################") + + code = client.SetBrightness(0) + + if code != 0: + print("set brightness error. code:", code) + else: + print("set brightness 0 success.") + + for i in range(1, 11): + print("#################GetVolume####################") + code, level = client.GetVolume() + + if code != 0: + print("get volume error. code:", code) + else: + print("get volume success. level:", level) + + time.sleep(1) + + print("#################SetVolume####################") + + code = client.SetVolume(i) + + if code != 0: + print("set volume error. code:", code) + else: + print("set volume success. level:", i) + + time.sleep(1) + + print("#################SetVolume 0####################") + + code = client.SetVolume(0) + + if code != 0: + print("set volume error. code:", code) + else: + print("set volume 0 success.") diff --git a/example/wireless_controller/wireless_controller.py b/example/wireless_controller/wireless_controller.py new file mode 100644 index 0000000..995487f --- /dev/null +++ b/example/wireless_controller/wireless_controller.py @@ -0,0 +1,131 @@ +import time +import sys +import struct + +from unitree_sdk2py.core.channel import ChannelSubscriber, ChannelFactoryInitialize + +# Uncomment the following two lines when using Go2、Go2-W、B2、B2-W、H1 robot +# from unitree_sdk2py.idl.default import unitree_go_msg_dds__LowState_ +# from unitree_sdk2py.idl.unitree_go.msg.dds_ import LowState_ + +# Uncomment the following two lines when using G1、H1-2 robot +from unitree_sdk2py.idl.default import unitree_hg_msg_dds__LowState_ +from unitree_sdk2py.idl.unitree_hg.msg.dds_ import LowState_ + +class unitreeRemoteController: + def __init__(self): + # key + self.Lx = 0 + self.Rx = 0 + self.Ry = 0 + self.Ly = 0 + + # button + self.L1 = 0 + self.L2 = 0 + self.R1 = 0 + self.R2 = 0 + self.A = 0 + self.B = 0 + self.X = 0 + self.Y = 0 + self.Up = 0 + self.Down = 0 + self.Left = 0 + self.Right = 0 + self.Select = 0 + self.F1 = 0 + self.F3 = 0 + self.Start = 0 + + def parse_botton(self,data1,data2): + self.R1 = (data1 >> 0) & 1 + self.L1 = (data1 >> 1) & 1 + self.Start = (data1 >> 2) & 1 + self.Select = (data1 >> 3) & 1 + self.R2 = (data1 >> 4) & 1 + self.L2 = (data1 >> 5) & 1 + self.F1 = (data1 >> 6) & 1 + self.F3 = (data1 >> 7) & 1 + self.A = (data2 >> 0) & 1 + self.B = (data2 >> 1) & 1 + self.X = (data2 >> 2) & 1 + self.Y = (data2 >> 3) & 1 + self.Up = (data2 >> 4) & 1 + self.Right = (data2 >> 5) & 1 + self.Down = (data2 >> 6) & 1 + self.Left = (data2 >> 7) & 1 + + def parse_key(self,data): + lx_offset = 4 + self.Lx = struct.unpack('1: + ChannelFactoryInitialize(0, sys.argv[1]) + else: + ChannelFactoryInitialize(0) + + custom = Custom() + custom.Init() + + while True: + time.sleep(1) \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..07de284 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["setuptools", "wheel"] +build-backend = "setuptools.build_meta" \ No newline at end of file diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..54d8cac --- /dev/null +++ b/setup.py @@ -0,0 +1,21 @@ +from setuptools import setup, find_packages + +setup(name='unitree_sdk2py', + version='1.0.1', + author='UnitreeRobotics', + author_email='unitree@unitree.com', + long_description=open('README.md').read(), + long_description_content_type="text/markdown", + license="BSD-3-Clause", + packages=find_packages(include=['unitree_sdk2py','unitree_sdk2py.*']), + description='Unitree robot sdk version 2 for python', + project_urls={ + "Source Code": "https://github.com/unitreerobotics/unitree_sdk2_python", + }, + python_requires='>=3.8', + install_requires=[ + "cyclonedds==0.10.2", + "numpy", + "opencv-python", + ], + ) \ No newline at end of file diff --git a/unitree_sdk2py/__init__.py b/unitree_sdk2py/__init__.py new file mode 100644 index 0000000..f071aeb --- /dev/null +++ b/unitree_sdk2py/__init__.py @@ -0,0 +1,10 @@ +from . import idl, utils, core, rpc, go2, b2 + +__all__ = [ + "idl" + "utils" + "core", + "rpc", + "go2", + "b2", +] diff --git a/unitree_sdk2py/b2/back_video/back_video_api.py b/unitree_sdk2py/b2/back_video/back_video_api.py new file mode 100644 index 0000000..16f566b --- /dev/null +++ b/unitree_sdk2py/b2/back_video/back_video_api.py @@ -0,0 +1,16 @@ +""" +" service name +""" +ROBOT_BACK_VIDEO_SERVICE_NAME = "back_videohub" + + +""" +" service api version +""" +ROBOT_BACK_VIDEO_API_VERSION = "1.0.0.0" + + +""" +" api id +""" +ROBOT_BACK_VIDEO_API_ID_GETIMAGESAMPLE = 1001 diff --git a/unitree_sdk2py/b2/back_video/back_video_client.py b/unitree_sdk2py/b2/back_video/back_video_client.py new file mode 100644 index 0000000..e19c97f --- /dev/null +++ b/unitree_sdk2py/b2/back_video/back_video_client.py @@ -0,0 +1,23 @@ +import json + +from ...rpc.client import Client +from .back_video_api import * + + +""" +" class FrontVideoClient +""" +class BackVideoClient(Client): + def __init__(self): + super().__init__(ROBOT_BACK_VIDEO_SERVICE_NAME, False) + + + def Init(self): + # set api version + self._SetApiVerson(ROBOT_BACK_VIDEO_API_VERSION) + # regist api + self._RegistApi(ROBOT_BACK_VIDEO_API_ID_GETIMAGESAMPLE, 0) + + # 1001 + def GetImageSample(self): + return self._CallBinary(ROBOT_BACK_VIDEO_API_ID_GETIMAGESAMPLE, []) diff --git a/unitree_sdk2py/b2/front_video/front_video_api.py b/unitree_sdk2py/b2/front_video/front_video_api.py new file mode 100644 index 0000000..6f4717a --- /dev/null +++ b/unitree_sdk2py/b2/front_video/front_video_api.py @@ -0,0 +1,16 @@ +""" +" service name +""" +ROBOT_FRONT_VIDEO_SERVICE_NAME = "front_videohub" + + +""" +" service api version +""" +ROBOT_FRONT_VIDEO_API_VERSION = "1.0.0.0" + + +""" +" api id +""" +ROBOT_FRONT_VIDEO_API_ID_GETIMAGESAMPLE = 1001 diff --git a/unitree_sdk2py/b2/front_video/front_video_client.py b/unitree_sdk2py/b2/front_video/front_video_client.py new file mode 100644 index 0000000..5ba065a --- /dev/null +++ b/unitree_sdk2py/b2/front_video/front_video_client.py @@ -0,0 +1,23 @@ +import json + +from ...rpc.client import Client +from .front_video_api import * + + +""" +" class FrontVideoClient +""" +class FrontVideoClient(Client): + def __init__(self): + super().__init__(ROBOT_FRONT_VIDEO_SERVICE_NAME, False) + + + def Init(self): + # set api version + self._SetApiVerson(ROBOT_FRONT_VIDEO_API_VERSION) + # regist api + self._RegistApi(ROBOT_FRONT_VIDEO_API_ID_GETIMAGESAMPLE, 0) + + # 1001 + def GetImageSample(self): + return self._CallBinary(ROBOT_FRONT_VIDEO_API_ID_GETIMAGESAMPLE, []) diff --git a/unitree_sdk2py/b2/robot_state/robot_state_api.py b/unitree_sdk2py/b2/robot_state/robot_state_api.py new file mode 100644 index 0000000..fde54df --- /dev/null +++ b/unitree_sdk2py/b2/robot_state/robot_state_api.py @@ -0,0 +1,25 @@ +""" +" service name +""" +ROBOT_STATE_SERVICE_NAME = "robot_state" + + +""" +" service api version +""" +ROBOT_STATE_API_VERSION = "1.0.0.1" + + +""" +" api id +""" +ROBOT_STATE_API_ID_SERVICE_SWITCH = 1001 +ROBOT_STATE_API_ID_REPORT_FREQ = 1002 +ROBOT_STATE_API_ID_SERVICE_LIST = 1003 + + +""" +" error code +""" +ROBOT_STATE_ERR_SERVICE_SWITCH = 5201 +ROBOT_STATE_ERR_SERVICE_PROTECTED = 5202 diff --git a/unitree_sdk2py/b2/robot_state/robot_state_client.py b/unitree_sdk2py/b2/robot_state/robot_state_client.py new file mode 100644 index 0000000..5b2e74d --- /dev/null +++ b/unitree_sdk2py/b2/robot_state/robot_state_client.py @@ -0,0 +1,84 @@ +import json + +from ...rpc.client import Client +from ...rpc.client_internal import * +from .robot_state_api import * + + +""" +" class ServiceState +""" +class ServiceState: + def __init__(self, name: str = None, status: int = None, protect: bool = None): + self.name = name + self.status = status + self.protect = protect + +""" +" class RobotStateClient +""" +class RobotStateClient(Client): + def __init__(self): + super().__init__(ROBOT_STATE_SERVICE_NAME, False) + + def Init(self): + # set api version + self._SetApiVerson(ROBOT_STATE_API_VERSION) + # regist api + self._RegistApi(ROBOT_STATE_API_ID_SERVICE_SWITCH, 0) + self._RegistApi(ROBOT_STATE_API_ID_REPORT_FREQ, 0) + self._RegistApi(ROBOT_STATE_API_ID_SERVICE_LIST, 0) + + def ServiceList(self): + p = {} + parameter = json.dumps(p) + + code, data = self._Call(ROBOT_STATE_API_ID_SERVICE_LIST, parameter) + + if code != 0: + return code, None + + lst = [] + + d = json.loads(data) + for t in d: + s = ServiceState() + s.name = t["name"] + s.status = t["status"] + s.protect = t["protect"] + lst.append(s) + + return code, lst + + + def ServiceSwitch(self, name: str, switch: bool): + p = {} + p["name"] = name + p["switch"] = int(switch) + parameter = json.dumps(p) + + code, data = self._Call(ROBOT_STATE_API_ID_SERVICE_SWITCH, parameter) + + if code != 0: + return code + + d = json.loads(data) + + status = d["status"] + + if status == 5: + return ROBOT_STATE_ERR_SERVICE_PROTECTED + + if status != 0 and status != 1: + return ROBOT_STATE_ERR_SERVICE_SWITCH + + return code + + def SetReportFreq(self, interval: int, duration: int): + p = {} + p["interval"] = interval + p["duration"] = duration + parameter = json.dumps(p) + + code, data = self._Call(ROBOT_STATE_API_ID_REPORT_FREQ, p) + return code diff --git a/unitree_sdk2py/b2/sport/sport_api.py b/unitree_sdk2py/b2/sport/sport_api.py new file mode 100644 index 0000000..72520b6 --- /dev/null +++ b/unitree_sdk2py/b2/sport/sport_api.py @@ -0,0 +1,58 @@ +""" +" service name +""" +SPORT_SERVICE_NAME = "sport" + + +""" +" service api version +""" +SPORT_API_VERSION = "1.0.0.1" + + +""" +" api id +""" +SPORT_API_ID_DAMP = 1001; +SPORT_API_ID_BALANCESTAND = 1002; +SPORT_API_ID_STOPMOVE = 1003; +SPORT_API_ID_STANDUP = 1004; +SPORT_API_ID_STANDDOWN = 1005; +SPORT_API_ID_RECOVERYSTAND = 1006; +SPORT_API_ID_EULER = 1007; +SPORT_API_ID_MOVE = 1008; +SPORT_API_ID_SIT = 1009; +SPORT_API_ID_RISESIT = 1010; +SPORT_API_ID_SWITCHGAIT = 1011; +SPORT_API_ID_TRIGGER = 1012; +SPORT_API_ID_BODYHEIGHT = 1013; +SPORT_API_ID_FOOTRAISEHEIGHT = 1014; +SPORT_API_ID_SPEEDLEVEL = 1015; +SPORT_API_ID_HELLO = 1016; +SPORT_API_ID_STRETCH = 1017; +SPORT_API_ID_TRAJECTORYFOLLOW = 1018; +SPORT_API_ID_CONTINUOUSGAIT = 1019; +SPORT_API_ID_CONTENT = 1020; +SPORT_API_ID_WALLOW = 1021; +SPORT_API_ID_DANCE1 = 1022; +SPORT_API_ID_DANCE2 = 1023; +SPORT_API_ID_GETBODYHEIGHT = 1024; +SPORT_API_ID_GETFOOTRAISEHEIGHT = 1025; +SPORT_API_ID_GETSPEEDLEVEL = 1026; +SPORT_API_ID_SWITCHJOYSTICK = 1027; +SPORT_API_ID_POSE = 1028; +SPORT_API_ID_FRONTJUMP = 1031; +SPORT_API_ID_ECONOMICGAIT = 1035; +SPORT_API_ID_MOVETOPOS = 1036; +SPORT_API_ID_SWITCHEULERMODE = 1037; +SPORT_API_ID_SWITCHMOVEMODE = 1038; + + +""" +" error code +""" +# client side +SPORT_ERR_CLIENT_POINT_PATH = 4101 +# server side +SPORT_ERR_SERVER_OVERTIME = 4201 +SPORT_ERR_SERVER_NOT_INIT = 4202 diff --git a/unitree_sdk2py/b2/sport/sport_client.py b/unitree_sdk2py/b2/sport/sport_client.py new file mode 100644 index 0000000..9ca34a3 --- /dev/null +++ b/unitree_sdk2py/b2/sport/sport_client.py @@ -0,0 +1,241 @@ +import json + +from ...rpc.client import Client +from .sport_api import * + +""" +" SPORT_PATH_POINT_SIZE +""" +SPORT_PATH_POINT_SIZE = 30 + + +""" +" class PathPoint +""" +class PathPoint: + def __init__(self, timeFromStart: float, x: float, y: float, yaw: float, vx: float, vy: float, vyaw: float): + self.timeFromStart = timeFromStart + self.x = x + self.y = y + self.yaw = yaw + self.vx = vx + self.vy = vy + self.vyaw = vyaw + + +""" +" class SportClient +""" +class SportClient(Client): + def __init__(self, enableLease: bool = False): + super().__init__(SPORT_SERVICE_NAME, enableLease) + + + def Init(self): + # set api version + self._SetApiVerson(SPORT_API_VERSION) + + # regist api + self._RegistApi(SPORT_API_ID_DAMP, 0) + self._RegistApi(SPORT_API_ID_BALANCESTAND, 0) + self._RegistApi(SPORT_API_ID_STOPMOVE, 0) + self._RegistApi(SPORT_API_ID_STANDUP, 0) + self._RegistApi(SPORT_API_ID_STANDDOWN, 0) + self._RegistApi(SPORT_API_ID_RECOVERYSTAND, 0) + self._RegistApi(SPORT_API_ID_EULER, 0) + self._RegistApi(SPORT_API_ID_MOVE, 0) + self._RegistApi(SPORT_API_ID_SIT, 0) + self._RegistApi(SPORT_API_ID_SWITCHGAIT, 0) + self._RegistApi(SPORT_API_ID_BODYHEIGHT, 0) + self._RegistApi(SPORT_API_ID_FOOTRAISEHEIGHT, 0) + self._RegistApi(SPORT_API_ID_SPEEDLEVEL, 0) + self._RegistApi(SPORT_API_ID_TRAJECTORYFOLLOW, 0) + self._RegistApi(SPORT_API_ID_CONTINUOUSGAIT, 0) + self._RegistApi(SPORT_API_ID_MOVETOPOS, 0) + self._RegistApi(SPORT_API_ID_FRONTJUMP, 0) + self._RegistApi(SPORT_API_ID_ECONOMICGAIT, 0) + self._RegistApi(SPORT_API_ID_POSE, 0) + self._RegistApi(SPORT_API_ID_SWITCHEULERMODE, 0) + self._RegistApi(SPORT_API_ID_SWITCHMOVEMODE, 0) + + # 1001 + def Damp(self): + p = {} + parameter = json.dumps(p) + code, data = self._Call(SPORT_API_ID_DAMP, parameter) + return code + + # 1002 + def BalanceStand(self): + p = {} + parameter = json.dumps(p) + code, data = self._Call(SPORT_API_ID_BALANCESTAND, parameter) + return code + + # 1003 + def StopMove(self): + p = {} + parameter = json.dumps(p) + code, data = self._Call(SPORT_API_ID_STOPMOVE, parameter) + return code + + # 1004 + def StandUp(self): + p = {} + parameter = json.dumps(p) + code, data = self._Call(SPORT_API_ID_STANDUP, parameter) + return code + + # 1005 + def StandDown(self): + p = {} + parameter = json.dumps(p) + code, data = self._Call(SPORT_API_ID_STANDDOWN, parameter) + return code + + # 1006 + def RecoveryStand(self): + p = {} + parameter = json.dumps(p) + code, data = self._Call(SPORT_API_ID_RECOVERYSTAND, parameter) + return code + + # 1007 + def Euler(self, roll: float, pitch: float, yaw: float): + p = {} + p["x"] = roll + p["y"] = pitch + p["z"] = yaw + parameter = json.dumps(p) + code, data = self._Call(SPORT_API_ID_EULER, parameter) + return code + + # 1008 + def Move(self, vx: float, vy: float, vyaw: float): + p = {} + p["x"] = vx + p["y"] = vy + p["z"] = vyaw + parameter = json.dumps(p) + code = self._CallNoReply(SPORT_API_ID_MOVE, parameter) + return code + + # 1009 + def Sit(self): + p = {} + parameter = json.dumps(p) + code, data = self._Call(SPORT_API_ID_SIT, parameter) + return code + + # 1011 + def SwitchGait(self, t: int): + p = {} + p["data"] = t + parameter = json.dumps(p) + code, data = self._Call(SPORT_API_ID_SWITCHGAIT, parameter) + return code + + # 1013 + def BodyHeight(self, height: float): + p = {} + p["data"] = height + parameter = json.dumps(p) + code, data = self._Call(SPORT_API_ID_BODYHEIGHT, parameter) + return code + + # 1014 + def FootRaiseHeight(self, height: float): + p = {} + p["data"] = height + parameter = json.dumps(p) + code, data = self._Call(SPORT_API_ID_FOOTRAISEHEIGHT, parameter) + return code + + # 1015 + def SpeedLevel(self, level: int): + p = {} + p["data"] = level + parameter = json.dumps(p) + code, data = self._Call(SPORT_API_ID_SPEEDLEVEL, parameter) + return code + + # 1018 + def TrajectoryFollow(self, path: list): + l = len(path) + if l != SPORT_PATH_POINT_SIZE: + return SPORT_ERR_CLIENT_POINT_PATH + + path_p = [] + for i in range(l): + point = path[i] + p = {} + p["t_from_start"] = point.timeFromStart + p["x"] = point.x + p["y"] = point.y + p["yaw"] = point.yaw + p["vx"] = point.vx + p["vy"] = point.vy + p["vyaw"] = point.vyaw + path_p.append(p) + + parameter = json.dumps(path_p) + code = self._CallNoReply(SPORT_API_ID_TRAJECTORYFOLLOW, parameter) + return code + + # 1019 + def ContinuousGait(self, flag: int): + p = {} + p["data"] = flag + parameter = json.dumps(p) + code, data = self._Call(SPORT_API_ID_CONTINUOUSGAIT, parameter) + return code + + # 1036 + def MoveToPos(self, x: float, y: float, yaw: float): + p = {} + p["x"] = x + p["y"] = y + p["yaw"] = yaw + parameter = json.dumps(p) + code, data = self._Call(SPORT_API_ID_MOVETOPOS, parameter) + return code + + # 1031 + def FrontJump(self): + p = {} + parameter = json.dumps(p) + code, data = self._Call(SPORT_API_ID_FRONTJUMP, parameter) + return code + + + # 1035 + def EconomicGait(self, flag: bool): + p = {} + p["data"] = flag + parameter = json.dumps(p) + code, data = self._Call(SPORT_API_ID_ECONOMICGAIT, parameter) + return code + + # 1028 + def Pose(self, flag: bool): + p = {} + p["data"] = flag + parameter = json.dumps(p) + code, data = self._Call(SPORT_API_ID_POSE, parameter) + return code + + # 1037 + def SwitchEulerMode(self, flag: bool): + p = {} + p["data"] = flag + parameter = json.dumps(p) + code, data = self._Call(SPORT_API_ID_SWITCHEULERMODE, parameter) + return code + + # 1038 + def SwitchMoveMode(self, flag: bool): + p = {} + p["data"] = flag + parameter = json.dumps(p) + code, data = self._Call(SPORT_API_ID_SWITCHMOVEMODE, parameter) + return code diff --git a/unitree_sdk2py/b2/vui/vui_api.py b/unitree_sdk2py/b2/vui/vui_api.py new file mode 100644 index 0000000..d5dcd34 --- /dev/null +++ b/unitree_sdk2py/b2/vui/vui_api.py @@ -0,0 +1,21 @@ +""" +" service name +""" +VUI_SERVICE_NAME = "vui" + + +""" +" service api version +""" +VUI_API_VERSION = "1.0.0.1" + + +""" +" api id +""" +VUI_API_ID_SETSWITCH = 1001 +VUI_API_ID_GETSWITCH = 1002 +VUI_API_ID_SETVOLUME = 1003 +VUI_API_ID_GETVOLUME = 1004 +VUI_API_ID_SETBRIGHTNESS = 1005 +VUI_API_ID_GETBRIGHTNESS = 1006 diff --git a/unitree_sdk2py/b2/vui/vui_client.py b/unitree_sdk2py/b2/vui/vui_client.py new file mode 100644 index 0000000..234f285 --- /dev/null +++ b/unitree_sdk2py/b2/vui/vui_client.py @@ -0,0 +1,86 @@ +import json + +from ...rpc.client import Client +from .vui_api import * + + +""" +" class VideoClient +""" +class VuiClient(Client): + def __init__(self): + super().__init__(VUI_SERVICE_NAME, False) + + def Init(self): + # set api version + self._SetApiVerson(VUI_API_VERSION) + # regist api + self._RegistApi(VUI_API_ID_SETSWITCH, 0) + self._RegistApi(VUI_API_ID_GETSWITCH, 0) + self._RegistApi(VUI_API_ID_SETVOLUME, 0) + self._RegistApi(VUI_API_ID_GETVOLUME, 0) + self._RegistApi(VUI_API_ID_SETBRIGHTNESS, 0) + self._RegistApi(VUI_API_ID_GETBRIGHTNESS, 0) + + # 1001 + def SetSwitch(self, enable: int): + p = {} + p["enable"] = enable + parameter = json.dumps(p) + + code, data = self._Call(VUI_API_ID_SETSWITCH, parameter) + return code + + # 1002 + def GetSwitch(self): + p = {} + parameter = json.dumps(p) + + code, data = self._Call(VUI_API_ID_GETSWITCH, parameter) + if code == 0: + d = json.loads(data) + return code, d["enable"] + else: + return code, None + + # 1003 + def SetVolume(self, level: int): + p = {} + p["volume"] = level + parameter = json.dumps(p) + + code, data = self._Call(VUI_API_ID_SETVOLUME, parameter) + return code + + # 1006 + def GetVolume(self): + p = {} + parameter = json.dumps(p) + + code, data = self._Call(VUI_API_ID_GETVOLUME, parameter) + if code == 0: + d = json.loads(data) + return code, d["volume"] + else: + return code, None + + # 1005 + def SetBrightness(self, level: int): + p = {} + p["brightness"] = level + parameter = json.dumps(p) + + code, data = self._Call(VUI_API_ID_SETBRIGHTNESS, parameter) + return code + + # 1006 + def GetBrightness(self): + p = {} + parameter = json.dumps(p) + + code, data = self._Call(VUI_API_ID_GETBRIGHTNESS, parameter) + if code == 0: + d = json.loads(data) + return code, d["brightness"] + else: + return code, None \ No newline at end of file diff --git a/unitree_sdk2py/comm/motion_switcher/__init__.py b/unitree_sdk2py/comm/motion_switcher/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/unitree_sdk2py/comm/motion_switcher/motion_switcher_api.py b/unitree_sdk2py/comm/motion_switcher/motion_switcher_api.py new file mode 100644 index 0000000..ddb9a42 --- /dev/null +++ b/unitree_sdk2py/comm/motion_switcher/motion_switcher_api.py @@ -0,0 +1,29 @@ +""" +" service name +""" +MOTION_SWITCHER_SERVICE_NAME = "motion_switcher" + + +""" +" service api version +""" +MOTION_SWITCHER_API_VERSION = "1.0.0.1" + + +""" +" api id +""" +MOTION_SWITCHER_API_ID_CHECK_MODE = 1001 +MOTION_SWITCHER_API_ID_SELECT_MODE = 1002 +MOTION_SWITCHER_API_ID_RELEASE_MODE = 1003 +MOTION_SWITCHER_API_ID_SET_SILENT = 1004 +MOTION_SWITCHER_API_ID_GET_SILENT = 1005 + +# """ +# " error code +# """ +# # client side +# SPORT_ERR_CLIENT_POINT_PATH = 4101 +# # server side +# SPORT_ERR_SERVER_OVERTIME = 4201 +# SPORT_ERR_SERVER_NOT_INIT = 4202 diff --git a/unitree_sdk2py/comm/motion_switcher/motion_switcher_client.py b/unitree_sdk2py/comm/motion_switcher/motion_switcher_client.py new file mode 100644 index 0000000..1ad411a --- /dev/null +++ b/unitree_sdk2py/comm/motion_switcher/motion_switcher_client.py @@ -0,0 +1,51 @@ +import json + +from ...rpc.client import Client +from .motion_switcher_api import * + +""" +" class MotionSwitcherClient +""" +class MotionSwitcherClient(Client): + def __init__(self): + super().__init__(MOTION_SWITCHER_SERVICE_NAME, False) + + + def Init(self): + # set api version + self._SetApiVerson(MOTION_SWITCHER_API_VERSION) + + # regist api + self._RegistApi(MOTION_SWITCHER_API_ID_CHECK_MODE, 0) + self._RegistApi(MOTION_SWITCHER_API_ID_SELECT_MODE, 0) + self._RegistApi(MOTION_SWITCHER_API_ID_RELEASE_MODE, 0) + self._RegistApi(MOTION_SWITCHER_API_ID_SET_SILENT, 0) + self._RegistApi(MOTION_SWITCHER_API_ID_GET_SILENT, 0) + + # 1001 + def CheckMode(self): + p = {} + parameter = json.dumps(p) + code, data = self._Call(MOTION_SWITCHER_API_ID_CHECK_MODE, parameter) + if code == 0: + return code, json.loads(data) + else: + return code, None + + # 1002 + def SelectMode(self, nameOrAlias): + p = {} + p["name"] = nameOrAlias + parameter = json.dumps(p) + code, data = self._Call(MOTION_SWITCHER_API_ID_SELECT_MODE, parameter) + + return code, None + + # 1003 + def ReleaseMode(self): + p = {} + parameter = json.dumps(p) + code, data = self._Call(MOTION_SWITCHER_API_ID_RELEASE_MODE, parameter) + + return code, None + \ No newline at end of file diff --git a/unitree_sdk2py/core/__init__.py b/unitree_sdk2py/core/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/unitree_sdk2py/core/channel.py b/unitree_sdk2py/core/channel.py new file mode 100644 index 0000000..d955f75 --- /dev/null +++ b/unitree_sdk2py/core/channel.py @@ -0,0 +1,290 @@ +import time +from typing import Any, Callable +from threading import Thread, Event + +from cyclonedds.domain import Domain, DomainParticipant +from cyclonedds.internal import dds_c_t +from cyclonedds.pub import DataWriter +from cyclonedds.sub import DataReader +from cyclonedds.topic import Topic +from cyclonedds.qos import Qos +from cyclonedds.core import DDSException, Listener +from cyclonedds.util import duration +from cyclonedds.internal import dds_c_t, InvalidSample + +# for channel config +from .channel_config import ChannelConfigAutoDetermine, ChannelConfigHasInterface + +# for singleton +from ..utils.singleton import Singleton +from ..utils.bqueue import BQueue + + +""" +" class ChannelReader +""" + +""" +" class Channel +""" +class Channel: + + """ + " internal class __Reader + """ + class __Reader: + def __init__(self): + self.__reader = None + self.__handler = None + self.__queue = None + self.__queueEnable = False + self.__threadEvent = None + self.__threadReader = None + + def Init(self, participant: DomainParticipant, topic: Topic, qos: Qos = None, handler: Callable = None, queueLen: int = 0): + if handler is None: + self.__reader = DataReader(participant, topic, qos) + else: + self.__handler = handler + if queueLen > 0: + self.__queueEnable = True + self.__queue = BQueue(queueLen) + self.__threadEvent = Event() + self.__threadReader = Thread(target=self.__ChannelReaderThreadFunc, name="ch_reader", daemon=True) + self.__threadReader.start() + self.__reader = DataReader(participant, topic, qos, Listener(on_data_available=self.__OnDataAvailable)) + + def Read(self, timeout: float = None): + sample = None + try: + if timeout is None: + sample = self.__reader.take_one() + else: + sample = self.__reader.take_one(timeout=duration(seconds=timeout)) + except DDSException as e: + print("[Reader] catch DDSException msg:", e.msg) + except TimeoutError as e: + print("[Reader] take sample timeout") + except: + print("[Reader] take sample error") + + return sample + + def Close(self): + if self.__reader is not None: + del self.__reader + + if self.__queueEnable: + self.__threadEvent.set() + self.__queue.Interrupt() + self.__queue.Clear() + self.__threadReader.join() + + def __OnDataAvailable(self, reader: DataReader): + samples = [] + try: + samples = reader.take(1) + except DDSException as e: + print("[Reader] catch DDSException error. msg:", e.msg) + return + except TimeoutError as e: + print("[Reader] take sample timeout") + return + except: + print("[Reader] take sample error") + return + + if samples is None: + return + + # check invalid sample + sample = samples[0] + if isinstance(sample, InvalidSample): + return + + # do sample + if self.__queueEnable: + self.__queue.Put(sample) + else: + self.__handler(sample) + + def __ChannelReaderThreadFunc(self): + while not self.__threadEvent.is_set(): + sample = self.__queue.Get() + if sample is not None: + self.__handler(sample) + + """ + " internal class __Writer + """ + class __Writer: + def __init__(self): + self.__writer = None + self.__publication_matched_count = 0 + + def Init(self, participant: DomainParticipant, topic: Topic, qos: Qos = None): + self.__writer = DataWriter(participant, topic, qos, Listener(on_publication_matched=self.__OnPublicationMatched)) + time.sleep(0.2) + + def Write(self, sample: Any, timeout: float = None): + waitsec = 0.0 if timeout is None else timeout + + # check publication_matched_count + while waitsec > 0.0 and self.__publication_matched_count == 0: + time.sleep(0.1) + waitsec = waitsec - 0.1 + # print(time.time()) + + # check waitsec + if timeout is not None and waitsec <= 0.0: + return False + + try: + self.__writer.write(sample) + except DDSException as e: + print("[Writer] catch DDSException error. msg:", e.msg) + return False + except Exception as e: + print("[Writer] write sample error. msg:", e.args()) + return False + + return True + + def Close(self): + if self.__writer is not None: + del self.__writer + + def __OnPublicationMatched(self, writer: DataWriter, status: dds_c_t.publication_matched_status): + self.__publication_matched_count = status.current_count + + + # channel __init__ + def __init__(self, participant: DomainParticipant, name: str, type: Any, qos: Qos = None): + self.__reader = self.__Reader() + self.__writer = self.__Writer() + self.__participant = participant + self.__topic = Topic(self.__participant, name, type, qos) + + def SetWriter(self, qos: Qos = None): + self.__writer.Init(self.__participant, self.__topic, qos) + + def SetReader(self, qos: Qos = None, handler: Callable = None, queueLen: int = 0): + self.__reader.Init(self.__participant, self.__topic, qos, handler, queueLen) + + def Write(self, sample: Any, timeout: float = None): + return self.__writer.Write(sample, timeout) + + def Read(self, timeout: float = None): + return self.__reader.Read(timeout) + + def CloseReader(self): + self.__reader.Close() + + def CloseWriter(self): + self.__writer.Close() + + +""" +" class ChannelFactory +""" +class ChannelFactory(Singleton): + __domain = None + __participant = None + __qos = None + + def __init__(self): + super().__init__() + + def Init(self, id: int, networkInterface: str = None, qos: Qos = None): + config = None + # choose config + if networkInterface is None: + config = ChannelConfigAutoDetermine + else: + config = ChannelConfigHasInterface.replace('$__IF_NAME__$', networkInterface) + + try: + self.__domain = Domain(id, config) + except DDSException as e: + print("[ChannelFactory] create domain error. msg:", e.msg) + return False + except: + print("[ChannelFactory] create domain error.") + return False + + try: + self.__participant = DomainParticipant(id) + except DDSException as e: + print("[ChannelFactory] create domain participant error. msg:", e.msg) + return False + except: + print("[ChannelFactory] create domain participant error") + return False + + self.__qos = qos + + return True + + def CreateChannel(self, name: str, type: Any): + return Channel(self.__participant, name, type, self.__qos) + + def CreateSendChannel(self, name: str, type: Any): + channel = self.CreateChannel(name, type) + channel.SetWriter(None) + return channel + + def CreateRecvChannel(self, name: str, type: Any, handler: Callable = None, queueLen: int = 0): + channel = self.CreateChannel(name, type) + channel.SetReader(None, handler, queueLen) + return channel + + +""" +" class ChannelPublisher +""" +class ChannelPublisher: + def __init__(self, name: str, type: Any): + factory = ChannelFactory() + self.__channel = factory.CreateChannel(name, type) + self.__inited = False + + def Init(self): + if not self.__inited: + self.__channel.SetWriter(None) + self.__inited = True + + def Close(self): + self.__channel.CloseWriter() + self.__inited = False + + def Write(self, sample: Any, timeout: float = None): + return self.__channel.Write(sample, timeout) + +""" +" class ChannelSubscriber +""" +class ChannelSubscriber: + def __init__(self, name: str, type: Any): + factory = ChannelFactory() + self.__channel = factory.CreateChannel(name, type) + self.__inited = False + + def Init(self, handler: Callable = None, queueLen: int = 0): + if not self.__inited: + self.__channel.SetReader(None, handler, queueLen) + self.__inited = True + + def Close(self): + self.__channel.CloseReader() + self.__inited = False + + def Read(self, timeout: int = None): + return self.__channel.Read(timeout) + +""" +" function ChannelFactoryInitialize. used to intialize channel everenment. +""" +def ChannelFactoryInitialize(id: int = 0, networkInterface: str = None): + factory = ChannelFactory() + if not factory.Init(id, networkInterface): + raise Exception("channel factory init error.") diff --git a/unitree_sdk2py/core/channel_config.py b/unitree_sdk2py/core/channel_config.py new file mode 100644 index 0000000..19a67a4 --- /dev/null +++ b/unitree_sdk2py/core/channel_config.py @@ -0,0 +1,25 @@ +ChannelConfigHasInterface = ''' + + + + + + + + + config + /tmp/cdds.LOG + + + ''' + +ChannelConfigAutoDetermine = ''' + + + + + + + + + ''' diff --git a/unitree_sdk2py/core/channel_name.py b/unitree_sdk2py/core/channel_name.py new file mode 100644 index 0000000..722e408 --- /dev/null +++ b/unitree_sdk2py/core/channel_name.py @@ -0,0 +1,34 @@ +from enum import Enum + +""" +" Enum ChannelType +""" +class ChannelType(Enum): + SEND = 0 + RECV = 1 + +""" +" function GetClientChannelName +""" +def GetClientChannelName(serviceName: str, channelType: ChannelType): + name = "rt/api/" + serviceName + + if channelType == ChannelType.SEND: + name += "/request" + else: + name += "/response" + + return name + +""" +" function GetClientChannelName +""" +def GetServerChannelName(serviceName: str, channelType: ChannelType): + name = "rt/api/" + serviceName + + if channelType == ChannelType.SEND: + name += "/response" + else: + name += "/request" + + return name \ No newline at end of file diff --git a/unitree_sdk2py/g1/arm/g1_arm_action_api.py b/unitree_sdk2py/g1/arm/g1_arm_action_api.py new file mode 100644 index 0000000..f3e9829 --- /dev/null +++ b/unitree_sdk2py/g1/arm/g1_arm_action_api.py @@ -0,0 +1,19 @@ +""" +" service name +""" +ARM_ACTION_SERVICE_NAME = "arm" + +""" +" service api version +""" +ARM_ACTION_API_VERSION = "1.0.0.14" + +""" +" api id +""" +ROBOT_API_ID_ARM_ACTION_EXECUTE_ACTION = 7106 +ROBOT_API_ID_ARM_ACTION_GET_ACTION_LIST = 7107 + +""" +" error code +""" \ No newline at end of file diff --git a/unitree_sdk2py/g1/arm/g1_arm_action_client.py b/unitree_sdk2py/g1/arm/g1_arm_action_client.py new file mode 100644 index 0000000..615d276 --- /dev/null +++ b/unitree_sdk2py/g1/arm/g1_arm_action_client.py @@ -0,0 +1,56 @@ +import json + +from ...rpc.client import Client +from .g1_arm_action_api import * + +action_map = { + "release arm": 99, + "two-hand kiss": 11, + "left kiss": 12, + "right kiss": 13, + "hands up": 15, + "clap": 17, + "high five": 18, + "hug": 19, + "heart": 20, + "right heart": 21, + "reject": 22, + "right hand up": 23, + "x-ray": 24, + "face wave": 25, + "high wave": 26, + "shake hand": 27, +} + + +""" +" class SportClient +""" +class G1ArmActionClient(Client): + def __init__(self): + super().__init__(ARM_ACTION_SERVICE_NAME, False) + + def Init(self): + # set api version + self._SetApiVerson(ARM_ACTION_API_VERSION) + + # regist api + self._RegistApi(ROBOT_API_ID_ARM_ACTION_EXECUTE_ACTION, 0) + self._RegistApi(ROBOT_API_ID_ARM_ACTION_GET_ACTION_LIST, 0) + + ## API Call ## + def ExecuteAction(self, action_id: int): + p = {} + p["data"] = action_id + parameter = json.dumps(p) + code, data = self._Call(ROBOT_API_ID_ARM_ACTION_EXECUTE_ACTION, parameter) + return code + + def GetActionList(self): + p = {} + parameter = json.dumps(p) + code, data = self._Call(ROBOT_API_ID_ARM_ACTION_GET_ACTION_LIST, parameter) + if code == 0: + return code, json.loads(data) + else: + return code, None \ No newline at end of file diff --git a/unitree_sdk2py/g1/audio/g1_audio_api.py b/unitree_sdk2py/g1/audio/g1_audio_api.py new file mode 100644 index 0000000..9aba780 --- /dev/null +++ b/unitree_sdk2py/g1/audio/g1_audio_api.py @@ -0,0 +1,24 @@ +""" +" service name +""" +AUDIO_SERVICE_NAME = "voice" + +""" +" service api version +""" +AUDIO_API_VERSION = "1.0.0.0" + +""" +" api id +""" +ROBOT_API_ID_AUDIO_TTS = 1001 +ROBOT_API_ID_AUDIO_ASR = 1002 +ROBOT_API_ID_AUDIO_START_PLAY = 1003 +ROBOT_API_ID_AUDIO_STOP_PLAY = 1004 +ROBOT_API_ID_AUDIO_GET_VOLUME = 1005 +ROBOT_API_ID_AUDIO_SET_VOLUME = 1006 +ROBOT_API_ID_AUDIO_SET_RGB_LED = 1010 + +""" +" error code +""" \ No newline at end of file diff --git a/unitree_sdk2py/g1/audio/g1_audio_client.py b/unitree_sdk2py/g1/audio/g1_audio_client.py new file mode 100644 index 0000000..d8d0bc3 --- /dev/null +++ b/unitree_sdk2py/g1/audio/g1_audio_client.py @@ -0,0 +1,62 @@ +import json + +from ...rpc.client import Client +from .g1_audio_api import * + +""" +" class SportClient +""" +class AudioClient(Client): + def __init__(self): + super().__init__(AUDIO_SERVICE_NAME, False) + self.tts_index = 0 + + def Init(self): + # set api version + self._SetApiVerson(AUDIO_API_VERSION) + + # regist api + self._RegistApi(ROBOT_API_ID_AUDIO_TTS, 0) + self._RegistApi(ROBOT_API_ID_AUDIO_ASR, 0) + self._RegistApi(ROBOT_API_ID_AUDIO_START_PLAY, 0) + self._RegistApi(ROBOT_API_ID_AUDIO_STOP_PLAY, 0) + self._RegistApi(ROBOT_API_ID_AUDIO_GET_VOLUME, 0) + self._RegistApi(ROBOT_API_ID_AUDIO_SET_VOLUME, 0) + self._RegistApi(ROBOT_API_ID_AUDIO_SET_RGB_LED, 0) + + ## API Call ## + def TtsMaker(self, text: str, speaker_id: int): + self.tts_index += self.tts_index + p = {} + p["index"] = self.tts_index + p["text"] = text + p["speaker_id"] = speaker_id + parameter = json.dumps(p) + code, data = self._Call(ROBOT_API_ID_AUDIO_TTS, parameter) + return code + + def GetVolume(self): + p = {} + parameter = json.dumps(p) + code, data = self._Call(ROBOT_API_ID_AUDIO_GET_VOLUME, parameter) + if code == 0: + return code, json.loads(data) + else: + return code, None + + def SetVolume(self, volume: int): + p = {} + p["volume"] = volume + # p["name"] = 'volume' + parameter = json.dumps(p) + code, data = self._Call(ROBOT_API_ID_AUDIO_SET_VOLUME, parameter) + return code + + def LedControl(self, R: int, G: int, B: int): + p = {} + p["R"] = R + p["G"] = G + p["B"] = B + parameter = json.dumps(p) + code, data = self._Call(ROBOT_API_ID_AUDIO_SET_RGB_LED, parameter) + return code diff --git a/unitree_sdk2py/g1/loco/g1_loco_api.py b/unitree_sdk2py/g1/loco/g1_loco_api.py new file mode 100644 index 0000000..2fdca7e --- /dev/null +++ b/unitree_sdk2py/g1/loco/g1_loco_api.py @@ -0,0 +1,32 @@ +""" +" service name +""" +LOCO_SERVICE_NAME = "sport" + + +""" +" service api version +""" +LOCO_API_VERSION = "1.0.0.0" + + +""" +" api id +""" +ROBOT_API_ID_LOCO_GET_FSM_ID = 7001 +ROBOT_API_ID_LOCO_GET_FSM_MODE = 7002 +ROBOT_API_ID_LOCO_GET_BALANCE_MODE = 7003 +ROBOT_API_ID_LOCO_GET_SWING_HEIGHT = 7004 +ROBOT_API_ID_LOCO_GET_STAND_HEIGHT = 7005 +ROBOT_API_ID_LOCO_GET_PHASE = 7006 # deprecated + +ROBOT_API_ID_LOCO_SET_FSM_ID = 7101 +ROBOT_API_ID_LOCO_SET_BALANCE_MODE = 7102 +ROBOT_API_ID_LOCO_SET_SWING_HEIGHT = 7103 +ROBOT_API_ID_LOCO_SET_STAND_HEIGHT = 7104 +ROBOT_API_ID_LOCO_SET_VELOCITY = 7105 +ROBOT_API_ID_LOCO_SET_ARM_TASK = 7106 + +""" +" error code +""" \ No newline at end of file diff --git a/unitree_sdk2py/g1/loco/g1_loco_client.py b/unitree_sdk2py/g1/loco/g1_loco_client.py new file mode 100644 index 0000000..9d3a632 --- /dev/null +++ b/unitree_sdk2py/g1/loco/g1_loco_client.py @@ -0,0 +1,127 @@ +import json + +from ...rpc.client import Client +from .g1_loco_api import * + +""" +" class SportClient +""" +class LocoClient(Client): + def __init__(self): + super().__init__(LOCO_SERVICE_NAME, False) + self.first_shake_hand_stage_ = -1 + + def Init(self): + # set api version + self._SetApiVerson(LOCO_API_VERSION) + + # regist api + self._RegistApi(ROBOT_API_ID_LOCO_GET_FSM_ID, 0) + self._RegistApi(ROBOT_API_ID_LOCO_GET_FSM_MODE, 0) + self._RegistApi(ROBOT_API_ID_LOCO_GET_BALANCE_MODE, 0) + self._RegistApi(ROBOT_API_ID_LOCO_GET_SWING_HEIGHT, 0) + self._RegistApi(ROBOT_API_ID_LOCO_GET_STAND_HEIGHT, 0) + self._RegistApi(ROBOT_API_ID_LOCO_GET_PHASE, 0) # deprecated + + self._RegistApi(ROBOT_API_ID_LOCO_SET_FSM_ID, 0) + self._RegistApi(ROBOT_API_ID_LOCO_SET_BALANCE_MODE, 0) + self._RegistApi(ROBOT_API_ID_LOCO_SET_SWING_HEIGHT, 0) + self._RegistApi(ROBOT_API_ID_LOCO_SET_STAND_HEIGHT, 0) + self._RegistApi(ROBOT_API_ID_LOCO_SET_VELOCITY, 0) + self._RegistApi(ROBOT_API_ID_LOCO_SET_ARM_TASK, 0) + + # 7101 + def SetFsmId(self, fsm_id: int): + p = {} + p["data"] = fsm_id + parameter = json.dumps(p) + code, data = self._Call(ROBOT_API_ID_LOCO_SET_FSM_ID, parameter) + return code + + # 7102 + def SetBalanceMode(self, balance_mode: int): + p = {} + p["data"] = balance_mode + parameter = json.dumps(p) + code, data = self._Call(ROBOT_API_ID_LOCO_SET_BALANCE_MODE, parameter) + return code + + # 7104 + def SetStandHeight(self, stand_height: float): + p = {} + p["data"] = stand_height + parameter = json.dumps(p) + code, data = self._Call(ROBOT_API_ID_LOCO_SET_STAND_HEIGHT, parameter) + return code + + # 7105 + def SetVelocity(self, vx: float, vy: float, omega: float, duration: float = 1.0): + p = {} + velocity = [vx,vy,omega] + p["velocity"] = velocity + p["duration"] = duration + parameter = json.dumps(p) + code, data = self._Call(ROBOT_API_ID_LOCO_SET_VELOCITY, parameter) + return code + + # 7106 + def SetTaskId(self, task_id: float): + p = {} + p["data"] = task_id + parameter = json.dumps(p) + code, data = self._Call(ROBOT_API_ID_LOCO_SET_ARM_TASK, parameter) + return code + + def Damp(self): + self.SetFsmId(1) + + def Start(self): + self.SetFsmId(200) + + def Squat2StandUp(self): + self.SetFsmId(706) + + def Lie2StandUp(self): + self.SetFsmId(702) + + def Sit(self): + self.SetFsmId(3) + + def StandUp2Squat(self): + self.SetFsmId(706) + + def ZeroTorque(self): + self.SetFsmId(0) + + def StopMove(self): + self.SetVelocity(0., 0., 0.) + + def HighStand(self): + UINT32_MAX = (1 << 32) - 1 + self.SetStandHeight(UINT32_MAX) + + def LowStand(self): + UINT32_MIN = 0 + self.SetStandHeight(UINT32_MIN) + + def Move(self, vx: float, vy: float, vyaw: float, continous_move: bool = False): + duration = 864000.0 if continous_move else 1 + self.SetVelocity(vx, vy, vyaw, duration) + + def BalanceStand(self, balance_mode: int): + self.SetBalanceMode(balance_mode) + + def WaveHand(self, turn_flag: bool = False): + self.SetTaskId(1 if turn_flag else 0) + + def ShakeHand(self, stage: int = -1): + if stage == 0: + self.first_shake_hand_stage_ = False + self.SetTaskId(2) + elif stage == 1: + self.first_shake_hand_stage_ = True + self.SetTaskId(3) + else: + self.first_shake_hand_stage_ = not self.first_shake_hand_stage_ + return self.SetTaskId(3 if self.first_shake_hand_stage_ else 2) + \ No newline at end of file diff --git a/unitree_sdk2py/go2/__init__.py b/unitree_sdk2py/go2/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/unitree_sdk2py/go2/obstacles_avoid/__init__.py b/unitree_sdk2py/go2/obstacles_avoid/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/unitree_sdk2py/go2/obstacles_avoid/obstacles_avoid_api.py b/unitree_sdk2py/go2/obstacles_avoid/obstacles_avoid_api.py new file mode 100644 index 0000000..ad9dc06 --- /dev/null +++ b/unitree_sdk2py/go2/obstacles_avoid/obstacles_avoid_api.py @@ -0,0 +1,19 @@ +""" +" service name +""" +OBSTACLES_AVOID_SERVICE_NAME = "obstacles_avoid" + + +""" +" service api version +""" +OBSTACLES_AVOID_API_VERSION = "1.0.0.2" + + +""" +" api id +""" +OBSTACLES_AVOID_API_ID_SWITCH_SET = 1001 +OBSTACLES_AVOID_API_ID_SWITCH_GET = 1002 +OBSTACLES_AVOID_API_ID_MOVE = 1003 +OBSTACLES_AVOID_API_ID_USE_REMOTE_COMMAND_FROM_API = 1004 \ No newline at end of file diff --git a/unitree_sdk2py/go2/obstacles_avoid/obstacles_avoid_client.py b/unitree_sdk2py/go2/obstacles_avoid/obstacles_avoid_client.py new file mode 100644 index 0000000..4d7b62b --- /dev/null +++ b/unitree_sdk2py/go2/obstacles_avoid/obstacles_avoid_client.py @@ -0,0 +1,60 @@ +import json + +from ...rpc.client import Client +from .obstacles_avoid_api import * + + +""" +" class ObstaclesAvoidClient +""" +class ObstaclesAvoidClient(Client): + def __init__(self): + super().__init__(OBSTACLES_AVOID_SERVICE_NAME, False) + + def Init(self): + # set api version + self._SetApiVerson(OBSTACLES_AVOID_API_VERSION) + # regist api + self._RegistApi(OBSTACLES_AVOID_API_ID_SWITCH_SET, 0) + self._RegistApi(OBSTACLES_AVOID_API_ID_SWITCH_GET, 0) + self._RegistApi(OBSTACLES_AVOID_API_ID_MOVE, 0) + self._RegistApi(OBSTACLES_AVOID_API_ID_USE_REMOTE_COMMAND_FROM_API, 0) + + # 1001 + def SwitchSet(self, on: bool): + p = {} + p["enable"] = on + parameter = json.dumps(p) + + code, data = self._Call(OBSTACLES_AVOID_API_ID_SWITCH_SET, parameter) + return code + + # 1002 + def SwitchGet(self): + p = {} + parameter = json.dumps(p) + + code, data = self._Call(OBSTACLES_AVOID_API_ID_SWITCH_GET, parameter) + if code == 0: + d = json.loads(data) + return code, d["enable"] + else: + return code, None + + # 1003 + def Move(self, vx: float, vy: float, vyaw: float): + p = {} + p["x"] = vx + p["y"] = vy + p["yaw"] = vyaw + p["mode"] = 0 + parameter = json.dumps(p) + code = self._CallNoReply(OBSTACLES_AVOID_API_ID_MOVE, parameter) + return code + + def UseRemoteCommandFromApi(self, isRemoteCommandsFromApi: bool): + p = {} + p["is_remote_commands_from_api"] = isRemoteCommandsFromApi + parameter = json.dumps(p) + code, data = self._Call(OBSTACLES_AVOID_API_ID_USE_REMOTE_COMMAND_FROM_API, parameter) + return code \ No newline at end of file diff --git a/unitree_sdk2py/go2/robot_state/__init__.py b/unitree_sdk2py/go2/robot_state/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/unitree_sdk2py/go2/robot_state/robot_state_api.py b/unitree_sdk2py/go2/robot_state/robot_state_api.py new file mode 100644 index 0000000..fde54df --- /dev/null +++ b/unitree_sdk2py/go2/robot_state/robot_state_api.py @@ -0,0 +1,25 @@ +""" +" service name +""" +ROBOT_STATE_SERVICE_NAME = "robot_state" + + +""" +" service api version +""" +ROBOT_STATE_API_VERSION = "1.0.0.1" + + +""" +" api id +""" +ROBOT_STATE_API_ID_SERVICE_SWITCH = 1001 +ROBOT_STATE_API_ID_REPORT_FREQ = 1002 +ROBOT_STATE_API_ID_SERVICE_LIST = 1003 + + +""" +" error code +""" +ROBOT_STATE_ERR_SERVICE_SWITCH = 5201 +ROBOT_STATE_ERR_SERVICE_PROTECTED = 5202 diff --git a/unitree_sdk2py/go2/robot_state/robot_state_client.py b/unitree_sdk2py/go2/robot_state/robot_state_client.py new file mode 100644 index 0000000..097a891 --- /dev/null +++ b/unitree_sdk2py/go2/robot_state/robot_state_client.py @@ -0,0 +1,84 @@ +import json + +from ...rpc.client import Client +from ...rpc.internal import * +from .robot_state_api import * + + +""" +" class ServiceState +""" +class ServiceState: + def __init__(self, name: str = None, status: int = None, protect: bool = None): + self.name = name + self.status = status + self.protect = protect + +""" +" class RobotStateClient +""" +class RobotStateClient(Client): + def __init__(self): + super().__init__(ROBOT_STATE_SERVICE_NAME, False) + + def Init(self): + # set api version + self._SetApiVerson(ROBOT_STATE_API_VERSION) + # regist api + self._RegistApi(ROBOT_STATE_API_ID_SERVICE_SWITCH, 0) + self._RegistApi(ROBOT_STATE_API_ID_REPORT_FREQ, 0) + self._RegistApi(ROBOT_STATE_API_ID_SERVICE_LIST, 0) + + def ServiceList(self): + p = {} + parameter = json.dumps(p) + + code, data = self._Call(ROBOT_STATE_API_ID_SERVICE_LIST, parameter) + + if code != 0: + return code, None + + lst = [] + + d = json.loads(data) + for t in d: + s = ServiceState() + s.name = t["name"] + s.status = t["status"] + s.protect = t["protect"] + lst.append(s) + + return code, lst + + + def ServiceSwitch(self, name: str, switch: bool): + p = {} + p["name"] = name + p["switch"] = int(switch) + parameter = json.dumps(p) + + code, data = self._Call(ROBOT_STATE_API_ID_SERVICE_SWITCH, parameter) + + if code != 0: + return code + + d = json.loads(data) + + status = d["status"] + + if status == 5: + return ROBOT_STATE_ERR_SERVICE_PROTECTED + + if status != 0 and status != 1: + return ROBOT_STATE_ERR_SERVICE_SWITCH + + return code + + def SetReportFreq(self, interval: int, duration: int): + p = {} + p["interval"] = interval + p["duration"] = duration + parameter = json.dumps(p) + + code, data = self._Call(ROBOT_STATE_API_ID_REPORT_FREQ, p) + return code diff --git a/unitree_sdk2py/go2/sport/__init__.py b/unitree_sdk2py/go2/sport/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/unitree_sdk2py/go2/sport/sport_api.py b/unitree_sdk2py/go2/sport/sport_api.py new file mode 100644 index 0000000..bfca62a --- /dev/null +++ b/unitree_sdk2py/go2/sport/sport_api.py @@ -0,0 +1,74 @@ +""" +" service name +""" +SPORT_SERVICE_NAME = "sport" + + +""" +" service api version +""" +SPORT_API_VERSION = "1.0.0.1" + + +""" +" api id +""" +SPORT_API_ID_DAMP = 1001 +SPORT_API_ID_BALANCESTAND = 1002 +SPORT_API_ID_STOPMOVE = 1003 +SPORT_API_ID_STANDUP = 1004 +SPORT_API_ID_STANDDOWN = 1005 +SPORT_API_ID_RECOVERYSTAND = 1006 +SPORT_API_ID_EULER = 1007 +SPORT_API_ID_MOVE = 1008 +SPORT_API_ID_SIT = 1009 +SPORT_API_ID_RISESIT = 1010 +SPORT_API_ID_SWITCHGAIT = 1011 +SPORT_API_ID_TRIGGER = 1012 +SPORT_API_ID_BODYHEIGHT = 1013 +SPORT_API_ID_FOOTRAISEHEIGHT = 1014 +SPORT_API_ID_SPEEDLEVEL = 1015 +SPORT_API_ID_HELLO = 1016 +SPORT_API_ID_STRETCH = 1017 +SPORT_API_ID_TRAJECTORYFOLLOW = 1018 +SPORT_API_ID_CONTINUOUSGAIT = 1019 +SPORT_API_ID_CONTENT = 1020 +SPORT_API_ID_WALLOW = 1021 +SPORT_API_ID_DANCE1 = 1022 +SPORT_API_ID_DANCE2 = 1023 +SPORT_API_ID_GETBODYHEIGHT = 1024 +SPORT_API_ID_GETFOOTRAISEHEIGHT = 1025 +SPORT_API_ID_GETSPEEDLEVEL = 1026 +SPORT_API_ID_SWITCHJOYSTICK = 1027 +SPORT_API_ID_POSE = 1028 +SPORT_API_ID_SCRAPE = 1029 +SPORT_API_ID_FRONTFLIP = 1030 +SPORT_API_ID_FRONTJUMP = 1031 +SPORT_API_ID_FRONTPOUNCE = 1032 +SPORT_API_ID_WIGGLEHIPS = 1033 +SPORT_API_ID_GETSTATE = 1034 +SPORT_API_ID_ECONOMICGAIT = 1035 +SPORT_API_ID_HEART = 1036 +ROBOT_SPORT_API_ID_DANCE3 = 1037 +ROBOT_SPORT_API_ID_DANCE4 = 1038 +ROBOT_SPORT_API_ID_HOPSPINLEFT = 1039 +ROBOT_SPORT_API_ID_HOPSPINRIGHT = 1040 + +ROBOT_SPORT_API_ID_LEFTFLIP = 1042 +ROBOT_SPORT_API_ID_BACKFLIP = 1044 +ROBOT_SPORT_API_ID_FREEWALK = 1045 +ROBOT_SPORT_API_ID_FREEBOUND = 1046 +ROBOT_SPORT_API_ID_FREEJUMP = 1047 +ROBOT_SPORT_API_ID_FREEAVOID = 1048 +ROBOT_SPORT_API_ID_WALKSTAIR = 1049 +ROBOT_SPORT_API_ID_WALKUPRIGHT = 1050 +ROBOT_SPORT_API_ID_CROSSSTEP = 1051 + +""" +" error code +""" +# client side +SPORT_ERR_CLIENT_POINT_PATH = 4101 +# server side +SPORT_ERR_SERVER_OVERTIME = 4201 +SPORT_ERR_SERVER_NOT_INIT = 4202 diff --git a/unitree_sdk2py/go2/sport/sport_client.py b/unitree_sdk2py/go2/sport/sport_client.py new file mode 100644 index 0000000..d058e51 --- /dev/null +++ b/unitree_sdk2py/go2/sport/sport_client.py @@ -0,0 +1,446 @@ +import json + +from ...rpc.client import Client +from .sport_api import * + +""" +" SPORT_PATH_POINT_SIZE +""" +SPORT_PATH_POINT_SIZE = 30 + + +""" +" class PathPoint +""" +class PathPoint: + def __init__(self, timeFromStart: float, x: float, y: float, yaw: float, vx: float, vy: float, vyaw: float): + self.timeFromStart = timeFromStart + self.x = x + self.y = y + self.yaw = yaw + self.vx = vx + self.vy = vy + self.vyaw = vyaw + + +""" +" class SportClient +""" +class SportClient(Client): + def __init__(self, enableLease: bool = False): + super().__init__(SPORT_SERVICE_NAME, enableLease) + + + def Init(self): + # set api version + self._SetApiVerson(SPORT_API_VERSION) + + # regist api + self._RegistApi(SPORT_API_ID_DAMP, 0) + self._RegistApi(SPORT_API_ID_BALANCESTAND, 0) + self._RegistApi(SPORT_API_ID_STOPMOVE, 0) + self._RegistApi(SPORT_API_ID_STANDUP, 0) + self._RegistApi(SPORT_API_ID_STANDDOWN, 0) + self._RegistApi(SPORT_API_ID_RECOVERYSTAND, 0) + self._RegistApi(SPORT_API_ID_EULER, 0) + self._RegistApi(SPORT_API_ID_MOVE, 0) + self._RegistApi(SPORT_API_ID_SIT, 0) + self._RegistApi(SPORT_API_ID_RISESIT, 0) + self._RegistApi(SPORT_API_ID_SWITCHGAIT, 0) + self._RegistApi(SPORT_API_ID_TRIGGER, 0) + self._RegistApi(SPORT_API_ID_BODYHEIGHT, 0) + self._RegistApi(SPORT_API_ID_FOOTRAISEHEIGHT, 0) + self._RegistApi(SPORT_API_ID_SPEEDLEVEL, 0) + self._RegistApi(SPORT_API_ID_HELLO, 0) + self._RegistApi(SPORT_API_ID_STRETCH, 0) + self._RegistApi(SPORT_API_ID_TRAJECTORYFOLLOW, 0) + self._RegistApi(SPORT_API_ID_CONTINUOUSGAIT, 0) + # self._RegistApi(SPORT_API_ID_CONTENT, 0) + self._RegistApi(SPORT_API_ID_WALLOW, 0) + self._RegistApi(SPORT_API_ID_DANCE1, 0) + self._RegistApi(SPORT_API_ID_DANCE2, 0) + # self._RegistApi(SPORT_API_ID_GETBODYHEIGHT, 0) + # self._RegistApi(SPORT_API_ID_GETFOOTRAISEHEIGHT, 0) + # self._RegistApi(SPORT_API_ID_GETSPEEDLEVEL, 0) + self._RegistApi(SPORT_API_ID_SWITCHJOYSTICK, 0) + self._RegistApi(SPORT_API_ID_POSE, 0) + self._RegistApi(SPORT_API_ID_SCRAPE, 0) + self._RegistApi(SPORT_API_ID_FRONTFLIP, 0) + self._RegistApi(SPORT_API_ID_FRONTJUMP, 0) + self._RegistApi(SPORT_API_ID_FRONTPOUNCE, 0) + self._RegistApi(SPORT_API_ID_WIGGLEHIPS, 0) + self._RegistApi(SPORT_API_ID_GETSTATE, 0) + self._RegistApi(SPORT_API_ID_ECONOMICGAIT, 0) + self._RegistApi(SPORT_API_ID_HEART, 0) + + self._RegistApi(ROBOT_SPORT_API_ID_LEFTFLIP, 0) + self._RegistApi(ROBOT_SPORT_API_ID_BACKFLIP, 0) + self._RegistApi(ROBOT_SPORT_API_ID_FREEWALK, 0) + self._RegistApi(ROBOT_SPORT_API_ID_FREEBOUND, 0) + self._RegistApi(ROBOT_SPORT_API_ID_FREEJUMP, 0) + self._RegistApi(ROBOT_SPORT_API_ID_FREEAVOID, 0) + self._RegistApi(ROBOT_SPORT_API_ID_WALKSTAIR, 0) + self._RegistApi(ROBOT_SPORT_API_ID_WALKUPRIGHT, 0) + self._RegistApi(ROBOT_SPORT_API_ID_CROSSSTEP, 0) + + # 1001 + def Damp(self): + p = {} + parameter = json.dumps(p) + code, data = self._Call(SPORT_API_ID_DAMP, parameter) + return code + + # 1002 + def BalanceStand(self): + p = {} + parameter = json.dumps(p) + code, data = self._Call(SPORT_API_ID_BALANCESTAND, parameter) + return code + + # 1003 + def StopMove(self): + p = {} + parameter = json.dumps(p) + code, data = self._Call(SPORT_API_ID_STOPMOVE, parameter) + return code + + # 1004 + def StandUp(self): + p = {} + parameter = json.dumps(p) + code, data = self._Call(SPORT_API_ID_STANDUP, parameter) + return code + + # 1005 + def StandDown(self): + p = {} + parameter = json.dumps(p) + code, data = self._Call(SPORT_API_ID_STANDDOWN, parameter) + return code + + # 1006 + def RecoveryStand(self): + p = {} + parameter = json.dumps(p) + code, data = self._Call(SPORT_API_ID_RECOVERYSTAND, parameter) + return code + + # 1007 + def Euler(self, roll: float, pitch: float, yaw: float): + p = {} + p["x"] = roll + p["y"] = pitch + p["z"] = yaw + parameter = json.dumps(p) + code, data = self._Call(SPORT_API_ID_EULER, parameter) + return code + + # 1008 + def Move(self, vx: float, vy: float, vyaw: float): + p = {} + p["x"] = vx + p["y"] = vy + p["z"] = vyaw + parameter = json.dumps(p) + code = self._CallNoReply(SPORT_API_ID_MOVE, parameter) + return code + + # 1009 + def Sit(self): + p = {} + parameter = json.dumps(p) + code, data = self._Call(SPORT_API_ID_SIT, parameter) + return code + + #1010 + def RiseSit(self): + p = {} + parameter = json.dumps(p) + code, data = self._Call(SPORT_API_ID_RISESIT, parameter) + return code + + # 1011 + def SwitchGait(self, t: int): + p = {} + p["data"] = t + parameter = json.dumps(p) + code, data = self._Call(SPORT_API_ID_SWITCHGAIT, parameter) + return code + + # 1012 + def Trigger(self): + p = {} + parameter = json.dumps(p) + code, data = self._Call(SPORT_API_ID_TRIGGER, parameter) + return code + + # 1013 + def BodyHeight(self, height: float): + p = {} + p["data"] = height + parameter = json.dumps(p) + code, data = self._Call(SPORT_API_ID_BODYHEIGHT, parameter) + return code + + # 1014 + def FootRaiseHeight(self, height: float): + p = {} + p["data"] = height + parameter = json.dumps(p) + code, data = self._Call(SPORT_API_ID_FOOTRAISEHEIGHT, parameter) + return code + + # 1015 + def SpeedLevel(self, level: int): + p = {} + p["data"] = level + parameter = json.dumps(p) + code, data = self._Call(SPORT_API_ID_SPEEDLEVEL, parameter) + return code + + # 1016 + def Hello(self): + p = {} + parameter = json.dumps(p) + code, data = self._Call(SPORT_API_ID_HELLO, parameter) + return code + + # 1017 + def Stretch(self): + p = {} + parameter = json.dumps(p) + code, data = self._Call(SPORT_API_ID_STRETCH, parameter) + return code + + # 1018 + def TrajectoryFollow(self, path: list): + l = len(path) + if l != SPORT_PATH_POINT_SIZE: + return SPORT_ERR_CLIENT_POINT_PATH + + path_p = [] + for i in range(l): + point = path[i] + p = {} + p["t_from_start"] = point.timeFromStart + p["x"] = point.x + p["y"] = point.y + p["yaw"] = point.yaw + p["vx"] = point.vx + p["vy"] = point.vy + p["vyaw"] = point.vyaw + path_p.append(p) + + parameter = json.dumps(path_p) + code = self._CallNoReply(SPORT_API_ID_TRAJECTORYFOLLOW, parameter) + return code + + # 1019 + def ContinuousGait(self, flag: int): + p = {} + p["data"] = flag + parameter = json.dumps(p) + code, data = self._Call(SPORT_API_ID_CONTINUOUSGAIT, parameter) + return code + + # # 1020 + # def Content(self): + # p = {} + # parameter = json.dumps(p) + # code, data = self._Call(SPORT_API_ID_CONTENT, parameter) + # return code + + # 1021 + def Wallow(self): + p = {} + parameter = json.dumps(p) + code, data = self._Call(SPORT_API_ID_WALLOW, parameter) + return code + + # 1022 + def Dance1(self): + p = {} + parameter = json.dumps(p) + code, data = self._Call(SPORT_API_ID_DANCE1, parameter) + return code + + # 1023 + def Dance2(self): + p = {} + parameter = json.dumps(p) + code, data = self._Call(SPORT_API_ID_DANCE2, parameter) + return code + + # 1025 + def GetFootRaiseHeight(self): + p = {} + parameter = json.dumps(p) + + code, data = self._Call(SPORT_API_ID_GETFOOTRAISEHEIGHT, parameter) + + if code == 0: + d = json.loads(data) + return code, d["data"] + else: + return code, None + + + # 1026 + def GetSpeedLevel(self): + p = {} + parameter = json.dumps(p) + + code, data = self._Call(SPORT_API_ID_GETSPEEDLEVEL, parameter) + + if code == 0: + d = json.loads(data) + return code, d["data"] + else: + return code, None + + # 1027 + def SwitchJoystick(self, on: bool): + p = {} + p["data"] = on + parameter = json.dumps(p) + code, data = self._Call(SPORT_API_ID_SWITCHJOYSTICK, parameter) + return code + + # 1028 + def Pose(self, flag: bool): + p = {} + p["data"] = flag + parameter = json.dumps(p) + code, data = self._Call(SPORT_API_ID_POSE, parameter) + return code + + # 1029 + def Scrape(self): + p = {} + parameter = json.dumps(p) + code, data = self._Call(SPORT_API_ID_SCRAPE, parameter) + return code + + # 1030 + def FrontFlip(self): + p = {} + parameter = json.dumps(p) + code, data = self._Call(SPORT_API_ID_FRONTFLIP, parameter) + return code + + # 1031 + def FrontJump(self): + p = {} + parameter = json.dumps(p) + code, data = self._Call(SPORT_API_ID_FRONTJUMP, parameter) + return code + + # 1032 + def FrontPounce(self): + p = {} + parameter = json.dumps(p) + code, data = self._Call(SPORT_API_ID_FRONTPOUNCE, parameter) + return code + + # 1033 + def WiggleHips(self): + p = {} + parameter = json.dumps(p) + code, data = self._Call(SPORT_API_ID_WIGGLEHIPS, parameter) + return code + + # 1034 + def GetState(self, keys: list): + parameter = json.dumps(keys) + code, data = self._Call(SPORT_API_ID_GETSTATE, parameter) + if code == 0: + return code, json.loads(data) + else: + return code, None + + # 1035 + def EconomicGait(self, flag: bool): + p = {} + p["data"] = flag + parameter = json.dumps(p) + code, data = self._Call(SPORT_API_ID_ECONOMICGAIT, parameter) + return code + + # 1036 + def Heart(self): + p = {} + parameter = json.dumps(p) + code, data = self._Call(SPORT_API_ID_HEART, parameter) + return code + + # 1042 + def LeftFlip(self): + p = {} + p["data"] = True + parameter = json.dumps(p) + code, data = self._Call(ROBOT_SPORT_API_ID_LEFTFLIP, parameter) + return code + + # 1044 + def BackFlip(self): + p = {} + p["data"] = True + parameter = json.dumps(p) + code, data = self._Call(ROBOT_SPORT_API_ID_BACKFLIP, parameter) + return code + + # 1045 + def FreeWalk(self, flag: bool): + p = {} + p["data"] = True + parameter = json.dumps(p) + code, data = self._Call(ROBOT_SPORT_API_ID_FREEWALK, parameter) + return code + + # 1046 + def FreeBound(self, flag: bool): + p = {} + p["data"] = flag + parameter = json.dumps(p) + code, data = self._Call(ROBOT_SPORT_API_ID_FREEBOUND, parameter) + return code + + # 1047 + def FreeJump(self, flag: bool): + p = {} + p["data"] = flag + parameter = json.dumps(p) + code, data = self._Call(ROBOT_SPORT_API_ID_FREEJUMP, parameter) + return code + + # 1048 + def FreeAvoid(self, flag: bool): + p = {} + p["data"] = flag + parameter = json.dumps(p) + code, data = self._Call(ROBOT_SPORT_API_ID_FREEAVOID, parameter) + return code + + # 1049 + def WalkStair(self, flag: bool): + p = {} + p["data"] = flag + parameter = json.dumps(p) + code, data = self._Call(ROBOT_SPORT_API_ID_WALKSTAIR, parameter) + return code + + # 1050 + def WalkUpright(self, flag: bool): + p = {} + p["data"] = flag + parameter = json.dumps(p) + code, data = self._Call(ROBOT_SPORT_API_ID_WALKUPRIGHT, parameter) + return code + + # 1051 + def CrossStep(self, flag: bool): + p = {} + p["data"] = flag + parameter = json.dumps(p) + code, data = self._Call(ROBOT_SPORT_API_ID_CROSSSTEP, parameter) + return code \ No newline at end of file diff --git a/unitree_sdk2py/go2/video/__init__.py b/unitree_sdk2py/go2/video/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/unitree_sdk2py/go2/video/video_api.py b/unitree_sdk2py/go2/video/video_api.py new file mode 100644 index 0000000..a4cb1b6 --- /dev/null +++ b/unitree_sdk2py/go2/video/video_api.py @@ -0,0 +1,16 @@ +""" +" service name +""" +VIDEO_SERVICE_NAME = "videohub" + + +""" +" service api version +""" +VIDEO_API_VERSION = "1.0.0.1" + + +""" +" api id +""" +VIDEO_API_ID_GETIMAGESAMPLE = 1001 diff --git a/unitree_sdk2py/go2/video/video_client.py b/unitree_sdk2py/go2/video/video_client.py new file mode 100644 index 0000000..79e1fb5 --- /dev/null +++ b/unitree_sdk2py/go2/video/video_client.py @@ -0,0 +1,23 @@ +import json + +from ...rpc.client import Client +from .video_api import * + + +""" +" class VideoClient +""" +class VideoClient(Client): + def __init__(self): + super().__init__(VIDEO_SERVICE_NAME, False) + + + def Init(self): + # set api version + self._SetApiVerson(VIDEO_API_VERSION) + # regist api + self._RegistApi(VIDEO_API_ID_GETIMAGESAMPLE, 0) + + # 1001 + def GetImageSample(self): + return self._CallBinary(VIDEO_API_ID_GETIMAGESAMPLE, []) diff --git a/unitree_sdk2py/go2/vui/__init__.py b/unitree_sdk2py/go2/vui/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/unitree_sdk2py/go2/vui/vui_api.py b/unitree_sdk2py/go2/vui/vui_api.py new file mode 100644 index 0000000..d5dcd34 --- /dev/null +++ b/unitree_sdk2py/go2/vui/vui_api.py @@ -0,0 +1,21 @@ +""" +" service name +""" +VUI_SERVICE_NAME = "vui" + + +""" +" service api version +""" +VUI_API_VERSION = "1.0.0.1" + + +""" +" api id +""" +VUI_API_ID_SETSWITCH = 1001 +VUI_API_ID_GETSWITCH = 1002 +VUI_API_ID_SETVOLUME = 1003 +VUI_API_ID_GETVOLUME = 1004 +VUI_API_ID_SETBRIGHTNESS = 1005 +VUI_API_ID_GETBRIGHTNESS = 1006 diff --git a/unitree_sdk2py/go2/vui/vui_client.py b/unitree_sdk2py/go2/vui/vui_client.py new file mode 100644 index 0000000..234f285 --- /dev/null +++ b/unitree_sdk2py/go2/vui/vui_client.py @@ -0,0 +1,86 @@ +import json + +from ...rpc.client import Client +from .vui_api import * + + +""" +" class VideoClient +""" +class VuiClient(Client): + def __init__(self): + super().__init__(VUI_SERVICE_NAME, False) + + def Init(self): + # set api version + self._SetApiVerson(VUI_API_VERSION) + # regist api + self._RegistApi(VUI_API_ID_SETSWITCH, 0) + self._RegistApi(VUI_API_ID_GETSWITCH, 0) + self._RegistApi(VUI_API_ID_SETVOLUME, 0) + self._RegistApi(VUI_API_ID_GETVOLUME, 0) + self._RegistApi(VUI_API_ID_SETBRIGHTNESS, 0) + self._RegistApi(VUI_API_ID_GETBRIGHTNESS, 0) + + # 1001 + def SetSwitch(self, enable: int): + p = {} + p["enable"] = enable + parameter = json.dumps(p) + + code, data = self._Call(VUI_API_ID_SETSWITCH, parameter) + return code + + # 1002 + def GetSwitch(self): + p = {} + parameter = json.dumps(p) + + code, data = self._Call(VUI_API_ID_GETSWITCH, parameter) + if code == 0: + d = json.loads(data) + return code, d["enable"] + else: + return code, None + + # 1003 + def SetVolume(self, level: int): + p = {} + p["volume"] = level + parameter = json.dumps(p) + + code, data = self._Call(VUI_API_ID_SETVOLUME, parameter) + return code + + # 1006 + def GetVolume(self): + p = {} + parameter = json.dumps(p) + + code, data = self._Call(VUI_API_ID_GETVOLUME, parameter) + if code == 0: + d = json.loads(data) + return code, d["volume"] + else: + return code, None + + # 1005 + def SetBrightness(self, level: int): + p = {} + p["brightness"] = level + parameter = json.dumps(p) + + code, data = self._Call(VUI_API_ID_SETBRIGHTNESS, parameter) + return code + + # 1006 + def GetBrightness(self): + p = {} + parameter = json.dumps(p) + + code, data = self._Call(VUI_API_ID_GETBRIGHTNESS, parameter) + if code == 0: + d = json.loads(data) + return code, d["brightness"] + else: + return code, None \ No newline at end of file diff --git a/unitree_sdk2py/h1/loco/h1_loco_api.py b/unitree_sdk2py/h1/loco/h1_loco_api.py new file mode 100644 index 0000000..bd8ddbe --- /dev/null +++ b/unitree_sdk2py/h1/loco/h1_loco_api.py @@ -0,0 +1,31 @@ +""" +" service name +""" +LOCO_SERVICE_NAME = "loco" + + +""" +" service api version +""" +LOCO_API_VERSION = "2.0.0.0" + + +""" +" api id +""" +ROBOT_API_ID_LOCO_GET_FSM_ID = 8001 +ROBOT_API_ID_LOCO_GET_FSM_MODE = 8002 +ROBOT_API_ID_LOCO_GET_BALANCE_MODE = 8003 +ROBOT_API_ID_LOCO_GET_SWING_HEIGHT = 8004 +ROBOT_API_ID_LOCO_GET_STAND_HEIGHT = 8005 +ROBOT_API_ID_LOCO_GET_PHASE = 8006 # deprecated + +ROBOT_API_ID_LOCO_SET_FSM_ID = 8101 +ROBOT_API_ID_LOCO_SET_BALANCE_MODE = 8102 +ROBOT_API_ID_LOCO_SET_SWING_HEIGHT = 8103 +ROBOT_API_ID_LOCO_SET_STAND_HEIGHT = 8104 +ROBOT_API_ID_LOCO_SET_VELOCITY = 8105 + +""" +" error code +""" \ No newline at end of file diff --git a/unitree_sdk2py/h1/loco/h1_loco_client.py b/unitree_sdk2py/h1/loco/h1_loco_client.py new file mode 100644 index 0000000..3bc01e3 --- /dev/null +++ b/unitree_sdk2py/h1/loco/h1_loco_client.py @@ -0,0 +1,83 @@ +import json + +from ...rpc.client import Client +from .h1_loco_api import * + +""" +" class SportClient +""" +class LocoClient(Client): + def __init__(self): + super().__init__(LOCO_SERVICE_NAME, False) + + + def Init(self): + # set api version + self._SetApiVerson(LOCO_API_VERSION) + + # regist api + self._RegistApi(ROBOT_API_ID_LOCO_GET_FSM_ID, 0) + self._RegistApi(ROBOT_API_ID_LOCO_GET_FSM_MODE, 0) + self._RegistApi(ROBOT_API_ID_LOCO_GET_BALANCE_MODE, 0) + self._RegistApi(ROBOT_API_ID_LOCO_GET_SWING_HEIGHT, 0) + self._RegistApi(ROBOT_API_ID_LOCO_GET_STAND_HEIGHT, 0) + self._RegistApi(ROBOT_API_ID_LOCO_GET_PHASE, 0) # deprecated + + self._RegistApi(ROBOT_API_ID_LOCO_SET_FSM_ID, 0) + self._RegistApi(ROBOT_API_ID_LOCO_SET_BALANCE_MODE, 0) + self._RegistApi(ROBOT_API_ID_LOCO_SET_SWING_HEIGHT, 0) + self._RegistApi(ROBOT_API_ID_LOCO_SET_STAND_HEIGHT, 0) + self._RegistApi(ROBOT_API_ID_LOCO_SET_VELOCITY, 0) + + # 8101 + def SetFsmId(self, fsm_id: int): + p = {} + p["data"] = fsm_id + parameter = json.dumps(p) + code, data = self._Call(ROBOT_API_ID_LOCO_SET_FSM_ID, parameter) + return code + + # 8104 + def SetStandHeight(self, stand_height: float): + p = {} + p["data"] = stand_height + parameter = json.dumps(p) + code, data = self._Call(ROBOT_API_ID_LOCO_SET_STAND_HEIGHT, parameter) + return code + + # 8105 + def SetVelocity(self, vx: float, vy: float, omega: float, duration: float = 1.0): + p = {} + velocity = [vx,vy,omega] + p["velocity"] = velocity + p["duration"] = duration + parameter = json.dumps(p) + code, data = self._Call(ROBOT_API_ID_LOCO_SET_VELOCITY, parameter) + return code + + def Damp(self): + self.SetFsmId(1) + + def Start(self): + self.SetFsmId(204) + + def StandUp(self): + self.SetFsmId(2) + + def ZeroTorque(self): + self.SetFsmId(0) + + def StopMove(self): + self.SetVelocity(0., 0., 0.) + + def HighStand(self): + UINT32_MAX = (1 << 32) - 1 + self.SetStandHeight(UINT32_MAX) + + def LowStand(self): + UINT32_MIN = 0 + self.SetStandHeight(UINT32_MIN) + + def Move(self, vx: float, vy: float, vyaw: float, continous_move: bool = False): + duration = 864000.0 if continous_move else 1 + self.SetVelocity(vx, vy, vyaw, duration) \ No newline at end of file diff --git a/unitree_sdk2py/idl/__init__.py b/unitree_sdk2py/idl/__init__.py new file mode 100644 index 0000000..38d706e --- /dev/null +++ b/unitree_sdk2py/idl/__init__.py @@ -0,0 +1,12 @@ +from .default import * +from . import builtin_interfaces, geometry_msgs, sensor_msgs, std_msgs, unitree_go, unitree_api + +__all__ = [ + "builtin_interfaces", + "geometry_msgs", + "sensor_msgs", + "std_msgs", + "unitree_go", + "unitree_hg", + "unitree_api", +] diff --git a/unitree_sdk2py/idl/builtin_interfaces/__init__.py b/unitree_sdk2py/idl/builtin_interfaces/__init__.py new file mode 100644 index 0000000..c0397fd --- /dev/null +++ b/unitree_sdk2py/idl/builtin_interfaces/__init__.py @@ -0,0 +1,9 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: builtin_interfaces + +""" + +from . import msg +__all__ = ["msg", ] diff --git a/unitree_sdk2py/idl/builtin_interfaces/msg/__init__.py b/unitree_sdk2py/idl/builtin_interfaces/msg/__init__.py new file mode 100644 index 0000000..b791398 --- /dev/null +++ b/unitree_sdk2py/idl/builtin_interfaces/msg/__init__.py @@ -0,0 +1,9 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: builtin_interfaces.msg + +""" + +from . import dds_ +__all__ = ["dds_", ] diff --git a/unitree_sdk2py/idl/builtin_interfaces/msg/dds_/_Time_.py b/unitree_sdk2py/idl/builtin_interfaces/msg/dds_/_Time_.py new file mode 100644 index 0000000..970c671 --- /dev/null +++ b/unitree_sdk2py/idl/builtin_interfaces/msg/dds_/_Time_.py @@ -0,0 +1,28 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: builtin_interfaces.msg.dds_ + IDL file: Time_.idl + +""" + +from enum import auto +from typing import TYPE_CHECKING, Optional +from dataclasses import dataclass + +import cyclonedds.idl as idl +import cyclonedds.idl.annotations as annotate +import cyclonedds.idl.types as types + +# root module import for resolving types +# import builtin_interfaces + + +@dataclass +@annotate.final +@annotate.autoid("sequential") +class Time_(idl.IdlStruct, typename="builtin_interfaces.msg.dds_.Time_"): + sec: types.int32 + nanosec: types.uint32 + + diff --git a/unitree_sdk2py/idl/builtin_interfaces/msg/dds_/__init__.py b/unitree_sdk2py/idl/builtin_interfaces/msg/dds_/__init__.py new file mode 100644 index 0000000..c3f9730 --- /dev/null +++ b/unitree_sdk2py/idl/builtin_interfaces/msg/dds_/__init__.py @@ -0,0 +1,9 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: builtin_interfaces.msg.dds_ + +""" + +from ._Time_ import Time_ +__all__ = ["Time_", ] diff --git a/unitree_sdk2py/idl/default.py b/unitree_sdk2py/idl/default.py new file mode 100644 index 0000000..89d567d --- /dev/null +++ b/unitree_sdk2py/idl/default.py @@ -0,0 +1,268 @@ +from .builtin_interfaces.msg.dds_ import * +from .std_msgs.msg.dds_ import * +from .geometry_msgs.msg.dds_ import * +from .nav_msgs.msg.dds_ import * +from .sensor_msgs.msg.dds_ import * +from .unitree_go.msg.dds_ import * +from .unitree_api.msg.dds_ import * + +# IDL for unitree_hg +from .unitree_hg.msg.dds_ import LowCmd_ as HGLowCmd_ +from .unitree_hg.msg.dds_ import LowState_ as HGLowState_ +from .unitree_hg.msg.dds_ import MotorCmd_ as HGMotorCmd_ +from .unitree_hg.msg.dds_ import MotorState_ as HGMotorState_ +from .unitree_hg.msg.dds_ import BmsState_ as HGBmsState_ +from .unitree_hg.msg.dds_ import IMUState_ as HGIMUState_ +from .unitree_hg.msg.dds_ import MainBoardState_ as HGMainBoardState_ +from .unitree_hg.msg.dds_ import PressSensorState_ as HGPressSensorState_ +from .unitree_hg.msg.dds_ import HandCmd_ as HGHandCmd_ +from .unitree_hg.msg.dds_ import HandState_ as HGHandState_ + +""" +" builtin_interfaces_msgs.msg.dds_ dafault +""" +def builtin_interfaces_msgs_msg_dds__Time_(): + return Time_(0, 0) + + +""" +" std_msgs.msg.dds_ dafault +""" +def std_msgs_msg_dds__Header_(): + return Header_(builtin_interfaces_msgs_msg_dds__Time_(), "") + +def std_msgs_msg_dds__String_(): + return String_("") + + +""" +" geometry_msgs.msg.dds_ dafault +""" +def geometry_msgs_msg_dds__Point_(): + return Point_(0.0, 0.0, 0.0) + +def geometry_msgs_msg_dds__Point32_(): + return Point32_(0.0, 0.0, 0.0) + +def geometry_msgs_msg_dds__PointStamped_(): + return PointStamped_(std_msgs_msg_dds__Header_(), geometry_msgs_msg_dds__Point_()) + +def geometry_msgs_msg_dds__Quaternion_(): + return Quaternion_(0.0, 0.0, 0.0, 0.0) + +def geometry_msgs_msg_dds__Vector3_(): + return Vector3_(0.0, 0.0, 0.0) + +def geometry_msgs_msg_dds__Pose_(): + return Pose_(geometry_msgs_msg_dds__Point_(), geometry_msgs_msg_dds__Quaternion_()) + +def geometry_msgs_msg_dds__Pose2D_(): + return Pose2D_(0.0, 0.0, 0.0) + +def geometry_msgs_msg_dds__PoseStamped_(): + return PoseStamped_(std_msgs_msg_dds__Header_(), geometry_msgs_msg_dds__Pose_()) + +def geometry_msgs_msg_dds__PoseWithCovariance_(): + return PoseWithCovariance_(geometry_msgs_msg_dds__Pose_(), [ + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 + ]) + +def geometry_msgs_msg_dds__PoseWithCovarianceStamped_(): + return PoseWithCovarianceStamped_(std_msgs_msg_dds__Header_(), geometry_msgs_msg_dds__PoseWithCovariance_()) + +def geometry_msgs_msg_dds__QuaternionStamped_(): + return QuaternionStamped_(std_msgs_msg_dds__Header_(), geometry_msgs_msg_dds__Quaternion_()) + +def geometry_msgs_msg_dds__Twist_(): + return Twist_(geometry_msgs_msg_dds__Vector3_(), geometry_msgs_msg_dds__Vector3_()) + +def geometry_msgs_msg_dds__TwistStamped_(): + return TwistStamped_(std_msgs_msg_dds__Header_(), geometry_msgs_msg_dds__Twist_()) + +def geometry_msgs_msg_dds__TwistWithCovariance_(): + return TwistWithCovariance_(geometry_msgs_msg_dds__Twist_(), [ + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 + ]) + +def geometry_msgs_msg_dds__TwistWithCovarianceStamped_(): + return TwistWithCovarianceStamped_(std_msgs_msg_dds__Header_(), geometry_msgs_msg_dds__TwistWithCovariance_()) + + +""" +" nav_msgs.msg.dds_ dafault +""" +def nav_msgs_msg_dds__MapMetaData_(): + return MapMetaData_(builtin_interfaces_msgs_msg_dds__Time_(), 0, 0, geometry_msgs_msg_dds__Pose_()) + +def nav_msgs_msg_dds__OccupancyGrid_(): + return OccupancyGrid_(std_msgs_msg_dds__Header_(), nav_msgs_msg_dds__MapMetaData_(), []) + +def nav_msgs_msg_dds__Odometry_(): + return Odometry_(std_msgs_msg_dds__Header_(), "", geometry_msgs_msg_dds__PoseWithCovariance_(), + geometry_msgs_msg_dds__TwistWithCovariance_()) + + +""" +" sensor_msgs.msg.dds_ dafault +""" +def sensor_msgs_msg_dds__PointField_Constants_PointField_(): + return PointField_("", 0, 0, 0) + +def sensor_msgs_msg_dds__PointField_Constants_PointCloud2_(): + return PointCloud2_(std_msgs_msg_dds__Header_(), 0, 0, [], False, 0, 0, [], False) + + +""" +" unitree_go.msg.dds_ dafault +""" +def unitree_go_msg_dds__AudioData_(): + return AudioData_(0, []) + +def unitree_go_msg_dds__BmsCmd_(): + return BmsCmd_(0, [0, 0, 0]) + +def unitree_go_msg_dds__BmsState_(): + return BmsState_(0, 0, 0, 0, 0, 0, [0, 0], [0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) + +def unitree_go_msg_dds__Error_(): + return Error_(0, 0) + +def unitree_go_msg_dds__Go2FrontVideoData_(): + return Go2FrontVideoData_(0, [], [], []) + +def unitree_go_msg_dds__HeightMap_(): + return HeightMap_(0.0, "", 0.0, 0, 0, [0.0, 0.0], []) + +def unitree_go_msg_dds__IMUState_(): + return IMUState_([0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], 0) + +def unitree_go_msg_dds__InterfaceConfig_(): + return InterfaceConfig_(0, 0, [0, 0]) + +def unitree_go_msg_dds__LidarState_(): + return LidarState_(0.0, "", "", "", 0.0, 0.0, 0, 0.0, 0.0, 0, 0, 0.0, 0.0, [0.0, 0.0, 0.0], 0.0, 0, 0) + +def unitree_go_msg_dds__MotorCmd_(): + return MotorCmd_(0, 0.0, 0.0, 0.0, 0.0, 0.0, [0, 0, 0]) + +def unitree_go_msg_dds__MotorState_(): + return MotorState_(0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, 0, [0, 0]) + +def unitree_go_msg_dds__LowCmd_(): + return LowCmd_([0, 0], 0, 0, [0, 0], [0, 0], 0, [unitree_go_msg_dds__MotorCmd_() for i in range(20)], + unitree_go_msg_dds__BmsCmd_(), + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0], 0, 0, 0) + +def unitree_go_msg_dds__LowState_(): + return LowState_([0, 0], 0, 0, [0, 0], [0, 0], 0, unitree_go_msg_dds__IMUState_(), + [unitree_go_msg_dds__MotorState_() for i in range(20)], + unitree_go_msg_dds__BmsState_(), [0, 0, 0, 0], [0, 0, 0, 0], 0, + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + 0, 0, 0, 0, 0.0, 0.0, [0, 0, 0, 0], 0, 0) + +def unitree_go_msg_dds__Req_(): + return Req_("", "") + +def unitree_go_msg_dds__Res_(): + return Res_("", [], "") + +def unitree_go_msg_dds__TimeSpec_(): + return TimeSpec_(0, 0) + +def unitree_go_msg_dds__PathPoint_(): + return PathPoint_(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) + +def unitree_go_msg_dds__SportModeState_(): + return SportModeState_(unitree_go_msg_dds__TimeSpec_(), 0, unitree_go_msg_dds__IMUState_(), + 0, 0, 0, 0.0, [0.0, 0.0, 0.0], 0.0, + [0.0, 0.0, 0.0], 0.0, [0.0, 0.0, 0.0, 0.0], [0, 0, 0, 0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], + [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],[unitree_go_msg_dds__PathPoint_() for i in range(10)]) + +def unitree_go_msg_dds__UwbState_(): + return UwbState_([0, 0], 0, 0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, [0.0, 0.0], 0, 0, 0) + +def unitree_go_msg_dds__UwbSwitch_(): + return UwbSwitch_(0) + +def unitree_go_msg_dds__WirelessController_(): + return WirelessController_(0.0, 0.0, 0.0, 0.0, 0) + + +""" +" unitree_hg.msg.dds_ dafault +""" +def unitree_hg_msg_dds__BmsCmd_(): + return HGBmsCmd_(0, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) + +def unitree_hg_msg_dds__BmsState_(): + return HGBmsState_(0, 0, 0, + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0], 0, 0, 0, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 0, 0, [0, 0, 0, 0, 0], [0, 0, 0]) + +def unitree_hg_msg_dds__IMUState_(): + return HGIMUState_([0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], 0) + +def unitree_hg_msg_dds__MotorCmd_(): + return HGMotorCmd_(0, 0.0, 0.0, 0.0, 0.0, 0.0, 0) + +def unitree_hg_msg_dds__MotorState_(): + return HGMotorState_(0, 0.0, 0.0, 0.0, 0.0, [0, 0], 0.0, [0, 0], 0, [0, 0, 0, 0]) + +def unitree_hg_msg_dds__MainBoardState_(): + return HGMainBoardState_([0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0, 0, 0, 0, 0, 0]) + +def unitree_hg_msg_dds__LowCmd_(): + return HGLowCmd_(0, 0, [unitree_hg_msg_dds__MotorCmd_() for i in range(35)], [0, 0, 0, 0], 0) + +def unitree_hg_msg_dds__LowState_(): + return HGLowState_([0, 0], 0, 0, 0, unitree_hg_msg_dds__IMUState_(), + [unitree_hg_msg_dds__MotorState_() for i in range(35)], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0], 0) + +def unitree_hg_msg_dds__PressSensorState_(): + return HGPressSensorState_([0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], + [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], 0, 0) + +def unitree_hg_msg_dds__HandCmd_(): + return HGHandCmd_([unitree_hg_msg_dds__MotorCmd_() for i in range(7)], [0, 0, 0, 0]) + +def unitree_hg_msg_dds__HandState_(): + return HGHandState_([unitree_hg_msg_dds__MotorState_() for i in range(7)], + [unitree_hg_msg_dds__PressSensorState_() for i in range(7)], + unitree_hg_msg_dds__IMUState_(), + 0.0, 0.0, 0.0, 0.0, [0, 0], [0, 0]) + + +""" +" unitree_api.msg.dds_ dafault +""" +def unitree_api_msg_dds__RequestIdentity_(): + return RequestIdentity_(0, 0) + +def unitree_api_msg_dds__RequestLease_(): + return RequestLease_(0, unitree_hg_msg_dds__IMUState_(), [], ) + +def unitree_api_msg_dds__RequestPolicy_(): + return RequestPolicy_(0, False) + +def unitree_api_msg_dds__RequestHeader_(): + return RequestHeader_(unitree_api_msg_dds__RequestIdentity_(), unitree_api_msg_dds__RequestLease_(), + unitree_api_msg_dds__RequestPolicy_()) + +def unitree_api_msg_dds__Request_(): + return Request_(unitree_api_msg_dds__RequestHeader_(), "", []) + +def unitree_api_msg_dds__ResponseStatus_(): + return ResponseStatus_(0) + +def unitree_api_msg_dds__ResponseHeader_(): + return ResponseHeader_(unitree_api_msg_dds__RequestIdentity_(), unitree_api_msg_dds__ResponseStatus_()) + +def unitree_api_msg_dds__Response_(): + return Response_(unitree_api_msg_dds__ResponseHeader_(), "", [], 0, 0, [0, 0]) + diff --git a/unitree_sdk2py/idl/geometry_msgs/__init__.py b/unitree_sdk2py/idl/geometry_msgs/__init__.py new file mode 100644 index 0000000..ab19108 --- /dev/null +++ b/unitree_sdk2py/idl/geometry_msgs/__init__.py @@ -0,0 +1,9 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: geometry_msgs + +""" + +from . import msg +__all__ = ["msg", ] diff --git a/unitree_sdk2py/idl/geometry_msgs/msg/__init__.py b/unitree_sdk2py/idl/geometry_msgs/msg/__init__.py new file mode 100644 index 0000000..7d10dec --- /dev/null +++ b/unitree_sdk2py/idl/geometry_msgs/msg/__init__.py @@ -0,0 +1,9 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: geometry_msgs.msg + +""" + +from . import dds_ +__all__ = ["dds_", ] diff --git a/unitree_sdk2py/idl/geometry_msgs/msg/dds_/_Point32_.py b/unitree_sdk2py/idl/geometry_msgs/msg/dds_/_Point32_.py new file mode 100644 index 0000000..34eefd4 --- /dev/null +++ b/unitree_sdk2py/idl/geometry_msgs/msg/dds_/_Point32_.py @@ -0,0 +1,29 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: geometry_msgs.msg.dds_ + IDL file: Point32_.idl + +""" + +from enum import auto +from typing import TYPE_CHECKING, Optional +from dataclasses import dataclass + +import cyclonedds.idl as idl +import cyclonedds.idl.annotations as annotate +import cyclonedds.idl.types as types + +# root module import for resolving types +# import geometry_msgs + + +@dataclass +@annotate.final +@annotate.autoid("sequential") +class Point32_(idl.IdlStruct, typename="geometry_msgs.msg.dds_.Point32_"): + x: types.float32 + y: types.float32 + z: types.float32 + + diff --git a/unitree_sdk2py/idl/geometry_msgs/msg/dds_/_PointStamped_.py b/unitree_sdk2py/idl/geometry_msgs/msg/dds_/_PointStamped_.py new file mode 100644 index 0000000..19de6ae --- /dev/null +++ b/unitree_sdk2py/idl/geometry_msgs/msg/dds_/_PointStamped_.py @@ -0,0 +1,31 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: geometry_msgs.msg.dds_ + IDL file: PointStamped_.idl + +""" + +from enum import auto +from typing import TYPE_CHECKING, Optional +from dataclasses import dataclass + +import cyclonedds.idl as idl +import cyclonedds.idl.annotations as annotate +import cyclonedds.idl.types as types + +# root module import for resolving types +# import geometry_msgs + +# if TYPE_CHECKING: +# import std_msgs.msg.dds_ + + +@dataclass +@annotate.final +@annotate.autoid("sequential") +class PointStamped_(idl.IdlStruct, typename="geometry_msgs.msg.dds_.PointStamped_"): + header: 'unitree_sdk2py.idl.std_msgs.msg.dds_.Header_' + point: 'unitree_sdk2py.idl.geometry_msgs.msg.dds_.Point_' + + diff --git a/unitree_sdk2py/idl/geometry_msgs/msg/dds_/_Point_.py b/unitree_sdk2py/idl/geometry_msgs/msg/dds_/_Point_.py new file mode 100644 index 0000000..efbc562 --- /dev/null +++ b/unitree_sdk2py/idl/geometry_msgs/msg/dds_/_Point_.py @@ -0,0 +1,29 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: geometry_msgs.msg.dds_ + IDL file: Point_.idl + +""" + +from enum import auto +from typing import TYPE_CHECKING, Optional +from dataclasses import dataclass + +import cyclonedds.idl as idl +import cyclonedds.idl.annotations as annotate +import cyclonedds.idl.types as types + +# root module import for resolving types +# import geometry_msgs + + +@dataclass +@annotate.final +@annotate.autoid("sequential") +class Point_(idl.IdlStruct, typename="geometry_msgs.msg.dds_.Point_"): + x: types.float64 + y: types.float64 + z: types.float64 + + diff --git a/unitree_sdk2py/idl/geometry_msgs/msg/dds_/_Pose2D_.py b/unitree_sdk2py/idl/geometry_msgs/msg/dds_/_Pose2D_.py new file mode 100644 index 0000000..c223370 --- /dev/null +++ b/unitree_sdk2py/idl/geometry_msgs/msg/dds_/_Pose2D_.py @@ -0,0 +1,29 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: geometry_msgs.msg.dds_ + IDL file: Pose2D_.idl + +""" + +from enum import auto +from typing import TYPE_CHECKING, Optional +from dataclasses import dataclass + +import cyclonedds.idl as idl +import cyclonedds.idl.annotations as annotate +import cyclonedds.idl.types as types + +# root module import for resolving types +# import geometry_msgs + + +@dataclass +@annotate.final +@annotate.autoid("sequential") +class Pose2D_(idl.IdlStruct, typename="geometry_msgs.msg.dds_.Pose2D_"): + x: types.float64 + y: types.float64 + theta: types.float64 + + diff --git a/unitree_sdk2py/idl/geometry_msgs/msg/dds_/_PoseStamped_.py b/unitree_sdk2py/idl/geometry_msgs/msg/dds_/_PoseStamped_.py new file mode 100644 index 0000000..7864bb0 --- /dev/null +++ b/unitree_sdk2py/idl/geometry_msgs/msg/dds_/_PoseStamped_.py @@ -0,0 +1,32 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: geometry_msgs.msg.dds_ + IDL file: PoseStamped_.idl + +""" + +from enum import auto +from typing import TYPE_CHECKING, Optional +from dataclasses import dataclass + +import cyclonedds.idl as idl +import cyclonedds.idl.annotations as annotate +import cyclonedds.idl.types as types + +# root module import for resolving types +# import geometry_msgs + +# if TYPE_CHECKING: +# import std_msgs.msg.dds_ + + + +@dataclass +@annotate.final +@annotate.autoid("sequential") +class PoseStamped_(idl.IdlStruct, typename="geometry_msgs.msg.dds_.PoseStamped_"): + header: 'unitree_sdk2py.idl.std_msgs.msg.dds_.Header_' + pose: 'unitree_sdk2py.idl.geometry_msgs.msg.dds_.Pose_' + + diff --git a/unitree_sdk2py/idl/geometry_msgs/msg/dds_/_PoseWithCovarianceStamped_.py b/unitree_sdk2py/idl/geometry_msgs/msg/dds_/_PoseWithCovarianceStamped_.py new file mode 100644 index 0000000..843d4c8 --- /dev/null +++ b/unitree_sdk2py/idl/geometry_msgs/msg/dds_/_PoseWithCovarianceStamped_.py @@ -0,0 +1,32 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: geometry_msgs.msg.dds_ + IDL file: PoseWithCovarianceStamped_.idl + +""" + +from enum import auto +from typing import TYPE_CHECKING, Optional +from dataclasses import dataclass + +import cyclonedds.idl as idl +import cyclonedds.idl.annotations as annotate +import cyclonedds.idl.types as types + +# root module import for resolving types +# import geometry_msgs + +# if TYPE_CHECKING: +# import std_msgs.msg.dds_ + + + +@dataclass +@annotate.final +@annotate.autoid("sequential") +class PoseWithCovarianceStamped_(idl.IdlStruct, typename="geometry_msgs.msg.dds_.PoseWithCovarianceStamped_"): + header: 'unitree_sdk2py.idl.std_msgs.msg.dds_.Header_' + pose: 'unitree_sdk2py.idl.geometry_msgs.msg.dds_.PoseWithCovariance_' + + diff --git a/unitree_sdk2py/idl/geometry_msgs/msg/dds_/_PoseWithCovariance_.py b/unitree_sdk2py/idl/geometry_msgs/msg/dds_/_PoseWithCovariance_.py new file mode 100644 index 0000000..bd75301 --- /dev/null +++ b/unitree_sdk2py/idl/geometry_msgs/msg/dds_/_PoseWithCovariance_.py @@ -0,0 +1,28 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: geometry_msgs.msg.dds_ + IDL file: PoseWithCovariance_.idl + +""" + +from enum import auto +from typing import TYPE_CHECKING, Optional +from dataclasses import dataclass + +import cyclonedds.idl as idl +import cyclonedds.idl.annotations as annotate +import cyclonedds.idl.types as types + +# root module import for resolving types +# import geometry_msgs + + +@dataclass +@annotate.final +@annotate.autoid("sequential") +class PoseWithCovariance_(idl.IdlStruct, typename="geometry_msgs.msg.dds_.PoseWithCovariance_"): + pose: 'unitree_sdk2py.idl.geometry_msgs.msg.dds_.Pose_' + covariance: types.array[types.float64, 36] + + diff --git a/unitree_sdk2py/idl/geometry_msgs/msg/dds_/_Pose_.py b/unitree_sdk2py/idl/geometry_msgs/msg/dds_/_Pose_.py new file mode 100644 index 0000000..2ea78d1 --- /dev/null +++ b/unitree_sdk2py/idl/geometry_msgs/msg/dds_/_Pose_.py @@ -0,0 +1,28 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: geometry_msgs.msg.dds_ + IDL file: Pose_.idl + +""" + +from enum import auto +from typing import TYPE_CHECKING, Optional +from dataclasses import dataclass + +import cyclonedds.idl as idl +import cyclonedds.idl.annotations as annotate +import cyclonedds.idl.types as types + +# root module import for resolving types +# import geometry_msgs + + +@dataclass +@annotate.final +@annotate.autoid("sequential") +class Pose_(idl.IdlStruct, typename="geometry_msgs.msg.dds_.Pose_"): + position: 'unitree_sdk2py.idl.geometry_msgs.msg.dds_.Point_' + orientation: 'unitree_sdk2py.idl.geometry_msgs.msg.dds_.Quaternion_' + + diff --git a/unitree_sdk2py/idl/geometry_msgs/msg/dds_/_QuaternionStamped_.py b/unitree_sdk2py/idl/geometry_msgs/msg/dds_/_QuaternionStamped_.py new file mode 100644 index 0000000..ae2b360 --- /dev/null +++ b/unitree_sdk2py/idl/geometry_msgs/msg/dds_/_QuaternionStamped_.py @@ -0,0 +1,32 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: geometry_msgs.msg.dds_ + IDL file: QuaternionStamped_.idl + +""" + +from enum import auto +from typing import TYPE_CHECKING, Optional +from dataclasses import dataclass + +import cyclonedds.idl as idl +import cyclonedds.idl.annotations as annotate +import cyclonedds.idl.types as types + +# root module import for resolving types +# import geometry_msgs + +# if TYPE_CHECKING: +# import std_msgs.msg.dds_ + + + +@dataclass +@annotate.final +@annotate.autoid("sequential") +class QuaternionStamped_(idl.IdlStruct, typename="geometry_msgs.msg.dds_.QuaternionStamped_"): + header: 'unitree_sdk2py.idl.std_msgs.msg.dds_.Header_' + quaternion: 'unitree_sdk2py.idl.geometry_msgs.msg.dds_.Quaternion_' + + diff --git a/unitree_sdk2py/idl/geometry_msgs/msg/dds_/_Quaternion_.py b/unitree_sdk2py/idl/geometry_msgs/msg/dds_/_Quaternion_.py new file mode 100644 index 0000000..0a401fb --- /dev/null +++ b/unitree_sdk2py/idl/geometry_msgs/msg/dds_/_Quaternion_.py @@ -0,0 +1,30 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: geometry_msgs.msg.dds_ + IDL file: Quaternion_.idl + +""" + +from enum import auto +from typing import TYPE_CHECKING, Optional +from dataclasses import dataclass + +import cyclonedds.idl as idl +import cyclonedds.idl.annotations as annotate +import cyclonedds.idl.types as types + +# root module import for resolving types +# import geometry_msgs + + +@dataclass +@annotate.final +@annotate.autoid("sequential") +class Quaternion_(idl.IdlStruct, typename="geometry_msgs.msg.dds_.Quaternion_"): + x: types.float64 + y: types.float64 + z: types.float64 + w: types.float64 + + diff --git a/unitree_sdk2py/idl/geometry_msgs/msg/dds_/_TwistStamped_.py b/unitree_sdk2py/idl/geometry_msgs/msg/dds_/_TwistStamped_.py new file mode 100644 index 0000000..97aa7c9 --- /dev/null +++ b/unitree_sdk2py/idl/geometry_msgs/msg/dds_/_TwistStamped_.py @@ -0,0 +1,32 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: geometry_msgs.msg.dds_ + IDL file: TwistStamped_.idl + +""" + +from enum import auto +from typing import TYPE_CHECKING, Optional +from dataclasses import dataclass + +import cyclonedds.idl as idl +import cyclonedds.idl.annotations as annotate +import cyclonedds.idl.types as types + +# root module import for resolving types +# import geometry_msgs + +# if TYPE_CHECKING: +# import std_msgs.msg.dds_ + + + +@dataclass +@annotate.final +@annotate.autoid("sequential") +class TwistStamped_(idl.IdlStruct, typename="geometry_msgs.msg.dds_.TwistStamped_"): + header: 'unitree_sdk2py.idl.std_msgs.msg.dds_.Header_' + twist: 'unitree_sdk2py.idl.geometry_msgs.msg.dds_.Twist_' + + diff --git a/unitree_sdk2py/idl/geometry_msgs/msg/dds_/_TwistWithCovarianceStamped_.py b/unitree_sdk2py/idl/geometry_msgs/msg/dds_/_TwistWithCovarianceStamped_.py new file mode 100644 index 0000000..d322b7f --- /dev/null +++ b/unitree_sdk2py/idl/geometry_msgs/msg/dds_/_TwistWithCovarianceStamped_.py @@ -0,0 +1,32 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: geometry_msgs.msg.dds_ + IDL file: TwistWithCovarianceStamped_.idl + +""" + +from enum import auto +from typing import TYPE_CHECKING, Optional +from dataclasses import dataclass + +import cyclonedds.idl as idl +import cyclonedds.idl.annotations as annotate +import cyclonedds.idl.types as types + +# root module import for resolving types +# import geometry_msgs + +# if TYPE_CHECKING: +# import std_msgs.msg.dds_ + + + +@dataclass +@annotate.final +@annotate.autoid("sequential") +class TwistWithCovarianceStamped_(idl.IdlStruct, typename="geometry_msgs.msg.dds_.TwistWithCovarianceStamped_"): + header: 'unitree_sdk2py.idl.std_msgs.msg.dds_.Header_' + twist: 'unitree_sdk2py.idl.geometry_msgs.msg.dds_.TwistWithCovariance_' + + diff --git a/unitree_sdk2py/idl/geometry_msgs/msg/dds_/_TwistWithCovariance_.py b/unitree_sdk2py/idl/geometry_msgs/msg/dds_/_TwistWithCovariance_.py new file mode 100644 index 0000000..7281bfc --- /dev/null +++ b/unitree_sdk2py/idl/geometry_msgs/msg/dds_/_TwistWithCovariance_.py @@ -0,0 +1,28 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: geometry_msgs.msg.dds_ + IDL file: TwistWithCovariance_.idl + +""" + +from enum import auto +from typing import TYPE_CHECKING, Optional +from dataclasses import dataclass + +import cyclonedds.idl as idl +import cyclonedds.idl.annotations as annotate +import cyclonedds.idl.types as types + +# root module import for resolving types +# import geometry_msgs + + +@dataclass +@annotate.final +@annotate.autoid("sequential") +class TwistWithCovariance_(idl.IdlStruct, typename="geometry_msgs.msg.dds_.TwistWithCovariance_"): + twist: 'unitree_sdk2py.idl.geometry_msgs.msg.dds_.Twist_' + covariance: types.array[types.float64, 36] + + diff --git a/unitree_sdk2py/idl/geometry_msgs/msg/dds_/_Twist_.py b/unitree_sdk2py/idl/geometry_msgs/msg/dds_/_Twist_.py new file mode 100644 index 0000000..5cd3b23 --- /dev/null +++ b/unitree_sdk2py/idl/geometry_msgs/msg/dds_/_Twist_.py @@ -0,0 +1,28 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: geometry_msgs.msg.dds_ + IDL file: Twist_.idl + +""" + +from enum import auto +from typing import TYPE_CHECKING, Optional +from dataclasses import dataclass + +import cyclonedds.idl as idl +import cyclonedds.idl.annotations as annotate +import cyclonedds.idl.types as types + +# root module import for resolving types +# import geometry_msgs + + +@dataclass +@annotate.final +@annotate.autoid("sequential") +class Twist_(idl.IdlStruct, typename="geometry_msgs.msg.dds_.Twist_"): + linear: 'unitree_sdk2py.idl.geometry_msgs.msg.dds_.Vector3_' + angular: 'unitree_sdk2py.idl.geometry_msgs.msg.dds_.Vector3_' + + diff --git a/unitree_sdk2py/idl/geometry_msgs/msg/dds_/_Vector3_.py b/unitree_sdk2py/idl/geometry_msgs/msg/dds_/_Vector3_.py new file mode 100644 index 0000000..9cdeb0f --- /dev/null +++ b/unitree_sdk2py/idl/geometry_msgs/msg/dds_/_Vector3_.py @@ -0,0 +1,29 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: geometry_msgs.msg.dds_ + IDL file: Vector3_.idl + +""" + +from enum import auto +from typing import TYPE_CHECKING, Optional +from dataclasses import dataclass + +import cyclonedds.idl as idl +import cyclonedds.idl.annotations as annotate +import cyclonedds.idl.types as types + +# root module import for resolving types +# import geometry_msgs + + +@dataclass +@annotate.final +@annotate.autoid("sequential") +class Vector3_(idl.IdlStruct, typename="geometry_msgs.msg.dds_.Vector3_"): + x: types.float64 + y: types.float64 + z: types.float64 + + diff --git a/unitree_sdk2py/idl/geometry_msgs/msg/dds_/__init__.py b/unitree_sdk2py/idl/geometry_msgs/msg/dds_/__init__.py new file mode 100644 index 0000000..68c4fe2 --- /dev/null +++ b/unitree_sdk2py/idl/geometry_msgs/msg/dds_/__init__.py @@ -0,0 +1,23 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: geometry_msgs.msg.dds_ + +""" + +from ._Point32_ import Point32_ +from ._Point_ import Point_ +from ._PointStamped_ import PointStamped_ +from ._Pose2D_ import Pose2D_ +from ._Pose_ import Pose_ +from ._PoseStamped_ import PoseStamped_ +from ._PoseWithCovariance_ import PoseWithCovariance_ +from ._PoseWithCovarianceStamped_ import PoseWithCovarianceStamped_ +from ._Quaternion_ import Quaternion_ +from ._QuaternionStamped_ import QuaternionStamped_ +from ._Twist_ import Twist_ +from ._TwistStamped_ import TwistStamped_ +from ._TwistWithCovariance_ import TwistWithCovariance_ +from ._TwistWithCovarianceStamped_ import TwistWithCovarianceStamped_ +from ._Vector3_ import Vector3_ +__all__ = ["Point32_", "Point_", "PointStamped_", "Pose2D_", "Pose_", "PoseStamped_", "PoseWithCovariance_", "PoseWithCovarianceStamped_", "Quaternion_", "QuaternionStamped_", "Twist_", "TwistStamped_", "TwistWithCovariance_", "TwistWithCovarianceStamped_", "Vector3_", ] diff --git a/unitree_sdk2py/idl/nav_msgs/__init__.py b/unitree_sdk2py/idl/nav_msgs/__init__.py new file mode 100644 index 0000000..a2724c2 --- /dev/null +++ b/unitree_sdk2py/idl/nav_msgs/__init__.py @@ -0,0 +1,9 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: nav_msgs + +""" + +from . import msg +__all__ = ["msg", ] diff --git a/unitree_sdk2py/idl/nav_msgs/msg/__init__.py b/unitree_sdk2py/idl/nav_msgs/msg/__init__.py new file mode 100644 index 0000000..d47683b --- /dev/null +++ b/unitree_sdk2py/idl/nav_msgs/msg/__init__.py @@ -0,0 +1,9 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: nav_msgs.msg + +""" + +from . import dds_ +__all__ = ["dds_", ] diff --git a/unitree_sdk2py/idl/nav_msgs/msg/dds_/_MapMetaData_.py b/unitree_sdk2py/idl/nav_msgs/msg/dds_/_MapMetaData_.py new file mode 100644 index 0000000..9228cd6 --- /dev/null +++ b/unitree_sdk2py/idl/nav_msgs/msg/dds_/_MapMetaData_.py @@ -0,0 +1,35 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: nav_msgs.msg.dds_ + IDL file: MapMetaData_.idl + +""" + +from enum import auto +from typing import TYPE_CHECKING, Optional +from dataclasses import dataclass + +import cyclonedds.idl as idl +import cyclonedds.idl.annotations as annotate +import cyclonedds.idl.types as types + +# root module import for resolving types +# import nav_msgs + +# if TYPE_CHECKING: +# import builtin_interfaces.msg.dds_ +# import geometry_msgs.msg.dds_ + + + +@dataclass +@annotate.final +@annotate.autoid("sequential") +class MapMetaData_(idl.IdlStruct, typename="nav_msgs.msg.dds_.MapMetaData_"): + map_load_time: 'unitree_sdk2py.idl.builtin_interfaces.msg.dds_.Time_' + resolution: types.float32 + width: types.uint32 + height: types.uint32 + origin: 'unitree_sdk2py.idl.geometry_msgs.msg.dds_.Pose_' + diff --git a/unitree_sdk2py/idl/nav_msgs/msg/dds_/_OccupancyGrid_.py b/unitree_sdk2py/idl/nav_msgs/msg/dds_/_OccupancyGrid_.py new file mode 100644 index 0000000..0274c58 --- /dev/null +++ b/unitree_sdk2py/idl/nav_msgs/msg/dds_/_OccupancyGrid_.py @@ -0,0 +1,33 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: nav_msgs.msg.dds_ + IDL file: OccupancyGrid_.idl + +""" + +from enum import auto +from typing import TYPE_CHECKING, Optional +from dataclasses import dataclass + +import cyclonedds.idl as idl +import cyclonedds.idl.annotations as annotate +import cyclonedds.idl.types as types + +# root module import for resolving types +# import nav_msgs + +# if TYPE_CHECKING: +# import std_msgs.msg.dds_ + + + +@dataclass +@annotate.final +@annotate.autoid("sequential") +class OccupancyGrid_(idl.IdlStruct, typename="nav_msgs.msg.dds_.OccupancyGrid_"): + header: 'unitree_sdk2py.idl.std_msgs.msg.dds_.Header_' + info: 'unitree_sdk2py.idl.nav_msgs.msg.dds_.MapMetaData_' + data: types.sequence[types.uint8] + + diff --git a/unitree_sdk2py/idl/nav_msgs/msg/dds_/_Odometry_.py b/unitree_sdk2py/idl/nav_msgs/msg/dds_/_Odometry_.py new file mode 100644 index 0000000..054bb5c --- /dev/null +++ b/unitree_sdk2py/idl/nav_msgs/msg/dds_/_Odometry_.py @@ -0,0 +1,35 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: nav_msgs.msg.dds_ + IDL file: Odometry_.idl + +""" + +from enum import auto +from typing import TYPE_CHECKING, Optional +from dataclasses import dataclass + +import cyclonedds.idl as idl +import cyclonedds.idl.annotations as annotate +import cyclonedds.idl.types as types + +# root module import for resolving types +# import nav_msgs + +# if TYPE_CHECKING: +# import geometry_msgs.msg.dds_ +# import std_msgs.msg.dds_ + + + +@dataclass +@annotate.final +@annotate.autoid("sequential") +class Odometry_(idl.IdlStruct, typename="nav_msgs.msg.dds_.Odometry_"): + header: 'unitree_sdk2py.idl.std_msgs.msg.dds_.Header_' + child_frame_id: str + pose: 'unitree_sdk2py.idl.geometry_msgs.msg.dds_.PoseWithCovariance_' + twist: 'unitree_sdk2py.idl.geometry_msgs.msg.dds_.TwistWithCovariance_' + + diff --git a/unitree_sdk2py/idl/nav_msgs/msg/dds_/__init__.py b/unitree_sdk2py/idl/nav_msgs/msg/dds_/__init__.py new file mode 100644 index 0000000..a14e17a --- /dev/null +++ b/unitree_sdk2py/idl/nav_msgs/msg/dds_/__init__.py @@ -0,0 +1,11 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: nav_msgs.msg.dds_ + +""" + +from ._MapMetaData_ import MapMetaData_ +from ._OccupancyGrid_ import OccupancyGrid_ +from ._Odometry_ import Odometry_ +__all__ = ["MapMetaData_", "OccupancyGrid_", "Odometry_", ] diff --git a/unitree_sdk2py/idl/sensor_msgs/__init__.py b/unitree_sdk2py/idl/sensor_msgs/__init__.py new file mode 100644 index 0000000..984e7e2 --- /dev/null +++ b/unitree_sdk2py/idl/sensor_msgs/__init__.py @@ -0,0 +1,9 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: sensor_msgs + +""" + +from . import msg +__all__ = ["msg", ] diff --git a/unitree_sdk2py/idl/sensor_msgs/msg/__init__.py b/unitree_sdk2py/idl/sensor_msgs/msg/__init__.py new file mode 100644 index 0000000..62a2292 --- /dev/null +++ b/unitree_sdk2py/idl/sensor_msgs/msg/__init__.py @@ -0,0 +1,9 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: sensor_msgs.msg + +""" + +from . import dds_ +__all__ = ["dds_", ] diff --git a/unitree_sdk2py/idl/sensor_msgs/msg/dds_/PointField_Constants/_PointField_.py b/unitree_sdk2py/idl/sensor_msgs/msg/dds_/PointField_Constants/_PointField_.py new file mode 100644 index 0000000..673aa84 --- /dev/null +++ b/unitree_sdk2py/idl/sensor_msgs/msg/dds_/PointField_Constants/_PointField_.py @@ -0,0 +1,28 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: sensor_msgs.msg.dds_.PointField_Constants + IDL file: PointField_.idl + +""" + +from enum import auto +from typing import TYPE_CHECKING, Optional +from dataclasses import dataclass + +import cyclonedds.idl as idl +import cyclonedds.idl.annotations as annotate +import cyclonedds.idl.types as types + +# root module import for resolving types +# import sensor_msgs + +INT8_ = 1 +UINT8_ = 2 +INT16_ = 3 +UINT16_ = 4 +INT32_ = 5 +UINT32_ = 6 +FLOAT32_ = 7 +FLOAT64_ = 8 + diff --git a/unitree_sdk2py/idl/sensor_msgs/msg/dds_/PointField_Constants/__init__.py b/unitree_sdk2py/idl/sensor_msgs/msg/dds_/PointField_Constants/__init__.py new file mode 100644 index 0000000..310fecd --- /dev/null +++ b/unitree_sdk2py/idl/sensor_msgs/msg/dds_/PointField_Constants/__init__.py @@ -0,0 +1,9 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: sensor_msgs.msg.dds_.PointField_Constants + +""" + +from ._PointField_ import FLOAT32_, FLOAT64_, INT16_, INT32_, INT8_, UINT16_, UINT32_, UINT8_ +__all__ = ["FLOAT32_", "FLOAT64_", "INT16_", "INT32_", "INT8_", "UINT16_", "UINT32_", "UINT8_", ] diff --git a/unitree_sdk2py/idl/sensor_msgs/msg/dds_/_PointCloud2_.py b/unitree_sdk2py/idl/sensor_msgs/msg/dds_/_PointCloud2_.py new file mode 100644 index 0000000..ffdf713 --- /dev/null +++ b/unitree_sdk2py/idl/sensor_msgs/msg/dds_/_PointCloud2_.py @@ -0,0 +1,39 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: sensor_msgs.msg.dds_ + IDL file: PointCloud2_.idl + +""" + +from enum import auto +from typing import TYPE_CHECKING, Optional +from dataclasses import dataclass + +import cyclonedds.idl as idl +import cyclonedds.idl.annotations as annotate +import cyclonedds.idl.types as types + +# root module import for resolving types +# import sensor_msgs + +# if TYPE_CHECKING: +# import std_msgs.msg.dds_ + + + +@dataclass +@annotate.final +@annotate.autoid("sequential") +class PointCloud2_(idl.IdlStruct, typename="sensor_msgs.msg.dds_.PointCloud2_"): + header: 'unitree_sdk2py.idl.std_msgs.msg.dds_.Header_' + height: types.uint32 + width: types.uint32 + fields: types.sequence['unitree_sdk2py.idl.sensor_msgs.msg.dds_.PointField_'] + is_bigendian: bool + point_step: types.uint32 + row_step: types.uint32 + data: types.sequence[types.uint8] + is_dense: bool + + diff --git a/unitree_sdk2py/idl/sensor_msgs/msg/dds_/_PointField_.py b/unitree_sdk2py/idl/sensor_msgs/msg/dds_/_PointField_.py new file mode 100644 index 0000000..e62dbf9 --- /dev/null +++ b/unitree_sdk2py/idl/sensor_msgs/msg/dds_/_PointField_.py @@ -0,0 +1,30 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: sensor_msgs.msg.dds_ + IDL file: PointField_.idl + +""" + +from enum import auto +from typing import TYPE_CHECKING, Optional +from dataclasses import dataclass + +import cyclonedds.idl as idl +import cyclonedds.idl.annotations as annotate +import cyclonedds.idl.types as types + +# root module import for resolving types +# import sensor_msgs + + +@dataclass +@annotate.final +@annotate.autoid("sequential") +class PointField_(idl.IdlStruct, typename="sensor_msgs.msg.dds_.PointField_"): + name: str + offset: types.uint32 + datatype: types.uint8 + count: types.uint32 + + diff --git a/unitree_sdk2py/idl/sensor_msgs/msg/dds_/__init__.py b/unitree_sdk2py/idl/sensor_msgs/msg/dds_/__init__.py new file mode 100644 index 0000000..68e0141 --- /dev/null +++ b/unitree_sdk2py/idl/sensor_msgs/msg/dds_/__init__.py @@ -0,0 +1,11 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: sensor_msgs.msg.dds_ + +""" + +from . import PointField_Constants +from ._PointCloud2_ import PointCloud2_ +from ._PointField_ import PointField_ +__all__ = ["PointField_Constants", "PointCloud2_", "PointField_", ] diff --git a/unitree_sdk2py/idl/std_msgs/__init__.py b/unitree_sdk2py/idl/std_msgs/__init__.py new file mode 100644 index 0000000..c17a705 --- /dev/null +++ b/unitree_sdk2py/idl/std_msgs/__init__.py @@ -0,0 +1,9 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: std_msgs + +""" + +from . import msg +__all__ = ["msg", ] diff --git a/unitree_sdk2py/idl/std_msgs/msg/__init__.py b/unitree_sdk2py/idl/std_msgs/msg/__init__.py new file mode 100644 index 0000000..02c8fe3 --- /dev/null +++ b/unitree_sdk2py/idl/std_msgs/msg/__init__.py @@ -0,0 +1,9 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: std_msgs.msg + +""" + +from . import dds_ +__all__ = ["dds_", ] diff --git a/unitree_sdk2py/idl/std_msgs/msg/dds_/_Header_.py b/unitree_sdk2py/idl/std_msgs/msg/dds_/_Header_.py new file mode 100644 index 0000000..bd3564f --- /dev/null +++ b/unitree_sdk2py/idl/std_msgs/msg/dds_/_Header_.py @@ -0,0 +1,32 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: std_msgs.msg.dds_ + IDL file: Header_.idl + +""" + +from enum import auto +from typing import TYPE_CHECKING, Optional +from dataclasses import dataclass + +import cyclonedds.idl as idl +import cyclonedds.idl.annotations as annotate +import cyclonedds.idl.types as types + +# root module import for resolving types +# import std_msgs + +# if TYPE_CHECKING: +# import builtin_interfaces.msg.dds_ + + + +@dataclass +@annotate.final +@annotate.autoid("sequential") +class Header_(idl.IdlStruct, typename="std_msgs.msg.dds_.Header_"): + stamp: 'unitree_sdk2py.idl.builtin_interfaces.msg.dds_.Time_' + frame_id: str + + diff --git a/unitree_sdk2py/idl/std_msgs/msg/dds_/_String_.py b/unitree_sdk2py/idl/std_msgs/msg/dds_/_String_.py new file mode 100644 index 0000000..052f122 --- /dev/null +++ b/unitree_sdk2py/idl/std_msgs/msg/dds_/_String_.py @@ -0,0 +1,27 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: std_msgs.msg.dds_ + IDL file: String_.idl + +""" + +from enum import auto +from typing import TYPE_CHECKING, Optional +from dataclasses import dataclass + +import cyclonedds.idl as idl +import cyclonedds.idl.annotations as annotate +import cyclonedds.idl.types as types + +# root module import for resolving types +# import std_msgs + + +@dataclass +@annotate.final +@annotate.autoid("sequential") +class String_(idl.IdlStruct, typename="std_msgs.msg.dds_.String_"): + data: str + + diff --git a/unitree_sdk2py/idl/std_msgs/msg/dds_/__init__.py b/unitree_sdk2py/idl/std_msgs/msg/dds_/__init__.py new file mode 100644 index 0000000..f5282e5 --- /dev/null +++ b/unitree_sdk2py/idl/std_msgs/msg/dds_/__init__.py @@ -0,0 +1,10 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: std_msgs.msg.dds_ + +""" + +from ._Header_ import Header_ +from ._String_ import String_ +__all__ = ["Header_", "String_", ] diff --git a/unitree_sdk2py/idl/unitree_api/__init__.py b/unitree_sdk2py/idl/unitree_api/__init__.py new file mode 100644 index 0000000..e6546ff --- /dev/null +++ b/unitree_sdk2py/idl/unitree_api/__init__.py @@ -0,0 +1,9 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.10.2 + Module: unitree_api + +""" + +from . import msg +__all__ = ["msg", ] diff --git a/unitree_sdk2py/idl/unitree_api/msg/__init__.py b/unitree_sdk2py/idl/unitree_api/msg/__init__.py new file mode 100644 index 0000000..bbf9fde --- /dev/null +++ b/unitree_sdk2py/idl/unitree_api/msg/__init__.py @@ -0,0 +1,9 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.10.2 + Module: unitree_api.msg + +""" + +from . import dds_ +__all__ = ["dds_", ] diff --git a/unitree_sdk2py/idl/unitree_api/msg/dds_/_RequestHeader_.py b/unitree_sdk2py/idl/unitree_api/msg/dds_/_RequestHeader_.py new file mode 100644 index 0000000..57d67a0 --- /dev/null +++ b/unitree_sdk2py/idl/unitree_api/msg/dds_/_RequestHeader_.py @@ -0,0 +1,29 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.10.2 + Module: unitree_api.msg.dds_ + IDL file: RequestHeader_.idl + +""" + +from enum import auto +from typing import TYPE_CHECKING, Optional +from dataclasses import dataclass + +import cyclonedds.idl as idl +import cyclonedds.idl.annotations as annotate +import cyclonedds.idl.types as types + +# root module import for resolving types +# import unitree_api + + +@dataclass +@annotate.final +@annotate.autoid("sequential") +class RequestHeader_(idl.IdlStruct, typename="unitree_api.msg.dds_.RequestHeader_"): + identity: 'unitree_sdk2py.idl.unitree_api.msg.dds_.RequestIdentity_' + lease: 'unitree_sdk2py.idl.unitree_api.msg.dds_.RequestLease_' + policy: 'unitree_sdk2py.idl.unitree_api.msg.dds_.RequestPolicy_' + + diff --git a/unitree_sdk2py/idl/unitree_api/msg/dds_/_RequestIdentity_.py b/unitree_sdk2py/idl/unitree_api/msg/dds_/_RequestIdentity_.py new file mode 100644 index 0000000..a891b54 --- /dev/null +++ b/unitree_sdk2py/idl/unitree_api/msg/dds_/_RequestIdentity_.py @@ -0,0 +1,28 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.10.2 + Module: unitree_api.msg.dds_ + IDL file: RequestIdentity_.idl + +""" + +from enum import auto +from typing import TYPE_CHECKING, Optional +from dataclasses import dataclass + +import cyclonedds.idl as idl +import cyclonedds.idl.annotations as annotate +import cyclonedds.idl.types as types + +# root module import for resolving types +# import unitree_api + + +@dataclass +@annotate.final +@annotate.autoid("sequential") +class RequestIdentity_(idl.IdlStruct, typename="unitree_api.msg.dds_.RequestIdentity_"): + id: types.int64 + api_id: types.int64 + + diff --git a/unitree_sdk2py/idl/unitree_api/msg/dds_/_RequestLease_.py b/unitree_sdk2py/idl/unitree_api/msg/dds_/_RequestLease_.py new file mode 100644 index 0000000..32cef0f --- /dev/null +++ b/unitree_sdk2py/idl/unitree_api/msg/dds_/_RequestLease_.py @@ -0,0 +1,27 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.10.2 + Module: unitree_api.msg.dds_ + IDL file: RequestLease_.idl + +""" + +from enum import auto +from typing import TYPE_CHECKING, Optional +from dataclasses import dataclass + +import cyclonedds.idl as idl +import cyclonedds.idl.annotations as annotate +import cyclonedds.idl.types as types + +# root module import for resolving types +# import unitree_api + + +@dataclass +@annotate.final +@annotate.autoid("sequential") +class RequestLease_(idl.IdlStruct, typename="unitree_api.msg.dds_.RequestLease_"): + id: types.int64 + + diff --git a/unitree_sdk2py/idl/unitree_api/msg/dds_/_RequestPolicy_.py b/unitree_sdk2py/idl/unitree_api/msg/dds_/_RequestPolicy_.py new file mode 100644 index 0000000..aa7ef2f --- /dev/null +++ b/unitree_sdk2py/idl/unitree_api/msg/dds_/_RequestPolicy_.py @@ -0,0 +1,28 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.10.2 + Module: unitree_api.msg.dds_ + IDL file: RequestPolicy_.idl + +""" + +from enum import auto +from typing import TYPE_CHECKING, Optional +from dataclasses import dataclass + +import cyclonedds.idl as idl +import cyclonedds.idl.annotations as annotate +import cyclonedds.idl.types as types + +# root module import for resolving types +# import unitree_api + + +@dataclass +@annotate.final +@annotate.autoid("sequential") +class RequestPolicy_(idl.IdlStruct, typename="unitree_api.msg.dds_.RequestPolicy_"): + priority: types.int32 + noreply: bool + + diff --git a/unitree_sdk2py/idl/unitree_api/msg/dds_/_Request_.py b/unitree_sdk2py/idl/unitree_api/msg/dds_/_Request_.py new file mode 100644 index 0000000..39c6b43 --- /dev/null +++ b/unitree_sdk2py/idl/unitree_api/msg/dds_/_Request_.py @@ -0,0 +1,28 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.10.2 + Module: unitree_api.msg.dds_ + IDL file: Request_.idl + +""" + +from enum import auto +from typing import TYPE_CHECKING, Optional +from dataclasses import dataclass + +import cyclonedds.idl as idl +import cyclonedds.idl.annotations as annotate +import cyclonedds.idl.types as types + +# root module import for resolving types +# import unitree_api + + +@dataclass +@annotate.final +@annotate.autoid("sequential") +class Request_(idl.IdlStruct, typename="unitree_api.msg.dds_.Request_"): + header: 'unitree_sdk2py.idl.unitree_api.msg.dds_.RequestHeader_' + parameter: str + binary: types.sequence[types.uint8] + diff --git a/unitree_sdk2py/idl/unitree_api/msg/dds_/_ResponseHeader_.py b/unitree_sdk2py/idl/unitree_api/msg/dds_/_ResponseHeader_.py new file mode 100644 index 0000000..ef47340 --- /dev/null +++ b/unitree_sdk2py/idl/unitree_api/msg/dds_/_ResponseHeader_.py @@ -0,0 +1,28 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.10.2 + Module: unitree_api.msg.dds_ + IDL file: ResponseHeader_.idl + +""" + +from enum import auto +from typing import TYPE_CHECKING, Optional +from dataclasses import dataclass + +import cyclonedds.idl as idl +import cyclonedds.idl.annotations as annotate +import cyclonedds.idl.types as types + +# root module import for resolving types +# import unitree_api + + +@dataclass +@annotate.final +@annotate.autoid("sequential") +class ResponseHeader_(idl.IdlStruct, typename="unitree_api.msg.dds_.ResponseHeader_"): + identity: 'unitree_sdk2py.idl.unitree_api.msg.dds_.RequestIdentity_' + status: 'unitree_sdk2py.idl.unitree_api.msg.dds_.ResponseStatus_' + + diff --git a/unitree_sdk2py/idl/unitree_api/msg/dds_/_ResponseStatus_.py b/unitree_sdk2py/idl/unitree_api/msg/dds_/_ResponseStatus_.py new file mode 100644 index 0000000..92c0b1b --- /dev/null +++ b/unitree_sdk2py/idl/unitree_api/msg/dds_/_ResponseStatus_.py @@ -0,0 +1,27 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.10.2 + Module: unitree_api.msg.dds_ + IDL file: ResponseStatus_.idl + +""" + +from enum import auto +from typing import TYPE_CHECKING, Optional +from dataclasses import dataclass + +import cyclonedds.idl as idl +import cyclonedds.idl.annotations as annotate +import cyclonedds.idl.types as types + +# root module import for resolving types +# import unitree_api + + +@dataclass +@annotate.final +@annotate.autoid("sequential") +class ResponseStatus_(idl.IdlStruct, typename="unitree_api.msg.dds_.ResponseStatus_"): + code: types.int32 + + diff --git a/unitree_sdk2py/idl/unitree_api/msg/dds_/_Response_.py b/unitree_sdk2py/idl/unitree_api/msg/dds_/_Response_.py new file mode 100644 index 0000000..c743651 --- /dev/null +++ b/unitree_sdk2py/idl/unitree_api/msg/dds_/_Response_.py @@ -0,0 +1,28 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.10.2 + Module: unitree_api.msg.dds_ + IDL file: Response_.idl + +""" + +from enum import auto +from typing import TYPE_CHECKING, Optional +from dataclasses import dataclass + +import cyclonedds.idl as idl +import cyclonedds.idl.annotations as annotate +import cyclonedds.idl.types as types + +# root module import for resolving types +# import unitree_api + +@dataclass +@annotate.final +@annotate.autoid("sequential") +class Response_(idl.IdlStruct, typename="unitree_api.msg.dds_.Response_"): + header: 'unitree_sdk2py.idl.unitree_api.msg.dds_.ResponseHeader_' + data: str + binary: types.sequence[types.uint8] + + diff --git a/unitree_sdk2py/idl/unitree_api/msg/dds_/__init__.py b/unitree_sdk2py/idl/unitree_api/msg/dds_/__init__.py new file mode 100644 index 0000000..1e4c9f8 --- /dev/null +++ b/unitree_sdk2py/idl/unitree_api/msg/dds_/__init__.py @@ -0,0 +1,16 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.10.2 + Module: unitree_api.msg.dds_ + +""" + +from ._RequestHeader_ import RequestHeader_ +from ._RequestIdentity_ import RequestIdentity_ +from ._RequestLease_ import RequestLease_ +from ._RequestPolicy_ import RequestPolicy_ +from ._Request_ import Request_ +from ._ResponseHeader_ import ResponseHeader_ +from ._ResponseStatus_ import ResponseStatus_ +from ._Response_ import Response_ +__all__ = ["RequestHeader_", "RequestIdentity_", "RequestLease_", "RequestPolicy_", "Request_", "ResponseHeader_", "ResponseStatus_", "Response_", ] diff --git a/unitree_sdk2py/idl/unitree_go/__init__.py b/unitree_sdk2py/idl/unitree_go/__init__.py new file mode 100644 index 0000000..b553006 --- /dev/null +++ b/unitree_sdk2py/idl/unitree_go/__init__.py @@ -0,0 +1,9 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: unitree_go + +""" + +from . import msg +__all__ = ["msg", ] diff --git a/unitree_sdk2py/idl/unitree_go/msg/__init__.py b/unitree_sdk2py/idl/unitree_go/msg/__init__.py new file mode 100644 index 0000000..f8cae9b --- /dev/null +++ b/unitree_sdk2py/idl/unitree_go/msg/__init__.py @@ -0,0 +1,9 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: unitree_go.msg + +""" + +from . import dds_ +__all__ = ["dds_", ] diff --git a/unitree_sdk2py/idl/unitree_go/msg/dds_/_AudioData_.py b/unitree_sdk2py/idl/unitree_go/msg/dds_/_AudioData_.py new file mode 100644 index 0000000..27913c9 --- /dev/null +++ b/unitree_sdk2py/idl/unitree_go/msg/dds_/_AudioData_.py @@ -0,0 +1,28 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: unitree_go.msg.dds_ + IDL file: AudioData_.idl + +""" + +from enum import auto +from typing import TYPE_CHECKING, Optional +from dataclasses import dataclass + +import cyclonedds.idl as idl +import cyclonedds.idl.annotations as annotate +import cyclonedds.idl.types as types + +# root module import for resolving types +# import unitree_go + + +@dataclass +@annotate.final +@annotate.autoid("sequential") +class AudioData_(idl.IdlStruct, typename="unitree_go.msg.dds_.AudioData_"): + time_frame: types.uint64 + data: types.sequence[types.uint8] + + diff --git a/unitree_sdk2py/idl/unitree_go/msg/dds_/_BmsCmd_.py b/unitree_sdk2py/idl/unitree_go/msg/dds_/_BmsCmd_.py new file mode 100644 index 0000000..5da647e --- /dev/null +++ b/unitree_sdk2py/idl/unitree_go/msg/dds_/_BmsCmd_.py @@ -0,0 +1,28 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: unitree_go.msg.dds_ + IDL file: BmsCmd_.idl + +""" + +from enum import auto +from typing import TYPE_CHECKING, Optional +from dataclasses import dataclass + +import cyclonedds.idl as idl +import cyclonedds.idl.annotations as annotate +import cyclonedds.idl.types as types + +# root module import for resolving types +# import unitree_go + + +@dataclass +@annotate.final +@annotate.autoid("sequential") +class BmsCmd_(idl.IdlStruct, typename="unitree_go.msg.dds_.BmsCmd_"): + off: types.uint8 + reserve: types.array[types.uint8, 3] + + diff --git a/unitree_sdk2py/idl/unitree_go/msg/dds_/_BmsState_.py b/unitree_sdk2py/idl/unitree_go/msg/dds_/_BmsState_.py new file mode 100644 index 0000000..af635e8 --- /dev/null +++ b/unitree_sdk2py/idl/unitree_go/msg/dds_/_BmsState_.py @@ -0,0 +1,35 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: unitree_go.msg.dds_ + IDL file: BmsState_.idl + +""" + +from enum import auto +from typing import TYPE_CHECKING, Optional +from dataclasses import dataclass + +import cyclonedds.idl as idl +import cyclonedds.idl.annotations as annotate +import cyclonedds.idl.types as types + +# root module import for resolving types +# import unitree_go + + +@dataclass +@annotate.final +@annotate.autoid("sequential") +class BmsState_(idl.IdlStruct, typename="unitree_go.msg.dds_.BmsState_"): + version_high: types.uint8 + version_low: types.uint8 + status: types.uint8 + soc: types.uint8 + current: types.int32 + cycle: types.uint16 + bq_ntc: types.array[types.uint8, 2] + mcu_ntc: types.array[types.uint8, 2] + cell_vol: types.array[types.uint16, 15] + + diff --git a/unitree_sdk2py/idl/unitree_go/msg/dds_/_Error_.py b/unitree_sdk2py/idl/unitree_go/msg/dds_/_Error_.py new file mode 100644 index 0000000..c338c69 --- /dev/null +++ b/unitree_sdk2py/idl/unitree_go/msg/dds_/_Error_.py @@ -0,0 +1,28 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: unitree_go.msg.dds_ + IDL file: Error_.idl + +""" + +from enum import auto +from typing import TYPE_CHECKING, Optional +from dataclasses import dataclass + +import cyclonedds.idl as idl +import cyclonedds.idl.annotations as annotate +import cyclonedds.idl.types as types + +# root module import for resolving types +# import unitree_go + + +@dataclass +@annotate.final +@annotate.autoid("sequential") +class Error_(idl.IdlStruct, typename="unitree_go.msg.dds_.Error_"): + source: types.uint32 + state: types.uint32 + + diff --git a/unitree_sdk2py/idl/unitree_go/msg/dds_/_Go2FrontVideoData_.py b/unitree_sdk2py/idl/unitree_go/msg/dds_/_Go2FrontVideoData_.py new file mode 100644 index 0000000..04d245b --- /dev/null +++ b/unitree_sdk2py/idl/unitree_go/msg/dds_/_Go2FrontVideoData_.py @@ -0,0 +1,30 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: unitree_go.msg.dds_ + IDL file: Go2FrontVideoData_.idl + +""" + +from enum import auto +from typing import TYPE_CHECKING, Optional +from dataclasses import dataclass + +import cyclonedds.idl as idl +import cyclonedds.idl.annotations as annotate +import cyclonedds.idl.types as types + +# root module import for resolving types +# import unitree_go + + +@dataclass +@annotate.final +@annotate.autoid("sequential") +class Go2FrontVideoData_(idl.IdlStruct, typename="unitree_go.msg.dds_.Go2FrontVideoData_"): + time_frame: types.uint64 + video720p: types.sequence[types.uint8] + video360p: types.sequence[types.uint8] + video180p: types.sequence[types.uint8] + + diff --git a/unitree_sdk2py/idl/unitree_go/msg/dds_/_HeightMap_.py b/unitree_sdk2py/idl/unitree_go/msg/dds_/_HeightMap_.py new file mode 100644 index 0000000..48168da --- /dev/null +++ b/unitree_sdk2py/idl/unitree_go/msg/dds_/_HeightMap_.py @@ -0,0 +1,33 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: unitree_go.msg.dds_ + IDL file: HeightMap_.idl + +""" + +from enum import auto +from typing import TYPE_CHECKING, Optional +from dataclasses import dataclass + +import cyclonedds.idl as idl +import cyclonedds.idl.annotations as annotate +import cyclonedds.idl.types as types + +# root module import for resolving types +# import unitree_go + + +@dataclass +@annotate.final +@annotate.autoid("sequential") +class HeightMap_(idl.IdlStruct, typename="unitree_go.msg.dds_.HeightMap_"): + stamp: types.float64 + frame_id: str + resolution: types.float32 + width: types.uint32 + height: types.uint32 + origin: types.array[types.float32, 2] + data: types.sequence[types.float32] + + diff --git a/unitree_sdk2py/idl/unitree_go/msg/dds_/_IMUState_.py b/unitree_sdk2py/idl/unitree_go/msg/dds_/_IMUState_.py new file mode 100644 index 0000000..e48908f --- /dev/null +++ b/unitree_sdk2py/idl/unitree_go/msg/dds_/_IMUState_.py @@ -0,0 +1,31 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: unitree_go.msg.dds_ + IDL file: IMUState_.idl + +""" + +from enum import auto +from typing import TYPE_CHECKING, Optional +from dataclasses import dataclass + +import cyclonedds.idl as idl +import cyclonedds.idl.annotations as annotate +import cyclonedds.idl.types as types + +# root module import for resolving types +# import unitree_go + + +@dataclass +@annotate.final +@annotate.autoid("sequential") +class IMUState_(idl.IdlStruct, typename="unitree_go.msg.dds_.IMUState_"): + quaternion: types.array[types.float32, 4] + gyroscope: types.array[types.float32, 3] + accelerometer: types.array[types.float32, 3] + rpy: types.array[types.float32, 3] + temperature: types.uint8 + + diff --git a/unitree_sdk2py/idl/unitree_go/msg/dds_/_InterfaceConfig_.py b/unitree_sdk2py/idl/unitree_go/msg/dds_/_InterfaceConfig_.py new file mode 100644 index 0000000..5efbd64 --- /dev/null +++ b/unitree_sdk2py/idl/unitree_go/msg/dds_/_InterfaceConfig_.py @@ -0,0 +1,29 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: unitree_go.msg.dds_ + IDL file: InterfaceConfig_.idl + +""" + +from enum import auto +from typing import TYPE_CHECKING, Optional +from dataclasses import dataclass + +import cyclonedds.idl as idl +import cyclonedds.idl.annotations as annotate +import cyclonedds.idl.types as types + +# root module import for resolving types +# import unitree_go + + +@dataclass +@annotate.final +@annotate.autoid("sequential") +class InterfaceConfig_(idl.IdlStruct, typename="unitree_go.msg.dds_.InterfaceConfig_"): + mode: types.uint8 + value: types.uint8 + reserve: types.array[types.uint8, 2] + + diff --git a/unitree_sdk2py/idl/unitree_go/msg/dds_/_LidarState_.py b/unitree_sdk2py/idl/unitree_go/msg/dds_/_LidarState_.py new file mode 100644 index 0000000..6861068 --- /dev/null +++ b/unitree_sdk2py/idl/unitree_go/msg/dds_/_LidarState_.py @@ -0,0 +1,43 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: unitree_go.msg.dds_ + IDL file: LidarState_.idl + +""" + +from enum import auto +from typing import TYPE_CHECKING, Optional +from dataclasses import dataclass + +import cyclonedds.idl as idl +import cyclonedds.idl.annotations as annotate +import cyclonedds.idl.types as types + +# root module import for resolving types +# import unitree_go + + +@dataclass +@annotate.final +@annotate.autoid("sequential") +class LidarState_(idl.IdlStruct, typename="unitree_go.msg.dds_.LidarState_"): + stamp: types.float64 + firmware_version: str + software_version: str + sdk_version: str + sys_rotation_speed: types.float32 + com_rotation_speed: types.float32 + error_state: types.uint8 + cloud_frequency: types.float32 + cloud_packet_loss_rate: types.float32 + cloud_size: types.uint32 + cloud_scan_num: types.uint32 + imu_frequency: types.float32 + imu_packet_loss_rate: types.float32 + imu_rpy: types.array[types.float32, 3] + serial_recv_stamp: types.float64 + serial_buffer_size: types.uint32 + serial_buffer_read: types.uint32 + + diff --git a/unitree_sdk2py/idl/unitree_go/msg/dds_/_LowCmd_.py b/unitree_sdk2py/idl/unitree_go/msg/dds_/_LowCmd_.py new file mode 100644 index 0000000..bcd4781 --- /dev/null +++ b/unitree_sdk2py/idl/unitree_go/msg/dds_/_LowCmd_.py @@ -0,0 +1,40 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: unitree_go.msg.dds_ + IDL file: LowCmd_.idl + +""" + +from enum import auto +from typing import TYPE_CHECKING, Optional +from dataclasses import dataclass + +import cyclonedds.idl as idl +import cyclonedds.idl.annotations as annotate +import cyclonedds.idl.types as types + +# root module import for resolving types +# import unitree_go + + +@dataclass +@annotate.final +@annotate.autoid("sequential") +class LowCmd_(idl.IdlStruct, typename="unitree_go.msg.dds_.LowCmd_"): + head: types.array[types.uint8, 2] + level_flag: types.uint8 + frame_reserve: types.uint8 + sn: types.array[types.uint32, 2] + version: types.array[types.uint32, 2] + bandwidth: types.uint16 + motor_cmd: types.array['unitree_sdk2py.idl.unitree_go.msg.dds_.MotorCmd_', 20] + bms_cmd: 'unitree_sdk2py.idl.unitree_go.msg.dds_.BmsCmd_' + wireless_remote: types.array[types.uint8, 40] + led: types.array[types.uint8, 12] + fan: types.array[types.uint8, 2] + gpio: types.uint8 + reserve: types.uint32 + crc: types.uint32 + + diff --git a/unitree_sdk2py/idl/unitree_go/msg/dds_/_LowState_.py b/unitree_sdk2py/idl/unitree_go/msg/dds_/_LowState_.py new file mode 100644 index 0000000..79ecbe6 --- /dev/null +++ b/unitree_sdk2py/idl/unitree_go/msg/dds_/_LowState_.py @@ -0,0 +1,48 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: unitree_go.msg.dds_ + IDL file: LowState_.idl + +""" + +from enum import auto +from typing import TYPE_CHECKING, Optional +from dataclasses import dataclass + +import cyclonedds.idl as idl +import cyclonedds.idl.annotations as annotate +import cyclonedds.idl.types as types + +# root module import for resolving types +# import unitree_go + + +@dataclass +@annotate.final +@annotate.autoid("sequential") +class LowState_(idl.IdlStruct, typename="unitree_go.msg.dds_.LowState_"): + head: types.array[types.uint8, 2] + level_flag: types.uint8 + frame_reserve: types.uint8 + sn: types.array[types.uint32, 2] + version: types.array[types.uint32, 2] + bandwidth: types.uint16 + imu_state: 'unitree_sdk2py.idl.unitree_go.msg.dds_.IMUState_' + motor_state: types.array['unitree_sdk2py.idl.unitree_go.msg.dds_.MotorState_', 20] + bms_state: 'unitree_sdk2py.idl.unitree_go.msg.dds_.BmsState_' + foot_force: types.array[types.int16, 4] + foot_force_est: types.array[types.int16, 4] + tick: types.uint32 + wireless_remote: types.array[types.uint8, 40] + bit_flag: types.uint8 + adc_reel: types.float32 + temperature_ntc1: types.uint8 + temperature_ntc2: types.uint8 + power_v: types.float32 + power_a: types.float32 + fan_frequency: types.array[types.uint16, 4] + reserve: types.uint32 + crc: types.uint32 + + diff --git a/unitree_sdk2py/idl/unitree_go/msg/dds_/_MotorCmd_.py b/unitree_sdk2py/idl/unitree_go/msg/dds_/_MotorCmd_.py new file mode 100644 index 0000000..5a2dd85 --- /dev/null +++ b/unitree_sdk2py/idl/unitree_go/msg/dds_/_MotorCmd_.py @@ -0,0 +1,33 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: unitree_go.msg.dds_ + IDL file: MotorCmd_.idl + +""" + +from enum import auto +from typing import TYPE_CHECKING, Optional +from dataclasses import dataclass + +import cyclonedds.idl as idl +import cyclonedds.idl.annotations as annotate +import cyclonedds.idl.types as types + +# root module import for resolving types +# import unitree_go + + +@dataclass +@annotate.final +@annotate.autoid("sequential") +class MotorCmd_(idl.IdlStruct, typename="unitree_go.msg.dds_.MotorCmd_"): + mode: types.uint8 + q: types.float32 + dq: types.float32 + tau: types.float32 + kp: types.float32 + kd: types.float32 + reserve: types.array[types.uint32, 3] + + diff --git a/unitree_sdk2py/idl/unitree_go/msg/dds_/_MotorCmds_.py b/unitree_sdk2py/idl/unitree_go/msg/dds_/_MotorCmds_.py new file mode 100644 index 0000000..11d3029 --- /dev/null +++ b/unitree_sdk2py/idl/unitree_go/msg/dds_/_MotorCmds_.py @@ -0,0 +1,23 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: unitree_go.msg.dds_ + IDL file: MotorCmds_.idl + +""" + +from enum import auto +from typing import TYPE_CHECKING, Optional +from dataclasses import dataclass, field + +import cyclonedds.idl as idl +import cyclonedds.idl.annotations as annotate +import cyclonedds.idl.types as types + +@dataclass +@annotate.final +@annotate.autoid("sequential") +class MotorCmds_(idl.IdlStruct, typename="unitree_go.msg.dds_.MotorCmds_"): + cmds: types.sequence['unitree_sdk2py.idl.unitree_go.msg.dds_.MotorCmd_'] = field(default_factory=lambda: []) + + diff --git a/unitree_sdk2py/idl/unitree_go/msg/dds_/_MotorState_.py b/unitree_sdk2py/idl/unitree_go/msg/dds_/_MotorState_.py new file mode 100644 index 0000000..0787acb --- /dev/null +++ b/unitree_sdk2py/idl/unitree_go/msg/dds_/_MotorState_.py @@ -0,0 +1,37 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: unitree_go.msg.dds_ + IDL file: MotorState_.idl + +""" + +from enum import auto +from typing import TYPE_CHECKING, Optional +from dataclasses import dataclass + +import cyclonedds.idl as idl +import cyclonedds.idl.annotations as annotate +import cyclonedds.idl.types as types + +# root module import for resolving types +# import unitree_go + + +@dataclass +@annotate.final +@annotate.autoid("sequential") +class MotorState_(idl.IdlStruct, typename="unitree_go.msg.dds_.MotorState_"): + mode: types.uint8 + q: types.float32 + dq: types.float32 + ddq: types.float32 + tau_est: types.float32 + q_raw: types.float32 + dq_raw: types.float32 + ddq_raw: types.float32 + temperature: types.uint8 + lost: types.uint32 + reserve: types.array[types.uint32, 2] + + diff --git a/unitree_sdk2py/idl/unitree_go/msg/dds_/_MotorStates_.py b/unitree_sdk2py/idl/unitree_go/msg/dds_/_MotorStates_.py new file mode 100644 index 0000000..4b0245b --- /dev/null +++ b/unitree_sdk2py/idl/unitree_go/msg/dds_/_MotorStates_.py @@ -0,0 +1,23 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: unitree_go.msg.dds_ + IDL file: MotorStates_.idl + +""" + +from enum import auto +from typing import TYPE_CHECKING, Optional +from dataclasses import dataclass, field + +import cyclonedds.idl as idl +import cyclonedds.idl.annotations as annotate +import cyclonedds.idl.types as types + +@dataclass +@annotate.final +@annotate.autoid("sequential") +class MotorStates_(idl.IdlStruct, typename="unitree_go.msg.dds_.MotorStates_"): + states: types.sequence['unitree_sdk2py.idl.unitree_go.msg.dds_.MotorState_'] = field(default_factory=lambda: []) + + diff --git a/unitree_sdk2py/idl/unitree_go/msg/dds_/_PathPoint_.py b/unitree_sdk2py/idl/unitree_go/msg/dds_/_PathPoint_.py new file mode 100644 index 0000000..20a8c55 --- /dev/null +++ b/unitree_sdk2py/idl/unitree_go/msg/dds_/_PathPoint_.py @@ -0,0 +1,33 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: unitree_go.msg.dds_ + IDL file: PathPoint_.idl + +""" + +from enum import auto +from typing import TYPE_CHECKING, Optional +from dataclasses import dataclass + +import cyclonedds.idl as idl +import cyclonedds.idl.annotations as annotate +import cyclonedds.idl.types as types + +# root module import for resolving types +# import unitree_go + + +@dataclass +@annotate.final +@annotate.autoid("sequential") +class PathPoint_(idl.IdlStruct, typename="unitree_go.msg.dds_.PathPoint_"): + t_from_start: types.float32 + x: types.float32 + y: types.float32 + yaw: types.float32 + vx: types.float32 + vy: types.float32 + vyaw: types.float32 + + diff --git a/unitree_sdk2py/idl/unitree_go/msg/dds_/_Req_.py b/unitree_sdk2py/idl/unitree_go/msg/dds_/_Req_.py new file mode 100644 index 0000000..5bb39b3 --- /dev/null +++ b/unitree_sdk2py/idl/unitree_go/msg/dds_/_Req_.py @@ -0,0 +1,28 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: unitree_go.msg.dds_ + IDL file: Req_.idl + +""" + +from enum import auto +from typing import TYPE_CHECKING, Optional +from dataclasses import dataclass + +import cyclonedds.idl as idl +import cyclonedds.idl.annotations as annotate +import cyclonedds.idl.types as types + +# root module import for resolving types +# import unitree_go + + +@dataclass +@annotate.final +@annotate.autoid("sequential") +class Req_(idl.IdlStruct, typename="unitree_go.msg.dds_.Req_"): + uuid: str + body: str + + diff --git a/unitree_sdk2py/idl/unitree_go/msg/dds_/_Res_.py b/unitree_sdk2py/idl/unitree_go/msg/dds_/_Res_.py new file mode 100644 index 0000000..684a5a7 --- /dev/null +++ b/unitree_sdk2py/idl/unitree_go/msg/dds_/_Res_.py @@ -0,0 +1,29 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: unitree_go.msg.dds_ + IDL file: Res_.idl + +""" + +from enum import auto +from typing import TYPE_CHECKING, Optional +from dataclasses import dataclass + +import cyclonedds.idl as idl +import cyclonedds.idl.annotations as annotate +import cyclonedds.idl.types as types + +# root module import for resolving types +# import unitree_go + + +@dataclass +@annotate.final +@annotate.autoid("sequential") +class Res_(idl.IdlStruct, typename="unitree_go.msg.dds_.Res_"): + uuid: str + data: types.sequence[types.uint8] + body: str + + diff --git a/unitree_sdk2py/idl/unitree_go/msg/dds_/_SportModeState_.py b/unitree_sdk2py/idl/unitree_go/msg/dds_/_SportModeState_.py new file mode 100644 index 0000000..e0a26a1 --- /dev/null +++ b/unitree_sdk2py/idl/unitree_go/msg/dds_/_SportModeState_.py @@ -0,0 +1,42 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: unitree_go.msg.dds_ + IDL file: SportModeState_.idl + +""" + +from enum import auto +from typing import TYPE_CHECKING, Optional +from dataclasses import dataclass + +import cyclonedds.idl as idl +import cyclonedds.idl.annotations as annotate +import cyclonedds.idl.types as types + +# root module import for resolving types +# import unitree_go + + +@dataclass +@annotate.final +@annotate.autoid("sequential") +class SportModeState_(idl.IdlStruct, typename="unitree_go.msg.dds_.SportModeState_"): + stamp: 'unitree_sdk2py.idl.unitree_go.msg.dds_.TimeSpec_' + error_code: types.uint32 + imu_state: 'unitree_sdk2py.idl.unitree_go.msg.dds_.IMUState_' + mode: types.uint8 + progress: types.float32 + gait_type: types.uint8 + foot_raise_height: types.float32 + position: types.array[types.float32, 3] + body_height: types.float32 + velocity: types.array[types.float32, 3] + yaw_speed: types.float32 + range_obstacle: types.array[types.float32, 4] + foot_force: types.array[types.int16, 4] + foot_position_body: types.array[types.float32, 12] + foot_speed_body: types.array[types.float32, 12] + path_point: types.array['unitree_sdk2py.idl.unitree_go.msg.dds_.PathPoint_', 10] + + diff --git a/unitree_sdk2py/idl/unitree_go/msg/dds_/_TimeSpec_.py b/unitree_sdk2py/idl/unitree_go/msg/dds_/_TimeSpec_.py new file mode 100644 index 0000000..7a580b6 --- /dev/null +++ b/unitree_sdk2py/idl/unitree_go/msg/dds_/_TimeSpec_.py @@ -0,0 +1,28 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: unitree_go.msg.dds_ + IDL file: TimeSpec_.idl + +""" + +from enum import auto +from typing import TYPE_CHECKING, Optional +from dataclasses import dataclass + +import cyclonedds.idl as idl +import cyclonedds.idl.annotations as annotate +import cyclonedds.idl.types as types + +# root module import for resolving types +# import unitree_go + + +@dataclass +@annotate.final +@annotate.autoid("sequential") +class TimeSpec_(idl.IdlStruct, typename="unitree_go.msg.dds_.TimeSpec_"): + sec: types.int32 + nanosec: types.uint32 + + diff --git a/unitree_sdk2py/idl/unitree_go/msg/dds_/_UwbState_.py b/unitree_sdk2py/idl/unitree_go/msg/dds_/_UwbState_.py new file mode 100644 index 0000000..d5f2588 --- /dev/null +++ b/unitree_sdk2py/idl/unitree_go/msg/dds_/_UwbState_.py @@ -0,0 +1,43 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: unitree_go.msg.dds_ + IDL file: UwbState_.idl + +""" + +from enum import auto +from typing import TYPE_CHECKING, Optional +from dataclasses import dataclass + +import cyclonedds.idl as idl +import cyclonedds.idl.annotations as annotate +import cyclonedds.idl.types as types + +# root module import for resolving types +# import unitree_go + + +@dataclass +@annotate.final +@annotate.autoid("sequential") +class UwbState_(idl.IdlStruct, typename="unitree_go.msg.dds_.UwbState_"): + version: types.array[types.uint8, 2] + channel: types.uint8 + joy_mode: types.uint8 + orientation_est: types.float32 + pitch_est: types.float32 + distance_est: types.float32 + yaw_est: types.float32 + tag_roll: types.float32 + tag_pitch: types.float32 + tag_yaw: types.float32 + base_roll: types.float32 + base_pitch: types.float32 + base_yaw: types.float32 + joystick: types.array[types.float32, 2] + error_state: types.uint8 + buttons: types.uint8 + enabled_from_app: types.uint8 + + diff --git a/unitree_sdk2py/idl/unitree_go/msg/dds_/_UwbSwitch_.py b/unitree_sdk2py/idl/unitree_go/msg/dds_/_UwbSwitch_.py new file mode 100644 index 0000000..b902ef8 --- /dev/null +++ b/unitree_sdk2py/idl/unitree_go/msg/dds_/_UwbSwitch_.py @@ -0,0 +1,27 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: unitree_go.msg.dds_ + IDL file: UwbSwitch_.idl + +""" + +from enum import auto +from typing import TYPE_CHECKING, Optional +from dataclasses import dataclass + +import cyclonedds.idl as idl +import cyclonedds.idl.annotations as annotate +import cyclonedds.idl.types as types + +# root module import for resolving types +# import unitree_go + + +@dataclass +@annotate.final +@annotate.autoid("sequential") +class UwbSwitch_(idl.IdlStruct, typename="unitree_go.msg.dds_.UwbSwitch_"): + enabled: types.uint8 + + diff --git a/unitree_sdk2py/idl/unitree_go/msg/dds_/_WirelessController_.py b/unitree_sdk2py/idl/unitree_go/msg/dds_/_WirelessController_.py new file mode 100644 index 0000000..18919dd --- /dev/null +++ b/unitree_sdk2py/idl/unitree_go/msg/dds_/_WirelessController_.py @@ -0,0 +1,31 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: unitree_go.msg.dds_ + IDL file: WirelessController_.idl + +""" + +from enum import auto +from typing import TYPE_CHECKING, Optional +from dataclasses import dataclass + +import cyclonedds.idl as idl +import cyclonedds.idl.annotations as annotate +import cyclonedds.idl.types as types + +# root module import for resolving types +# import unitree_go + + +@dataclass +@annotate.final +@annotate.autoid("sequential") +class WirelessController_(idl.IdlStruct, typename="unitree_go.msg.dds_.WirelessController_"): + lx: types.float32 + ly: types.float32 + rx: types.float32 + ry: types.float32 + keys: types.uint16 + + diff --git a/unitree_sdk2py/idl/unitree_go/msg/dds_/__init__.py b/unitree_sdk2py/idl/unitree_go/msg/dds_/__init__.py new file mode 100644 index 0000000..fc24f6f --- /dev/null +++ b/unitree_sdk2py/idl/unitree_go/msg/dds_/__init__.py @@ -0,0 +1,31 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: unitree_go.msg.dds_ + +""" + +from ._AudioData_ import AudioData_ +from ._BmsCmd_ import BmsCmd_ +from ._BmsState_ import BmsState_ +from ._Error_ import Error_ +from ._Go2FrontVideoData_ import Go2FrontVideoData_ +from ._HeightMap_ import HeightMap_ +from ._IMUState_ import IMUState_ +from ._InterfaceConfig_ import InterfaceConfig_ +from ._LidarState_ import LidarState_ +from ._LowCmd_ import LowCmd_ +from ._LowState_ import LowState_ +from ._MotorCmd_ import MotorCmd_ +from ._MotorCmds_ import MotorCmds_ +from ._MotorState_ import MotorState_ +from ._MotorStates_ import MotorStates_ +from ._Req_ import Req_ +from ._Res_ import Res_ +from ._SportModeState_ import SportModeState_ +from ._TimeSpec_ import TimeSpec_ +from ._PathPoint_ import PathPoint_ +from ._UwbState_ import UwbState_ +from ._UwbSwitch_ import UwbSwitch_ +from ._WirelessController_ import WirelessController_ +__all__ = ["AudioData_", "BmsCmd_", "BmsState_", "Error_", "Go2FrontVideoData_", "HeightMap_", "IMUState_", "InterfaceConfig_", "LidarState_", "LowCmd_", "LowState_", "MotorCmd_", "MotorCmds_", "MotorState_", "MotorStates_", "Req_", "Res_", "SportModeState_", "TimeSpec_", "PathPoint_", "UwbState_", "UwbSwitch_", "WirelessController_", ] diff --git a/unitree_sdk2py/idl/unitree_hg/.idlpy_manifest b/unitree_sdk2py/idl/unitree_hg/.idlpy_manifest new file mode 100644 index 0000000..fd4ea94 --- /dev/null +++ b/unitree_sdk2py/idl/unitree_hg/.idlpy_manifest @@ -0,0 +1,43 @@ +BmsCmd_ +msg + + +BmsState_ +msg + + +HandCmd_ +msg + + +HandState_ +msg + + +IMUState_ +msg + + +LowCmd_ +msg + + +LowState_ +msg + + +MainBoardState_ +msg + + +MotorCmd_ +msg + + +MotorState_ +msg + + +PressSensorState_ +msg + diff --git a/unitree_sdk2py/idl/unitree_hg/__init__.py b/unitree_sdk2py/idl/unitree_hg/__init__.py new file mode 100644 index 0000000..5f55ee5 --- /dev/null +++ b/unitree_sdk2py/idl/unitree_hg/__init__.py @@ -0,0 +1,9 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: unitree_hg + +""" + +from . import msg +__all__ = ["msg", ] diff --git a/unitree_sdk2py/idl/unitree_hg/msg/.idlpy_manifest b/unitree_sdk2py/idl/unitree_hg/msg/.idlpy_manifest new file mode 100644 index 0000000..3218e96 --- /dev/null +++ b/unitree_sdk2py/idl/unitree_hg/msg/.idlpy_manifest @@ -0,0 +1,43 @@ +BmsCmd_ +dds_ + + +BmsState_ +dds_ + + +HandCmd_ +dds_ + + +HandState_ +dds_ + + +IMUState_ +dds_ + + +LowCmd_ +dds_ + + +LowState_ +dds_ + + +MainBoardState_ +dds_ + + +MotorCmd_ +dds_ + + +MotorState_ +dds_ + + +PressSensorState_ +dds_ + diff --git a/unitree_sdk2py/idl/unitree_hg/msg/__init__.py b/unitree_sdk2py/idl/unitree_hg/msg/__init__.py new file mode 100644 index 0000000..02b132d --- /dev/null +++ b/unitree_sdk2py/idl/unitree_hg/msg/__init__.py @@ -0,0 +1,9 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: unitree_hg.msg + +""" + +from . import dds_ +__all__ = ["dds_", ] diff --git a/unitree_sdk2py/idl/unitree_hg/msg/dds_/.idlpy_manifest b/unitree_sdk2py/idl/unitree_hg/msg/dds_/.idlpy_manifest new file mode 100644 index 0000000..6174f37 --- /dev/null +++ b/unitree_sdk2py/idl/unitree_hg/msg/dds_/.idlpy_manifest @@ -0,0 +1,43 @@ +BmsCmd_ + +BmsCmd_ + +BmsState_ + +BmsState_ + +HandCmd_ + +HandCmd_ + +HandState_ + +HandState_ + +IMUState_ + +IMUState_ + +LowCmd_ + +LowCmd_ + +LowState_ + +LowState_ + +MainBoardState_ + +MainBoardState_ + +MotorCmd_ + +MotorCmd_ + +MotorState_ + +MotorState_ + +PressSensorState_ + +PressSensorState_ diff --git a/unitree_sdk2py/idl/unitree_hg/msg/dds_/_BmsCmd_.py b/unitree_sdk2py/idl/unitree_hg/msg/dds_/_BmsCmd_.py new file mode 100644 index 0000000..525d1a4 --- /dev/null +++ b/unitree_sdk2py/idl/unitree_hg/msg/dds_/_BmsCmd_.py @@ -0,0 +1,28 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: unitree_hg.msg.dds_ + IDL file: BmsCmd_.idl + +""" + +from enum import auto +from typing import TYPE_CHECKING, Optional +from dataclasses import dataclass + +import cyclonedds.idl as idl +import cyclonedds.idl.annotations as annotate +import cyclonedds.idl.types as types + +# root module import for resolving types +# import unitree_hg + + +@dataclass +@annotate.final +@annotate.autoid("sequential") +class BmsCmd_(idl.IdlStruct, typename="unitree_hg.msg.dds_.BmsCmd_"): + cmd: types.uint8 + reserve: types.array[types.uint8, 40] + + diff --git a/unitree_sdk2py/idl/unitree_hg/msg/dds_/_BmsState_.py b/unitree_sdk2py/idl/unitree_hg/msg/dds_/_BmsState_.py new file mode 100644 index 0000000..dd0c6bd --- /dev/null +++ b/unitree_sdk2py/idl/unitree_hg/msg/dds_/_BmsState_.py @@ -0,0 +1,39 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: unitree_hg.msg.dds_ + IDL file: BmsState_.idl + +""" + +from enum import auto +from typing import TYPE_CHECKING, Optional +from dataclasses import dataclass + +import cyclonedds.idl as idl +import cyclonedds.idl.annotations as annotate +import cyclonedds.idl.types as types + +# root module import for resolving types +# import unitree_hg + + +@dataclass +@annotate.final +@annotate.autoid("sequential") +class BmsState_(idl.IdlStruct, typename="unitree_hg.msg.dds_.BmsState_"): + version_high: types.uint8 + version_low: types.uint8 + fn: types.uint8 + cell_vol: types.array[types.uint16, 40] + bmsvoltage: types.array[types.uint32, 3] + current: types.int32 + soc: types.uint8 + soh: types.uint8 + temperature: types.array[types.int16, 12] + cycle: types.uint16 + manufacturer_date: types.uint16 + bmsstate: types.array[types.uint32, 5] + reserve: types.array[types.uint32, 3] + + diff --git a/unitree_sdk2py/idl/unitree_hg/msg/dds_/_HandCmd_.py b/unitree_sdk2py/idl/unitree_hg/msg/dds_/_HandCmd_.py new file mode 100644 index 0000000..044afcb --- /dev/null +++ b/unitree_sdk2py/idl/unitree_hg/msg/dds_/_HandCmd_.py @@ -0,0 +1,28 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: unitree_hg.msg.dds_ + IDL file: HandCmd_.idl + +""" + +from enum import auto +from typing import TYPE_CHECKING, Optional +from dataclasses import dataclass + +import cyclonedds.idl as idl +import cyclonedds.idl.annotations as annotate +import cyclonedds.idl.types as types + +# root module import for resolving types +# import unitree_hg + + +@dataclass +@annotate.final +@annotate.autoid("sequential") +class HandCmd_(idl.IdlStruct, typename="unitree_hg.msg.dds_.HandCmd_"): + motor_cmd: types.sequence['unitree_sdk2py.idl.unitree_hg.msg.dds_.MotorCmd_'] + reserve: types.array[types.uint32, 4] + + diff --git a/unitree_sdk2py/idl/unitree_hg/msg/dds_/_HandState_.py b/unitree_sdk2py/idl/unitree_hg/msg/dds_/_HandState_.py new file mode 100644 index 0000000..351dc75 --- /dev/null +++ b/unitree_sdk2py/idl/unitree_hg/msg/dds_/_HandState_.py @@ -0,0 +1,35 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: unitree_hg.msg.dds_ + IDL file: HandState_.idl + +""" + +from enum import auto +from typing import TYPE_CHECKING, Optional +from dataclasses import dataclass + +import cyclonedds.idl as idl +import cyclonedds.idl.annotations as annotate +import cyclonedds.idl.types as types + +# root module import for resolving types +# import unitree_hg + + +@dataclass +@annotate.final +@annotate.autoid("sequential") +class HandState_(idl.IdlStruct, typename="unitree_hg.msg.dds_.HandState_"): + motor_state: types.sequence['unitree_sdk2py.idl.unitree_hg.msg.dds_.MotorState_'] + press_sensor_state: types.sequence['unitree_sdk2py.idl.unitree_hg.msg.dds_.PressSensorState_'] + imu_state: 'unitree_sdk2py.idl.unitree_hg.msg.dds_.IMUState_' + power_v: types.float32 + power_a: types.float32 + system_v: types.float32 + device_v: types.float32 + error: types.array[types.uint32, 2] + reserve: types.array[types.uint32, 2] + + diff --git a/unitree_sdk2py/idl/unitree_hg/msg/dds_/_IMUState_.py b/unitree_sdk2py/idl/unitree_hg/msg/dds_/_IMUState_.py new file mode 100644 index 0000000..75d01a6 --- /dev/null +++ b/unitree_sdk2py/idl/unitree_hg/msg/dds_/_IMUState_.py @@ -0,0 +1,31 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: unitree_hg.msg.dds_ + IDL file: IMUState_.idl + +""" + +from enum import auto +from typing import TYPE_CHECKING, Optional +from dataclasses import dataclass + +import cyclonedds.idl as idl +import cyclonedds.idl.annotations as annotate +import cyclonedds.idl.types as types + +# root module import for resolving types +# import unitree_hg + + +@dataclass +@annotate.final +@annotate.autoid("sequential") +class IMUState_(idl.IdlStruct, typename="unitree_hg.msg.dds_.IMUState_"): + quaternion: types.array[types.float32, 4] + gyroscope: types.array[types.float32, 3] + accelerometer: types.array[types.float32, 3] + rpy: types.array[types.float32, 3] + temperature: types.int16 + + diff --git a/unitree_sdk2py/idl/unitree_hg/msg/dds_/_LowCmd_.py b/unitree_sdk2py/idl/unitree_hg/msg/dds_/_LowCmd_.py new file mode 100644 index 0000000..56b4b8b --- /dev/null +++ b/unitree_sdk2py/idl/unitree_hg/msg/dds_/_LowCmd_.py @@ -0,0 +1,31 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: unitree_hg.msg.dds_ + IDL file: LowCmd_.idl + +""" + +from enum import auto +from typing import TYPE_CHECKING, Optional +from dataclasses import dataclass + +import cyclonedds.idl as idl +import cyclonedds.idl.annotations as annotate +import cyclonedds.idl.types as types + +# root module import for resolving types +# import unitree_hg + + +@dataclass +@annotate.final +@annotate.autoid("sequential") +class LowCmd_(idl.IdlStruct, typename="unitree_hg.msg.dds_.LowCmd_"): + mode_pr: types.uint8 + mode_machine: types.uint8 + motor_cmd: types.array['unitree_sdk2py.idl.unitree_hg.msg.dds_.MotorCmd_', 35] + reserve: types.array[types.uint32, 4] + crc: types.uint32 + + diff --git a/unitree_sdk2py/idl/unitree_hg/msg/dds_/_LowState_.py b/unitree_sdk2py/idl/unitree_hg/msg/dds_/_LowState_.py new file mode 100644 index 0000000..8e95ac7 --- /dev/null +++ b/unitree_sdk2py/idl/unitree_hg/msg/dds_/_LowState_.py @@ -0,0 +1,35 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: unitree_hg.msg.dds_ + IDL file: LowState_.idl + +""" + +from enum import auto +from typing import TYPE_CHECKING, Optional +from dataclasses import dataclass + +import cyclonedds.idl as idl +import cyclonedds.idl.annotations as annotate +import cyclonedds.idl.types as types + +# root module import for resolving types +# import unitree_hg + + +@dataclass +@annotate.final +@annotate.autoid("sequential") +class LowState_(idl.IdlStruct, typename="unitree_hg.msg.dds_.LowState_"): + version: types.array[types.uint32, 2] + mode_pr: types.uint8 + mode_machine: types.uint8 + tick: types.uint32 + imu_state: 'unitree_sdk2py.idl.unitree_hg.msg.dds_.IMUState_' + motor_state: types.array['unitree_sdk2py.idl.unitree_hg.msg.dds_.MotorState_', 35] + wireless_remote: types.array[types.uint8, 40] + reserve: types.array[types.uint32, 4] + crc: types.uint32 + + diff --git a/unitree_sdk2py/idl/unitree_hg/msg/dds_/_MainBoardState_.py b/unitree_sdk2py/idl/unitree_hg/msg/dds_/_MainBoardState_.py new file mode 100644 index 0000000..c280245 --- /dev/null +++ b/unitree_sdk2py/idl/unitree_hg/msg/dds_/_MainBoardState_.py @@ -0,0 +1,30 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: unitree_hg.msg.dds_ + IDL file: MainBoardState_.idl + +""" + +from enum import auto +from typing import TYPE_CHECKING, Optional +from dataclasses import dataclass + +import cyclonedds.idl as idl +import cyclonedds.idl.annotations as annotate +import cyclonedds.idl.types as types + +# root module import for resolving types +# import unitree_hg + + +@dataclass +@annotate.final +@annotate.autoid("sequential") +class MainBoardState_(idl.IdlStruct, typename="unitree_hg.msg.dds_.MainBoardState_"): + fan_state: types.array[types.uint16, 6] + temperature: types.array[types.int16, 6] + value: types.array[types.float32, 6] + state: types.array[types.uint32, 6] + + diff --git a/unitree_sdk2py/idl/unitree_hg/msg/dds_/_MotorCmd_.py b/unitree_sdk2py/idl/unitree_hg/msg/dds_/_MotorCmd_.py new file mode 100644 index 0000000..3dd8f9d --- /dev/null +++ b/unitree_sdk2py/idl/unitree_hg/msg/dds_/_MotorCmd_.py @@ -0,0 +1,33 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: unitree_hg.msg.dds_ + IDL file: MotorCmd_.idl + +""" + +from enum import auto +from typing import TYPE_CHECKING, Optional +from dataclasses import dataclass + +import cyclonedds.idl as idl +import cyclonedds.idl.annotations as annotate +import cyclonedds.idl.types as types + +# root module import for resolving types +# import unitree_hg + + +@dataclass +@annotate.final +@annotate.autoid("sequential") +class MotorCmd_(idl.IdlStruct, typename="unitree_hg.msg.dds_.MotorCmd_"): + mode: types.uint8 + q: types.float32 + dq: types.float32 + tau: types.float32 + kp: types.float32 + kd: types.float32 + reserve: types.uint32 + + diff --git a/unitree_sdk2py/idl/unitree_hg/msg/dds_/_MotorState_.py b/unitree_sdk2py/idl/unitree_hg/msg/dds_/_MotorState_.py new file mode 100644 index 0000000..839fccf --- /dev/null +++ b/unitree_sdk2py/idl/unitree_hg/msg/dds_/_MotorState_.py @@ -0,0 +1,36 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: unitree_hg.msg.dds_ + IDL file: MotorState_.idl + +""" + +from enum import auto +from typing import TYPE_CHECKING, Optional +from dataclasses import dataclass + +import cyclonedds.idl as idl +import cyclonedds.idl.annotations as annotate +import cyclonedds.idl.types as types + +# root module import for resolving types +# import unitree_hg + + +@dataclass +@annotate.final +@annotate.autoid("sequential") +class MotorState_(idl.IdlStruct, typename="unitree_hg.msg.dds_.MotorState_"): + mode: types.uint8 + q: types.float32 + dq: types.float32 + ddq: types.float32 + tau_est: types.float32 + temperature: types.array[types.int16, 2] + vol: types.float32 + sensor: types.array[types.uint32, 2] + motorstate: types.uint32 + reserve: types.array[types.uint32, 4] + + diff --git a/unitree_sdk2py/idl/unitree_hg/msg/dds_/_PressSensorState_.py b/unitree_sdk2py/idl/unitree_hg/msg/dds_/_PressSensorState_.py new file mode 100644 index 0000000..7dcf794 --- /dev/null +++ b/unitree_sdk2py/idl/unitree_hg/msg/dds_/_PressSensorState_.py @@ -0,0 +1,30 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: unitree_hg.msg.dds_ + IDL file: PressSensorState_.idl + +""" + +from enum import auto +from typing import TYPE_CHECKING, Optional +from dataclasses import dataclass + +import cyclonedds.idl as idl +import cyclonedds.idl.annotations as annotate +import cyclonedds.idl.types as types + +# root module import for resolving types +# import unitree_hg + + +@dataclass +@annotate.final +@annotate.autoid("sequential") +class PressSensorState_(idl.IdlStruct, typename="unitree_hg.msg.dds_.PressSensorState_"): + pressure: types.array[types.float32, 12] + temperature: types.array[types.float32, 12] + lost: types.uint32 + reserve: types.uint32 + + diff --git a/unitree_sdk2py/idl/unitree_hg/msg/dds_/__init__.py b/unitree_sdk2py/idl/unitree_hg/msg/dds_/__init__.py new file mode 100644 index 0000000..87b865f --- /dev/null +++ b/unitree_sdk2py/idl/unitree_hg/msg/dds_/__init__.py @@ -0,0 +1,19 @@ +""" + Generated by Eclipse Cyclone DDS idlc Python Backend + Cyclone DDS IDL version: v0.11.0 + Module: unitree_hg.msg.dds_ + +""" + +from ._BmsCmd_ import BmsCmd_ +from ._BmsState_ import BmsState_ +from ._HandCmd_ import HandCmd_ +from ._HandState_ import HandState_ +from ._IMUState_ import IMUState_ +from ._LowCmd_ import LowCmd_ +from ._LowState_ import LowState_ +from ._MainBoardState_ import MainBoardState_ +from ._MotorCmd_ import MotorCmd_ +from ._MotorState_ import MotorState_ +from ._PressSensorState_ import PressSensorState_ +__all__ = ["BmsCmd_", "BmsState_", "HandCmd_", "HandState_", "IMUState_", "LowCmd_", "LowState_", "MainBoardState_", "MotorCmd_", "MotorState_", "PressSensorState_", ] diff --git a/unitree_sdk2py/rpc/__init__.py b/unitree_sdk2py/rpc/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/unitree_sdk2py/rpc/client.py b/unitree_sdk2py/rpc/client.py new file mode 100644 index 0000000..d774e53 --- /dev/null +++ b/unitree_sdk2py/rpc/client.py @@ -0,0 +1,89 @@ +from .client_base import ClientBase +from .lease_client import LeaseClient +from .internal import * + +""" +" class Client +""" +class Client(ClientBase): + def __init__(self, serviceName: str, enabaleLease: bool = False): + super().__init__(serviceName) + + self.__apiMapping = {} + self.__apiVersion = None + self.__leaseClient = None + self.__enableLease = enabaleLease + + if (self.__enableLease): + self.__leaseClient = LeaseClient(serviceName) + self.__leaseClient.Init() + + def WaitLeaseApplied(self): + if self.__enableLease: + self.__leaseClient.WaitApplied() + + def GetLeaseId(self): + if self.__enableLease: + return self.__leaseClient.GetId() + else: + return None + + def GetApiVersion(self): + return self.__apiVersion + + def GetServerApiVersion(self): + code, apiVerson = self._CallBase(RPC_API_ID_INTERNAL_API_VERSION, "{}", 0, 0) + if code != 0: + print("[Client] get server api version error:", code) + return code, None + else: + return code, apiVerson + + def _SetApiVerson(self, apiVersion: str): + self.__apiVersion = apiVersion + + def _Call(self, apiId: int, parameter: str): + ret, proirity, leaseId = self.__CheckApi(apiId) + if ret == 0: + return self._CallBase(apiId, parameter, proirity, leaseId) + else: + return RPC_ERR_CLIENT_API_NOT_REG, None + + def _CallNoReply(self, apiId: int, parameter: str): + ret, proirity, leaseId = self.__CheckApi(apiId) + if ret == 0: + return self._CallNoReplyBase(apiId, parameter, proirity, leaseId) + else: + return RPC_ERR_CLIENT_API_NOT_REG + + def _CallBinary(self, apiId: int, parameter: list): + ret, proirity, leaseId = self.__CheckApi(apiId) + if ret == 0: + return self._CallBinaryBase(apiId, parameter, proirity, leaseId) + else: + return RPC_ERR_CLIENT_API_NOT_REG, None + + def _CallBinaryNoReply(self, apiId: int, parameter: list): + ret, proirity, leaseId = self.__CheckApi(apiId) + if ret == 0: + return self._CallBinaryNoReplyBase(apiId, parameter, proirity, leaseId) + else: + return RPC_ERR_CLIENT_API_NOT_REG + + def _RegistApi(self, apiId: int, proirity: int): + self.__apiMapping[apiId] = proirity + + def __CheckApi(self, apiId: int): + proirity = 0 + leaseId = 0 + + if apiId > RPC_INTERNAL_API_ID_MAX: + proirity = self.__apiMapping.get(apiId) + + if proirity is None: + return RPC_ERR_CLIENT_API_NOT_REG, proirity, leaseId + + if self.__enableLease: + leaseId = self.__leaseClient.GetId() + + return 0, proirity, leaseId \ No newline at end of file diff --git a/unitree_sdk2py/rpc/client_base.py b/unitree_sdk2py/rpc/client_base.py new file mode 100644 index 0000000..1bac028 --- /dev/null +++ b/unitree_sdk2py/rpc/client_base.py @@ -0,0 +1,93 @@ +import time + +from ..idl.unitree_api.msg.dds_ import Request_ as Request +from ..idl.unitree_api.msg.dds_ import RequestHeader_ as RequestHeader +from ..idl.unitree_api.msg.dds_ import RequestLease_ as RequestLease +from ..idl.unitree_api.msg.dds_ import RequestIdentity_ as RequestIdentity +from ..idl.unitree_api.msg.dds_ import RequestPolicy_ as RequestPolicy + +from ..utils.future import FutureResult + +from .client_stub import ClientStub +from .internal import * + + +""" +" class ClientBase +""" +class ClientBase: + def __init__(self, serviceName: str): + self.__timeout = 1.0 + self.__stub = ClientStub(serviceName) + self.__stub.Init() + + def SetTimeout(self, timeout: float): + self.__timeout = timeout + + def _CallBase(self, apiId: int, parameter: str, proirity: int = 0, leaseId: int = 0): + # print("[CallBase] call apiId:", apiId, ", proirity:", proirity, ", leaseId:", leaseId) + header = self.__SetHeader(apiId, leaseId, proirity, False) + request = Request(header, parameter, []) + + future = self.__stub.SendRequest(request, self.__timeout) + if future is None: + return RPC_ERR_CLIENT_SEND, None + + result = future.GetResult(self.__timeout) + + if result.code != FutureResult.FUTURE_SUCC: + self.__stub.RemoveFuture(request.header.identity.id) + code = RPC_ERR_CLIENT_API_TIMEOUT if result.code == FutureResult.FUTUTE_ERR_TIMEOUT else RPC_ERR_UNKNOWN + return code, None + + response = result.value + + if response.header.identity.api_id != apiId: + return RPC_ERR_CLIENT_API_NOT_MATCH, None + else: + return response.header.status.code, response.data + + def _CallNoReplyBase(self, apiId: int, parameter: str, proirity: int, leaseId: int): + header = self.__SetHeader(apiId, leaseId, proirity, True) + request = Request(header, parameter, []) + + if self.__stub.Send(request, self.__timeout): + return 0 + else: + return RPC_ERR_CLIENT_SEND + + def _CallBinaryBase(self, apiId: int, parameter: list, proirity: int, leaseId: int): + header = self.__SetHeader(apiId, leaseId, proirity, False) + request = Request(header, "", parameter) + + future = self.__stub.SendRequest(request, self.__timeout) + if future is None: + return RPC_ERR_CLIENT_SEND, None + + result = future.GetResult(self.__timeout) + if result.code != FutureResult.FUTURE_SUCC: + self.__stub.RemoveFuture(request.header.identity.id) + code = RPC_ERR_CLIENT_API_TIMEOUT if result.code == FutureResult.FUTUTE_ERR_TIMEOUT else RPC_ERR_UNKNOWN + return code, None + + response = result.value + + if response.header.identity.api_id != apiId: + return RPC_ERR_CLIENT_API_NOT_MATCH, None + else: + return response.header.status.code, response.binary + + def _CallBinaryNoReplyBase(self, apiId: int, parameter: list, proirity: int, leaseId: int): + header = self.__SetHeader(apiId, leaseId, proirity, True) + request = Request(header, "", parameter) + + if self.__stub.Send(request, self.__timeout): + return 0 + else: + return RPC_ERR_CLIENT_SEND + + def __SetHeader(self, apiId: int, leaseId: int, priority: int, noReply: bool): + identity = RequestIdentity(time.monotonic_ns(), apiId) + lease = RequestLease(leaseId) + policy = RequestPolicy(priority, noReply) + return RequestHeader(identity, lease, policy) diff --git a/unitree_sdk2py/rpc/client_stub.py b/unitree_sdk2py/rpc/client_stub.py new file mode 100644 index 0000000..67c2c8f --- /dev/null +++ b/unitree_sdk2py/rpc/client_stub.py @@ -0,0 +1,69 @@ +import time + +from enum import Enum +from threading import Thread, Condition + +from ..idl.unitree_api.msg.dds_ import Request_ as Request +from ..idl.unitree_api.msg.dds_ import Response_ as Response + +from ..core.channel import ChannelFactory +from ..core.channel_name import ChannelType, GetClientChannelName +from .request_future import RequestFuture, RequestFutureQueue + + +""" +" class ClientStub +""" +class ClientStub: + def __init__(self, serviceName: str): + self.__serviceName = serviceName + self.__futureQueue = None + + self.__sendChannel = None + self.__recvChannel = None + + def Init(self): + factory = ChannelFactory() + self.__futureQueue = RequestFutureQueue() + + # create channel + self.__sendChannel = factory.CreateSendChannel(GetClientChannelName(self.__serviceName, ChannelType.SEND), Request) + self.__recvChannel = factory.CreateRecvChannel(GetClientChannelName(self.__serviceName, ChannelType.RECV), Response, + self.__ResponseHandler,10) + time.sleep(0.5) + + + def Send(self, request: Request, timeout: float): + if self.__sendChannel.Write(request, timeout): + return True + else: + print("[ClientStub] send error. id:", request.header.identity.id) + return False + + def SendRequest(self, request: Request, timeout: float): + id = request.header.identity.id + + future = RequestFuture() + future.SetRequestId(id) + self.__futureQueue.Set(id, future) + + if self.__sendChannel.Write(request, timeout): + return future + else: + print("[ClientStub] send request error. id:", request.header.identity.id) + self.__futureQueue.Remove(id) + return None + + def RemoveFuture(self, requestId: int): + self.__futureQueue.Remove(requestId) + + def __ResponseHandler(self, response: Response): + id = response.header.identity.id + # apiId = response.header.identity.api_id + # print("[ClientStub] responseHandler recv response id:", id, ", apiId:", apiId) + future = self.__futureQueue.Get(id) + if future is None: + # print("[ClientStub] get future from queue error. id:", id) + pass + elif not future.Ready(response): + print("[ClientStub] set future ready error.") diff --git a/unitree_sdk2py/rpc/internal.py b/unitree_sdk2py/rpc/internal.py new file mode 100644 index 0000000..875a78b --- /dev/null +++ b/unitree_sdk2py/rpc/internal.py @@ -0,0 +1,31 @@ +# internal api id max +RPC_INTERNAL_API_ID_MAX = 100 + +# internal api id +RPC_API_ID_INTERNAL_API_VERSION = 1 + +# lease api id +RPC_API_ID_LEASE_APPLY = 101 +RPC_API_ID_LEASE_RENEWAL = 102 + +# lease term default +RPC_LEASE_TERM = 1.0 + +# internal error +RPC_OK = 0 +# client error +RPC_ERR_UNKNOWN = 3001 +RPC_ERR_CLIENT_SEND = 3102 +RPC_ERR_CLIENT_API_NOT_REG = 3103 +RPC_ERR_CLIENT_API_TIMEOUT = 3104 +RPC_ERR_CLIENT_API_NOT_MATCH = 3105 +RPC_ERR_CLIENT_API_DATA = 3106 +RPC_ERR_CLIENT_LEASE_INVALID = 3107 +# server error +RPC_ERR_SERVER_SEND = 3201 +RPC_ERR_SERVER_INTERNAL = 3202 +RPC_ERR_SERVER_API_NOT_IMPL = 3203 +RPC_ERR_SERVER_API_PARAMETER = 3204 +RPC_ERR_SERVER_LEASE_DENIED = 3205 +RPC_ERR_SERVER_LEASE_NOT_EXIST = 3206 +RPC_ERR_SERVER_LEASE_EXIST = 3207 diff --git a/unitree_sdk2py/rpc/lease_client.py b/unitree_sdk2py/rpc/lease_client.py new file mode 100644 index 0000000..37f600f --- /dev/null +++ b/unitree_sdk2py/rpc/lease_client.py @@ -0,0 +1,113 @@ +import time +import socket +import os +import json + +from threading import Thread, Lock + +from .client_base import ClientBase +from .internal import * + + +""" +" class LeaseContext +""" +class LeaseContext: + def __init__(self): + self.id = 0 + self.term = RPC_LEASE_TERM + + def Update(self, id, term): + self.id = id + self.term = term + + def Reset(self): + self.id = 0 + self.term = RPC_LEASE_TERM + + def Valid(self): + return self.id != 0 + + +""" +" class LeaseClient +""" +class LeaseClient(ClientBase): + def __init__(self, name: str): + self.__name = name + "_lease" + self.__contextName = socket.gethostname() + "/" + name + "/" + str(os.getpid()) + self.__context = LeaseContext() + self.__thread = None + self.__lock = Lock() + super().__init__(self.__name) + print("[LeaseClient] lease name:", self.__name, ", context name:", self.__contextName) + + def Init(self): + self.SetTimeout(1.0) + self.__thread = Thread(target=self.__ThreadFunc, name=self.__name, daemon=True) + self.__thread.start() + + def WaitApplied(self): + while True: + with self.__lock: + if self.__context.Valid(): + break + time.sleep(0.1) + + def GetId(self): + with self.__lock: + return self.__context.id + + def Applied(self): + with self.__lock: + return self.__context.Valid() + + def __Apply(self): + parameter = {} + parameter["name"] = self.__contextName + p = json.dumps(parameter) + + c, d = self._CallBase(RPC_API_ID_LEASE_APPLY, p) + if c != 0: + print("[LeaseClient] apply lease error. code:", c) + return + + data = json.loads(d) + + id = data["id"] + term = data["term"] + + print("[LeaseClient] lease applied id:", id, ", term:", term) + + with self.__lock: + self.__context.Update(id, float(term/1000000)) + + def __Renewal(self): + parameter = {} + p = json.dumps(parameter) + + c, d = self._CallBase(RPC_API_ID_LEASE_RENEWAL, p, 0, self.__context.id) + if c != 0: + print("[LeaseClient] renewal lease error. code:", c) + if c == RPC_ERR_SERVER_LEASE_NOT_EXIST: + with self.__lock: + self.__context.Reset() + + def __GetWaitSec(self): + waitsec = 0.0 + if self.__context.Valid(): + waitsec = self.__context.term + + if waitsec <= 0: + waitsec = RPC_LEASE_TERM + + return waitsec * 0.3 + + def __ThreadFunc(self): + while True: + if self.__context.Valid(): + self.__Renewal() + else: + self.__Apply() + # sleep waitsec + time.sleep(self.__GetWaitSec()) diff --git a/unitree_sdk2py/rpc/lease_server.py b/unitree_sdk2py/rpc/lease_server.py new file mode 100644 index 0000000..d5b27d1 --- /dev/null +++ b/unitree_sdk2py/rpc/lease_server.py @@ -0,0 +1,151 @@ +import time +import json + +from threading import Lock + +from ..idl.unitree_api.msg.dds_ import Request_ as Request +from ..idl.unitree_api.msg.dds_ import ResponseHeader_ as ResponseHeader +from ..idl.unitree_api.msg.dds_ import ResponseStatus_ as ResponseStatus +from ..idl.unitree_api.msg.dds_ import Response_ as Response + +from .internal import * +from .server_base import ServerBase + + +""" +" class LeaseCache +""" +class LeaseCache: + def __init__(self): + self.lastModified = 0 + self.id = 0 + self.name = None + + def Set(self, id: int, name: str, lastModified: int) : + self.id = id + self.name = name + self.lastModified = lastModified + + def Renewal(self, lastModified: int): + self.lastModified = lastModified + + def Clear(self): + self.id = 0 + self.lastModified = 0 + self.name = None + + +""" +" class LeaseServer +""" +class LeaseServer(ServerBase): + def __init__(self, name: str, term: float): + self.__term = int(term * 1000000) + self.__lock = Lock() + self.__cache = LeaseCache() + super().__init__(name + "_lease") + + def Init(self): + pass + + def Start(self, enablePrioQueue: bool = False): + super()._SetServerRequestHandler(self.__ServerRequestHandler) + super()._Start(enablePrioQueue) + + def CheckRequestLeaseDenied(self, leaseId: int): + with self.__lock: + if self.__cache.id == 0: + return self.__cache.id != leaseId + + now = self.__Now() + if now > self.__cache.lastModified + self.__term: + self.__cache.Clear() + return False + else: + return self.__cache.id != leaseId + + def __Apply(self, parameter: str): + name = "" + data = "" + + try: + p = json.loads(parameter) + name = p.get("name") + + except: + print("[LeaseServer] apply json loads error. parameter:", parameter) + return RPC_ERR_SERVER_API_PARAMETER, data + + if not name: + name = "anonymous" + + id = 0 + lastModified = 0 + setted = False + + now = self.__Now() + + with self.__lock: + id = self.__cache.id + lastModified = self.__cache.lastModified + + if id == 0 or now > lastModified + self.__term: + if id != 0: + print("[LeaseServer] id expired:", id, ", name:", self.__cache.name) + + id = self.__GenerateId() + self.__cache.Set(id, name, now) + setted = True + + print("[LeaseServer] id stored:", id, ", name:", name) + + if setted: + d = {} + d["id"] = id + d["term"] = self.__term + data = json.dumps(d) + return 0, data + else: + return RPC_ERR_SERVER_LEASE_EXIST, data + + + def __Renewal(self, id: int): + now = self.__Now() + + with self.__lock: + if self.__cache.id != id: + return RPC_ERR_SERVER_LEASE_NOT_EXIST + + if now > self.__cache.lastModified + self.__term: + self.__cache.Clear() + return RPC_ERR_SERVER_LEASE_NOT_EXIST + else: + self.__cache.Renewal(now) + return 0 + + def __ServerRequestHandler(self, request: Request): + identity = request.header.identity + parameter = request.parameter + apiId = identity.api_id + code = RPC_ERR_SERVER_API_NOT_IMPL + data = "" + + if apiId == RPC_API_ID_LEASE_APPLY: + code, data = self.__Apply(parameter) + elif apiId == RPC_API_ID_LEASE_RENEWAL: + code = self.__Renewal(request.header.lease.id) + else: + print("[LeaseServer] api is not implemented. apiId", apiId) + + if request.header.policy.noreply: + return + + status = ResponseStatus(code) + response = Response(ResponseHeader(identity, status), data, []) + self._SendResponse(response) + + def __GenerateId(self): + return self.__Now() + + def __Now(self): + return int(time.time_ns()/1000) \ No newline at end of file diff --git a/unitree_sdk2py/rpc/request_future.py b/unitree_sdk2py/rpc/request_future.py new file mode 100644 index 0000000..037ab10 --- /dev/null +++ b/unitree_sdk2py/rpc/request_future.py @@ -0,0 +1,46 @@ +from threading import Condition, Lock +from enum import Enum + +from ..idl.unitree_api.msg.dds_ import Response_ as Response +from ..utils.future import Future, FutureResult + + +""" +" class RequestFuture +""" +class RequestFuture(Future): + def __init__(self): + self.__requestId = None + super().__init__() + + def SetRequestId(self, requestId: int): + self.__requestId = requestId + + def GetRequestId(self): + return self.__requestId + + +class RequestFutureQueue: + def __init__(self): + self.__data = {} + self.__lock = Lock() + + def Set(self, requestId: int, future: RequestFuture): + if future is None: + return False + with self.__lock: + self.__data[requestId] = future + return True + + def Get(self, requestId: int): + future = None + with self.__lock: + future = self.__data.get(requestId) + if future is not None: + self.__data.pop(requestId) + return future + + def Remove(self, requestId: int): + with self.__lock: + if id in self.__data: + self.__data.pop(requestId) \ No newline at end of file diff --git a/unitree_sdk2py/rpc/server.py b/unitree_sdk2py/rpc/server.py new file mode 100644 index 0000000..4e389a8 --- /dev/null +++ b/unitree_sdk2py/rpc/server.py @@ -0,0 +1,122 @@ +import time + +from typing import Callable, Any + +from ..idl.unitree_api.msg.dds_ import Request_ as Request +from ..idl.unitree_api.msg.dds_ import ResponseStatus_ as ResponseStatus +from ..idl.unitree_api.msg.dds_ import ResponseHeader_ as ResponseHeader +from ..idl.unitree_api.msg.dds_ import Response_ as Response + +from .server_base import ServerBase +from .lease_server import LeaseServer +from .internal import * + +""" +" class Server +""" +class Server(ServerBase): + def __init__(self, name: str): + self.__apiVersion = "" + self.__apiHandlerMapping = {} + self.__apiBinaryHandlerMapping = {} + self.__apiBinarySet = {} + self.__enableLease = False + self.__leaseServer = None + super().__init__(name) + + def Init(self): + pass + + def StartLease(self, term: float = 1.0): + self.__enableLease = True + self.__leaseServer = LeaseServer(self.GetName(), term) + self.__leaseServer.Init() + self.__leaseServer.Start(False) + + def Start(self, enablePrioQueue: bool = False): + super()._SetServerRequestHandler(self.__ServerRequestHandler) + super()._Start(enablePrioQueue) + + def GetApiVersion(self): + return self.__apiVersion + + def _SetApiVersion(self, apiVersion: str): + self.__apiVersion = apiVersion + print("[Server] set api version:", self.__apiVersion) + + def _RegistHandler(self, apiId: int, handler: Callable, checkLease: bool): + self.__apiHandlerMapping[apiId] = (handler, checkLease) + + def _RegistBinaryHandler(self, apiId: int, handler: Callable, checkLease: bool): + self.__apiBinaryHandlerMapping[apiId] = (handler, checkLease) + self.__apiBinarySet.add(apiId) + + def __GetHandler(self, apiId: int): + if apiId in self.__apiHandlerMapping: + return self.__apiHandlerMapping.get(apiId) + else: + return None, False + + def __GetBinaryHandler(self, apiId: int): + if apiId in self.__apiBinaryHandlerMapping: + return self.__apiBinaryHandlerMapping.get(apiId) + else: + return None, False + + def __IsBinary(self, apiId): + return apiId in self.__apiBinarySet + + def __CheckLeaseDenied(self, leaseId: int): + if (self.__enableLease): + return self.__leaseServer.CheckRequestLeaseDenied(leaseId) + else: + return False + + def __ServerRequestHandler(self, request: Request): + parameter = request.parameter + parameterBinary = request.binary + + identity = request.header.identity + leaseId = request.header.lease.id + apiId = identity.api_id + + code = 0 + data = "" + dataBinary = [] + + if apiId == RPC_API_ID_INTERNAL_API_VERSION: + data = self.__apiVersion + else: + requestHandler = None + binaryRequestHandler = None + checkLease = False + + if self.__IsBinary(apiId): + binaryRequestHandler, checkLease = self.__GetBinaryHandler(apiId) + else: + requestHandler, checkLease = self.__GetHandler(apiId) + + if requestHandler is None and binaryRequestHandler is None: + code = RPC_ERR_SERVER_API_NOT_IMPL + elif checkLease and self.__CheckLeaseDenied(leaseId): + code = RPC_ERR_SERVER_LEASE_DENIED + else: + try: + if binaryRequestHandler is None: + code, data = requestHandler(parameter) + if code != 0: + data = "" + else: + code, dataBinary = binaryRequestHandler(parameterBinary) + if code != 0: + dataBinary = [] + except: + code = RPC_ERR_SERVER_INTERNAL + + if request.header.policy.noreply: + return + + status = ResponseStatus(code) + response = Response(ResponseHeader(identity, status), data, dataBinary) + + self._SendResponse(response) \ No newline at end of file diff --git a/unitree_sdk2py/rpc/server_base.py b/unitree_sdk2py/rpc/server_base.py new file mode 100644 index 0000000..f010561 --- /dev/null +++ b/unitree_sdk2py/rpc/server_base.py @@ -0,0 +1,32 @@ +import time + +from typing import Callable, Any + +from ..idl.unitree_api.msg.dds_ import Request_ as Request +from ..idl.unitree_api.msg.dds_ import Response_ as Response + +from .server_stub import ServerStub + + +""" +" class ServerBase +""" +class ServerBase: + def __init__(self, name: str): + self.__name = name + self.__serverRequestHandler = None + self.__serverStub = ServerStub(self.__name) + + def GetName(self): + return self.__name + + def _Start(self, enablePrioQueue: bool = False): + self.__serverStub.Init(self.__serverRequestHandler, enablePrioQueue) + print("[ServerBase] server started. name:", self.__name, ", enable proirity queue:", enablePrioQueue) + + def _SetServerRequestHandler(self, serverRequestHandler: Callable): + self.__serverRequestHandler = serverRequestHandler + + def _SendResponse(self, response: Response): + if not self.__serverStub.Send(response, 1.0): + print("[ServerBase] send response error.") diff --git a/unitree_sdk2py/rpc/server_stub.py b/unitree_sdk2py/rpc/server_stub.py new file mode 100644 index 0000000..e67be1f --- /dev/null +++ b/unitree_sdk2py/rpc/server_stub.py @@ -0,0 +1,78 @@ +import time + +from enum import Enum +from threading import Thread, Condition +from typing import Callable, Any + +from ..utils.bqueue import BQueue +from ..idl.unitree_api.msg.dds_ import Request_ as Request +from ..idl.unitree_api.msg.dds_ import Response_ as Response + +from ..core.channel import ChannelFactory +from ..core.channel_name import ChannelType, GetServerChannelName + + +""" +" class ServerStub +""" +class ServerStub: + def __init__(self, serviceName: str): + self.__serviceName = serviceName + self.__serverRquestHandler = None + self.__sendChannel = None + self.__recvChannel = None + self.__enablePriority = None + self.__queue = None + self.__prioQueue = None + self.__queueThread = None + self.__prioQueueThread = None + + def Init(self, serverRequestHander: Callable, enablePriority: bool = False): + self.__serverRquestHandler = serverRequestHander + self.__enablePriority = enablePriority + + factory = ChannelFactory() + + # create channel + self.__sendChannel = factory.CreateSendChannel(GetServerChannelName(self.__serviceName, ChannelType.SEND), Response) + self.__recvChannel = factory.CreateRecvChannel(GetServerChannelName(self.__serviceName, ChannelType.RECV), Request, self.__Enqueue, 10) + + # start priority request thread + self.__queue = BQueue(10) + self.__queueThread = Thread(target=self.__QueueThreadFunc, name="server_queue", daemon=True) + self.__queueThread.start() + + if enablePriority: + self.__prioQueue = BQueue(5) + self.__prioQueueThread = Thread(target=self.__PrioQueueThreadFunc, name="server_prio_queue", daemon=True) + self.__prioQueueThread.start() + + # wait thread started + time.sleep(0.5) + + def Send(self, response: Response, timeout: float): + if self.__sendChannel.Write(response, timeout): + return True + else: + print("[ServerStub] send error. id:", response.header.identity.id) + return False + + def __Enqueue(self, request: Request): + if self.__enablePriority and request.header.policy.priority > 0: + self.__prioQueue.Put(request, True) + else: + self.__queue.Put(request, True) + + def __QueueThreadFunc(self): + while True: + request = self.__queue.Get() + if request is None: + continue + self.__serverRquestHandler(request) + + def __PrioQueueThreadFunc(self): + while True: + request = self.__prioQueue.Get() + if request is None: + continue + self.__serverRquestHandler(request) diff --git a/unitree_sdk2py/test/client/obstacles_avoid_client_example.py b/unitree_sdk2py/test/client/obstacles_avoid_client_example.py new file mode 100644 index 0000000..7936fe7 --- /dev/null +++ b/unitree_sdk2py/test/client/obstacles_avoid_client_example.py @@ -0,0 +1,91 @@ +import time +import os + +from unitree_sdk2py.core.channel import ChannelFactoryInitialize +from unitree_sdk2py.go2.obstacles_avoid.obstacles_avoid_client import ObstaclesAvoidClient + +if __name__ == "__main__": + ChannelFactoryInitialize(0, "enp3s0") + + client = ObstaclesAvoidClient() + client.SetTimeout(3.0) + client.Init() + + while True: + print("##################GetServerApiVersion###################") + code, serverAPiVersion = client.GetServerApiVersion() + if code != 0: + print("get server api error. code:", code) + else: + print("get server api version:", serverAPiVersion) + + if serverAPiVersion != client.GetApiVersion(): + print("api version not equal.") + + time.sleep(3) + + print("##################SwitchGet###################") + code, enable = client.SwitchGet() + if code != 0: + print("switch get error. code:", code) + else: + print("switch get success. enable:", enable) + + time.sleep(3) + + print("##################SwitchSet (on)###################") + code = client.SwitchSet(True) + if code != 0: + print("switch set error. code:", code) + else: + print("switch set success.") + + time.sleep(3) + + print("##################SwitchGet###################") + code, enable1 = client.SwitchGet() + if code != 0: + print("switch get error. code:", code) + else: + print("switch get success. enable:", enable1) + + time.sleep(3) + + print("##################SwitchSet (off)###################") + code = client.SwitchSet(False) + if code != 0: + print("switch set error. code:", code) + else: + print("switch set success.") + + time.sleep(3) + + print("##################SwitchGet###################") + code, enable1 = client.SwitchGet() + if code != 0: + print("switch get error. code:", code) + else: + print("switch get success. enable:", enable1) + + time.sleep(3) + + + print("##################SwitchSet (enable)###################") + + code = client.SwitchSet(enable) + if code != 0: + print("switch set error. code:", code) + else: + print("switch set success. enable:", enable) + + time.sleep(3) + + print("##################SwitchGet###################") + code, enable = client.SwitchGet() + if code != 0: + print("switch get error. code:", code) + else: + print("switch get success. enable:", enable) + + time.sleep(3) + \ No newline at end of file diff --git a/unitree_sdk2py/test/client/robot_service_client_example.py b/unitree_sdk2py/test/client/robot_service_client_example.py new file mode 100644 index 0000000..01467c0 --- /dev/null +++ b/unitree_sdk2py/test/client/robot_service_client_example.py @@ -0,0 +1,50 @@ +import time +from unitree_sdk2py.core.channel import ChannelFactoryInitialize +from unitree_sdk2py.go2.robot_state.robot_state_client import RobotStateClient + +if __name__ == "__main__": + ChannelFactoryInitialize(0, "enx000ec6768747") + rsc = RobotStateClient() + rsc.SetTimeout(3.0) + rsc.Init() + + while True: + print("##################GetServerApiVersion###################") + code, serverAPiVersion = rsc.GetServerApiVersion() + + if code != 0: + print("get server api error. code:", code) + else: + print("get server api version:", serverAPiVersion) + + time.sleep(3) + + print("##################ServiceList###################") + code, lst = rsc.ServiceList() + + if code != 0: + print("list sevrice error. code:", code) + else: + print("list service success. len:", len(lst)) + for s in lst: + print("name:", s.name, ", protect:", s.protect, ", status:", s.status) + + time.sleep(3) + + print("##################ServiceSwitch###################") + code = rsc.ServiceSwitch("sport_mode", False) + if code != 0: + print("service stop sport_mode error. code:", code) + else: + print("service stop sport_mode success. code:", code) + + time.sleep(1) + + code = rsc.ServiceSwitch("sport_mode", True) + if code != 0: + print("service start sport_mode error. code:", code) + else: + print("service start sport_mode success. code:", code) + + time.sleep(3) + diff --git a/unitree_sdk2py/test/client/sport_client_example.py b/unitree_sdk2py/test/client/sport_client_example.py new file mode 100644 index 0000000..22a8de0 --- /dev/null +++ b/unitree_sdk2py/test/client/sport_client_example.py @@ -0,0 +1,109 @@ +import time +from unitree_sdk2py.core.channel import ChannelFactoryInitialize +from unitree_sdk2py.go2.sport.sport_client import SportClient, PathPoint, SPORT_PATH_POINT_SIZE + +if __name__ == "__main__": + ChannelFactoryInitialize(0, "enp2s0") + client = SportClient() + client.SetTimeout(10.0) + client.Init() + + print("##################GetServerApiVersion###################") + code, serverAPiVersion = client.GetServerApiVersion() + if code != 0: + print("get server api error. code:", code) + else: + print("get server api version:", serverAPiVersion) + + if serverAPiVersion != client.GetApiVersion(): + print("api version not equal.") + + time.sleep(3) + + print("##################Trigger###################") + code = client.Trigger() + if code != 0: + print("sport trigger error. code:", code) + else: + print("sport trigger success.") + + time.sleep(3) + + while True: + print("##################RecoveryStand###################") + code = client.RecoveryStand() + + if code != 0: + print("sport recovery stand error. code:", code) + else: + print("sport recovery stand success.") + + time.sleep(3) + + print("##################StandDown###################") + code = client.StandDown() + if code != 0: + print("sport stand down error. code:", code) + else: + print("sport stand down success.") + + time.sleep(3) + + print("##################Damp###################") + code = client.Damp() + if code != 0: + print("sport damp error. code:", code) + else: + print("sport damp down success.") + + time.sleep(3) + + print("##################RecoveryStand###################") + code = client.RecoveryStand() + + if code != 0: + print("sport recovery stand error. code:", code) + else: + print("sport recovery stand success.") + + time.sleep(3) + + print("##################Sit###################") + code = client.Sit() + if code != 0: + print("sport stand down error. code:", code) + else: + print("sport stand down success.") + + time.sleep(3) + + print("##################RiseSit###################") + code = client.RiseSit() + + if code != 0: + print("sport rise sit error. code:", code) + else: + print("sport rise sit success.") + + time.sleep(3) + + print("##################SetBodyHight###################") + code = client.BodyHeight(0.18) + + if code != 0: + print("sport body hight error. code:", code) + else: + print("sport body hight success.") + + time.sleep(3) + + print("##################GetState#################") + keys = ["state", "bodyHeight", "footRaiseHeight", "speedLevel", "gait"] + code, data = client.GetState(keys) + + if code != 0: + print("sport get state error. code:", code) + else: + print("sport get state success. data:", data) + + time.sleep(3) diff --git a/unitree_sdk2py/test/client/video_client_example.py b/unitree_sdk2py/test/client/video_client_example.py new file mode 100644 index 0000000..7eec949 --- /dev/null +++ b/unitree_sdk2py/test/client/video_client_example.py @@ -0,0 +1,26 @@ +import time +import os + +from unitree_sdk2py.core.channel import ChannelFactoryInitialize +from unitree_sdk2py.go2.video.video_client import VideoClient + +if __name__ == "__main__": + ChannelFactoryInitialize(0, "enp2s0") + + client = VideoClient() + client.SetTimeout(3.0) + client.Init() + + print("##################GetImageSample###################") + code, data = client.GetImageSample() + + if code != 0: + print("get image sample error. code:", code) + else: + imageName = os.path.dirname(__file__) + time.strftime('/%Y%m%d%H%M%S.jpg',time.localtime()) + print("ImageName:", imageName) + + with open(imageName, "+wb") as f: + f.write(bytes(data)) + + time.sleep(1) diff --git a/unitree_sdk2py/test/client/vui_client_example.py b/unitree_sdk2py/test/client/vui_client_example.py new file mode 100644 index 0000000..6df7c09 --- /dev/null +++ b/unitree_sdk2py/test/client/vui_client_example.py @@ -0,0 +1,74 @@ +import time +import os + +from unitree_sdk2py.core.channel import ChannelFactoryInitialize +from unitree_sdk2py.go2.vui.vui_client import VuiClient + +if __name__ == "__main__": + ChannelFactoryInitialize(0, "enp2s0") + + client = VuiClient() + client.SetTimeout(3.0) + client.Init() + + for i in range(1, 11): + print("#################GetBrightness####################") + code, level = client.GetBrightness() + + if code != 0: + print("get brightness error. code:", code) + else: + print("get brightness success. level:", level) + + time.sleep(1) + + print("#################SetBrightness####################") + + code = client.SetBrightness(i) + + if code != 0: + print("set brightness error. code:", code) + else: + print("set brightness success. level:", i) + + time.sleep(1) + + print("#################SetBrightness 0####################") + + code = client.SetBrightness(0) + + if code != 0: + print("set brightness error. code:", code) + else: + print("set brightness 0 success.") + + for i in range(1, 11): + print("#################GetVolume####################") + code, level = client.GetVolume() + + if code != 0: + print("get volume error. code:", code) + else: + print("get volume success. level:", level) + + time.sleep(1) + + print("#################SetVolume####################") + + code = client.SetVolume(i) + + if code != 0: + print("set volume error. code:", code) + else: + print("set volume success. level:", i) + + time.sleep(1) + + print("#################SetVolume 0####################") + + code = client.SetVolume(0) + + if code != 0: + print("set volume error. code:", code) + else: + print("set volume 0 success.") diff --git a/unitree_sdk2py/test/crc/test_crc.py b/unitree_sdk2py/test/crc/test_crc.py new file mode 100644 index 0000000..ceb1b4b --- /dev/null +++ b/unitree_sdk2py/test/crc/test_crc.py @@ -0,0 +1,27 @@ +from unitree_sdk2py.idl.default import unitree_go_msg_dds__LowCmd_, unitree_go_msg_dds__LowState_ +from unitree_sdk2py.idl.default import unitree_hg_msg_dds__LowCmd_, unitree_hg_msg_dds__LowState_ +from unitree_sdk2py.utils.crc import CRC + +crc = CRC() + +""" +" LowCmd/LowState CRC +""" +cmd = unitree_go_msg_dds__LowCmd_() +cmd.crc = crc.Crc(cmd) + +state = unitree_go_msg_dds__LowState_() +state.crc = crc.Crc(state) + +print("CRC[LowCmd, LowState]: {}, {}".format(cmd.crc, state.crc)) + +""" +" LowCmd/LowState for HG CRC. () +""" +cmd = unitree_hg_msg_dds__LowCmd_() +cmd.crc = crc.Crc(cmd) + +state = unitree_hg_msg_dds__LowState_() +state.crc = crc.Crc(state) + +print("CRC[HGLowCmd, HGLowState]: {}, {}".format(cmd.crc, state.crc)) diff --git a/unitree_sdk2py/test/helloworld/helloworld.py b/unitree_sdk2py/test/helloworld/helloworld.py new file mode 100644 index 0000000..7e93803 --- /dev/null +++ b/unitree_sdk2py/test/helloworld/helloworld.py @@ -0,0 +1,6 @@ +from dataclasses import dataclass +from cyclonedds.idl import IdlStruct + +@dataclass +class HelloWorld(IdlStruct, typename="HelloWorld"): + data: str \ No newline at end of file diff --git a/unitree_sdk2py/test/helloworld/publisher.py b/unitree_sdk2py/test/helloworld/publisher.py new file mode 100644 index 0000000..36e8fb8 --- /dev/null +++ b/unitree_sdk2py/test/helloworld/publisher.py @@ -0,0 +1,22 @@ +import time + +from unitree_sdk2py.core.channel import ChannelPublisher, ChannelFactoryInitialize +from helloworld import HelloWorld + +ChannelFactoryInitialize() + +pub = ChannelPublisher("topic", HelloWorld) +pub.Init() + +for i in range(30): + msg = HelloWorld("Hello world. time:" + str(time.time())) + # msg.data = "Hello world. time:" + str(time.time()) + + if pub.Write(msg, 0.5): + print("publish success. msg:", msg) + else: + print("publish error.") + + time.sleep(1) + +pub.Close() \ No newline at end of file diff --git a/unitree_sdk2py/test/helloworld/subscriber.py b/unitree_sdk2py/test/helloworld/subscriber.py new file mode 100644 index 0000000..38e4763 --- /dev/null +++ b/unitree_sdk2py/test/helloworld/subscriber.py @@ -0,0 +1,19 @@ +import time + +from unitree_sdk2py.core.channel import ChannelSubscriber, ChannelFactoryInitialize +from helloworld import HelloWorld + +ChannelFactoryInitialize() + +sub = ChannelSubscriber("topic", HelloWorld) +sub.Init() + +while True: + msg = sub.Read() + + if msg is None: + print("subscribe error.") + else: + print("subscribe success. msg:", msg) + +pub.Close() \ No newline at end of file diff --git a/unitree_sdk2py/test/lowlevel/lowlevel_control.py b/unitree_sdk2py/test/lowlevel/lowlevel_control.py new file mode 100644 index 0000000..8e94fe1 --- /dev/null +++ b/unitree_sdk2py/test/lowlevel/lowlevel_control.py @@ -0,0 +1,51 @@ +import time + +from unitree_sdk2py.core.channel import ChannelPublisher, ChannelFactoryInitialize +from unitree_sdk2py.core.channel import ChannelSubscriber, ChannelFactoryInitialize +from unitree_sdk2py.idl.default import unitree_go_msg_dds__LowCmd_ +from unitree_sdk2py.idl.unitree_go.msg.dds_ import LowCmd_ +from unitree_sdk2py.utils.crc import CRC +from unitree_sdk2py.utils.thread import Thread +import unitree_go2_const as go2 + +crc = CRC() +lowCmdThreadPtr=Thread() + +if __name__ == '__main__': + + ChannelFactoryInitialize(1, "enp2s0") + # Create a publisher to publish the data defined in UserData class + pub = ChannelPublisher("lowcmd", LowCmd_) + pub.Init() + + while True: + # Create a Userdata message + cmd = unitree_go_msg_dds__LowCmd_() + + # Toque controle, set RL_2 toque + cmd.motor_cmd[go2.LegID["RL_2"]].mode = 0x01 + cmd.motor_cmd[go2.LegID["RL_2"]].q = go2.PosStopF # Set to stop position(rad) + cmd.motor_cmd[go2.LegID["RL_2"]].kp = 0 + cmd.motor_cmd[go2.LegID["RL_2"]].dq = go2.VelStopF # Set to stop angular velocity(rad/s) + cmd.motor_cmd[go2.LegID["RL_2"]].kd = 0 + cmd.motor_cmd[go2.LegID["RL_2"]].tau = 1 # target toque is set to 1N.m + + # Poinstion(rad) control, set RL_0 rad + cmd.motor_cmd[go2.LegID["RL_0"]].mode = 0x01 + cmd.motor_cmd[go2.LegID["RL_0"]].q = 0 # Taregt angular(rad) + cmd.motor_cmd[go2.LegID["RL_0"]].kp = 10 # Poinstion(rad) control kp gain + cmd.motor_cmd[go2.LegID["RL_0"]].dq = 0 # Taregt angular velocity(rad/ss) + cmd.motor_cmd[go2.LegID["RL_0"]].kd = 1 # Poinstion(rad) control kd gain + cmd.motor_cmd[go2.LegID["RL_0"]].tau = 0 # Feedforward toque 1N.m + + cmd.crc = crc.Crc(cmd) + + #Publish message + if pub.Write(cmd): + print("Publish success. msg:", cmd.crc) + else: + print("Waitting for subscriber.") + + time.sleep(0.002) + + pub.Close() diff --git a/unitree_sdk2py/test/lowlevel/read_lowstate.py b/unitree_sdk2py/test/lowlevel/read_lowstate.py new file mode 100644 index 0000000..d3f20ca --- /dev/null +++ b/unitree_sdk2py/test/lowlevel/read_lowstate.py @@ -0,0 +1,24 @@ +import time +from unitree_sdk2py.core.channel import ChannelSubscriber, ChannelFactoryInitialize +from unitree_sdk2py.idl.default import unitree_go_msg_dds__LowState_ +from unitree_sdk2py.idl.unitree_go.msg.dds_ import LowState_ + +import unitree_go2_const as go2 + + +def LowStateHandler(msg: LowState_): + + # print front right hip motor states + print("FR_0 motor state: ", msg.motor_state[go2.LegID["FR_0"]]) + print("IMU state: ", msg.imu_state) + print("Battery state: voltage: ", msg.power_v, "current: ", msg.power_a) + + +if __name__ == "__main__": + # Modify "enp2s0" to the actual network interface + ChannelFactoryInitialize(0, "enp2s0") + sub = ChannelSubscriber("rt/lowstate", LowState_) + sub.Init(LowStateHandler, 10) + + while True: + time.sleep(10.0) diff --git a/unitree_sdk2py/test/lowlevel/sub_lowstate.py b/unitree_sdk2py/test/lowlevel/sub_lowstate.py new file mode 100644 index 0000000..9a94619 --- /dev/null +++ b/unitree_sdk2py/test/lowlevel/sub_lowstate.py @@ -0,0 +1,15 @@ +import time +from unitree_sdk2py.core.channel import ChannelSubscriber, ChannelFactoryInitialize +from unitree_sdk2py.idl.default import unitree_go_msg_dds__LowState_ +from unitree_sdk2py.idl.unitree_go.msg.dds_ import LowState_ + +def LowStateHandler(msg: LowState_): + print(msg.motor_state) + + +ChannelFactoryInitialize(0, "enp2s0") +sub = ChannelSubscriber("rt/lowstate", LowState_) +sub.Init(LowStateHandler, 10) + +while True: + time.sleep(10.0) \ No newline at end of file diff --git a/unitree_sdk2py/test/lowlevel/unitree_go2_const.py b/unitree_sdk2py/test/lowlevel/unitree_go2_const.py new file mode 100644 index 0000000..153a051 --- /dev/null +++ b/unitree_sdk2py/test/lowlevel/unitree_go2_const.py @@ -0,0 +1,20 @@ +LegID = { + "FR_0": 0, # Front right hip + "FR_1": 1, # Front right thigh + "FR_2": 2, # Front right calf + "FL_0": 3, + "FL_1": 4, + "FL_2": 5, + "RR_0": 6, + "RR_1": 7, + "RR_2": 8, + "RL_0": 9, + "RL_1": 10, + "RL_2": 11, +} + +HIGHLEVEL = 0xEE +LOWLEVEL = 0xFF +TRIGERLEVEL = 0xF0 +PosStopF = 2.146e9 +VelStopF = 16000.0 diff --git a/unitree_sdk2py/test/rpc/test_api.py b/unitree_sdk2py/test/rpc/test_api.py new file mode 100644 index 0000000..68778ca --- /dev/null +++ b/unitree_sdk2py/test/rpc/test_api.py @@ -0,0 +1,9 @@ +# service name +TEST_SERVICE_NAME = "test" + +# api version +TEST_API_VERSION = "1.0.0.1" + +# api id +TEST_API_ID_MOVE = 1008 +TEST_API_ID_STOP = 1002 \ No newline at end of file diff --git a/unitree_sdk2py/test/rpc/test_client_example.py b/unitree_sdk2py/test/rpc/test_client_example.py new file mode 100644 index 0000000..35c6ad4 --- /dev/null +++ b/unitree_sdk2py/test/rpc/test_client_example.py @@ -0,0 +1,62 @@ +import time +import json + +from unitree_sdk2py.core.channel import ChannelFactoryInitialize +from unitree_sdk2py.rpc.client import Client + +from test_api import * + +""" +" class TestClient +""" +class TestClient(Client): + def __init__(self, enableLease: bool = False): + super().__init__("test", enableLease) + + def Init(self): + self._RegistApi(TEST_API_ID_MOVE, 0) + self._RegistApi(TEST_API_ID_STOP, 1) + self._SetApiVerson(TEST_API_VERSION) + + def Move(self, vx: float, vy: float, vyaw: float): + parameter = {} + parameter["vx"] = vx + parameter["vy"] = vy + parameter["vyaw"] = vyaw + p = json.dumps(parameter) + + c, d = self._Call(TEST_API_ID_MOVE, p) + return c + + def Stop(self): + parameter = {} + p = json.dumps(parameter) + + c, d = self._Call(TEST_API_ID_STOP, p) + return c + +if __name__ == "__main__": + # initialize channel factory. + ChannelFactoryInitialize(0) + + # create client + client = TestClient(True) + client.Init() + client.SetTimeout(5.0) + + # get server version + code, serverApiVersion = client.GetServerApiVersion() + print("server api version:", serverApiVersion) + + # wait lease applied + client.WaitLeaseApplied() + + # test api + while True: + code = client.Move(0.2, 0, 0) + print("client move ret:", code) + time.sleep(1.0) + + code = client.Stop() + print("client stop ret:", code) + time.sleep(1.0) diff --git a/unitree_sdk2py/test/rpc/test_server_example.py b/unitree_sdk2py/test/rpc/test_server_example.py new file mode 100644 index 0000000..a929e01 --- /dev/null +++ b/unitree_sdk2py/test/rpc/test_server_example.py @@ -0,0 +1,45 @@ +import time +import json + +from unitree_sdk2py.core.channel import ChannelFactoryInitialize +from unitree_sdk2py.rpc.server import Server + +from test_api import * + + +""" +" class TestServer +""" +class TestServer(Server): + def __init__(self): + super().__init__("test") + + def Init(self): + self._RegistHandler(TEST_API_ID_MOVE, self.Move, 1) + self._RegistHandler(TEST_API_ID_STOP, self.Stop, 0) + self._SetApiVersion(TEST_API_VERSION) + + def Move(self, parameter: str): + p = json.loads(parameter) + x = p["vx"] + y = p["vy"] + yaw = p["vyaw"] + print("Move Called. vx:", x, ", vy:", y, ", vyaw:", yaw) + return 0, "" + + def Stop(self, parameter: str): + print("Stop Called.") + return 0, "" + +if __name__ == "__main__": + # initialize channel factory. + ChannelFactoryInitialize(0) + + # create server + server = TestServer() + server.Init() + server.StartLease(1.0) + server.Start(False) + + while True: + time.sleep(10) \ No newline at end of file diff --git a/unitree_sdk2py/utils/__init__.py b/unitree_sdk2py/utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/unitree_sdk2py/utils/bqueue.py b/unitree_sdk2py/utils/bqueue.py new file mode 100644 index 0000000..a612bfb --- /dev/null +++ b/unitree_sdk2py/utils/bqueue.py @@ -0,0 +1,58 @@ +from typing import Any +from collections import deque +from threading import Condition + +class BQueue: + def __init__(self, maxLen: int = 10): + self.__curLen = 0 + self.__maxLen = maxLen + self.__queue = deque() + self.__condition = Condition() + + def Put(self, x: Any, replace: bool = False): + noReplaced = True + with self.__condition: + if self.__curLen >= self.__maxLen: + if not replace: + return False + else: + noReplaced = False + self.__queue.popleft() + self.__curLen -= 1 + + self.__queue.append(x) + self.__curLen += 1 + self.__condition.notify() + + return noReplaced + + def Get(self, timeout: float = None): + with self.__condition: + if not self.__queue: + try: + self.__condition.wait(timeout) + except: + return None + + if not self.__queue: + return None + + self.__curLen -= 1 + return self.__queue.popleft() + + def Clear(self): + with self.__condition: + if self.__queue: + self.__queue.clear() + self.__curLen = 0 + + def Size(self): + with self.__condition: + return self.__curLen + + def Interrupt(self, notifyAll: bool = False): + with self.__condition: + if notifyAll: + self.__condition.notify() + else: + self.__condition.notify_all() diff --git a/unitree_sdk2py/utils/clib_lookup.py b/unitree_sdk2py/utils/clib_lookup.py new file mode 100644 index 0000000..ca7073d --- /dev/null +++ b/unitree_sdk2py/utils/clib_lookup.py @@ -0,0 +1,17 @@ +import os +import ctypes + +clib = ctypes.CDLL(None, use_errno=True) + +def CLIBCheckError(ret, func, args): + if ret < 0: + code = ctypes.get_errno() + raise OSError(code, os.strerror(code)) + return ret + +def CLIBLookup(name, resType, argTypes): + func = clib[name] + func.restye = resType + func.argtypes = argTypes + func.errcheck = CLIBCheckError + return func diff --git a/unitree_sdk2py/utils/crc.py b/unitree_sdk2py/utils/crc.py new file mode 100644 index 0000000..c250706 --- /dev/null +++ b/unitree_sdk2py/utils/crc.py @@ -0,0 +1,228 @@ +import struct +import cyclonedds +import cyclonedds.idl as idl + +from .singleton import Singleton +from ..idl.unitree_go.msg.dds_ import LowCmd_ +from ..idl.unitree_go.msg.dds_ import LowState_ + +from ..idl.unitree_hg.msg.dds_ import LowCmd_ as HGLowCmd_ +from ..idl.unitree_hg.msg.dds_ import LowState_ as HGLowState_ +import ctypes +import os +import platform + +class CRC(Singleton): + def __init__(self): + #4 bytes aligned, little-endian format. + #size 812 + self.__packFmtLowCmd = '<4B4IH2x' + 'B3x5f3I' * 20 + '4B' + '55Bx2I' + #size 1180 + self.__packFmtLowState = '<4B4IH2x' + '13fb3x' + 'B3x7fb3x3I' * 20 + '4BiH4b15H' + '8hI41B3xf2b2x2f4h2I' + #size 1004 + self.__packFmtHGLowCmd = '<2B2x' + 'B3x5fI' * 35 + '5I' + #size 2092 + self.__packFmtHGLowState = '<2I2B2xI' + '13fh2x' + 'B3x4f2hf7I' * 35 + '40B5I' + + + script_dir = os.path.dirname(os.path.abspath(__file__)) + self.platform = platform.system() + if self.platform == "Linux": + if platform.machine()=="x86_64": + self.crc_lib = ctypes.CDLL(script_dir + '/lib/crc_amd64.so') + elif platform.machine()=="aarch64": + self.crc_lib = ctypes.CDLL(script_dir + '/lib/crc_aarch64.so') + + self.crc_lib.crc32_core.argtypes = (ctypes.POINTER(ctypes.c_uint32), ctypes.c_uint32) + self.crc_lib.crc32_core.restype = ctypes.c_uint32 + + def Crc(self, msg: idl.IdlStruct): + if msg.__idl_typename__ == 'unitree_go.msg.dds_.LowCmd_': + return self.__Crc32(self.__PackLowCmd(msg)) + elif msg.__idl_typename__ == 'unitree_go.msg.dds_.LowState_': + return self.__Crc32(self.__PackLowState(msg)) + if msg.__idl_typename__ == 'unitree_hg.msg.dds_.LowCmd_': + return self.__Crc32(self.__PackHGLowCmd(msg)) + elif msg.__idl_typename__ == 'unitree_hg.msg.dds_.LowState_': + return self.__Crc32(self.__PackHGLowState(msg)) + else: + raise TypeError('unknown IDL message type to crc') + + def __PackLowCmd(self, cmd: LowCmd_): + origData = [] + origData.extend(cmd.head) + origData.append(cmd.level_flag) + origData.append(cmd.frame_reserve) + origData.extend(cmd.sn) + origData.extend(cmd.version) + origData.append(cmd.bandwidth) + + for i in range(20): + origData.append(cmd.motor_cmd[i].mode) + origData.append(cmd.motor_cmd[i].q) + origData.append(cmd.motor_cmd[i].dq) + origData.append(cmd.motor_cmd[i].tau) + origData.append(cmd.motor_cmd[i].kp) + origData.append(cmd.motor_cmd[i].kd) + origData.extend(cmd.motor_cmd[i].reserve) + + origData.append(cmd.bms_cmd.off) + origData.extend(cmd.bms_cmd.reserve) + + origData.extend(cmd.wireless_remote) + origData.extend(cmd.led) + origData.extend(cmd.fan) + origData.append(cmd.gpio) + origData.append(cmd.reserve) + origData.append(cmd.crc) + + return self.__Trans(struct.pack(self.__packFmtLowCmd, *origData)) + + def __PackLowState(self, state: LowState_): + origData = [] + origData.extend(state.head) + origData.append(state.level_flag) + origData.append(state.frame_reserve) + origData.extend(state.sn) + origData.extend(state.version) + origData.append(state.bandwidth) + + origData.extend(state.imu_state.quaternion) + origData.extend(state.imu_state.gyroscope) + origData.extend(state.imu_state.accelerometer) + origData.extend(state.imu_state.rpy) + origData.append(state.imu_state.temperature) + + for i in range(20): + origData.append(state.motor_state[i].mode) + origData.append(state.motor_state[i].q) + origData.append(state.motor_state[i].dq) + origData.append(state.motor_state[i].ddq) + origData.append(state.motor_state[i].tau_est) + origData.append(state.motor_state[i].q_raw) + origData.append(state.motor_state[i].dq_raw) + origData.append(state.motor_state[i].ddq_raw) + origData.append(state.motor_state[i].temperature) + origData.append(state.motor_state[i].lost) + origData.extend(state.motor_state[i].reserve) + + origData.append(state.bms_state.version_high) + origData.append(state.bms_state.version_low) + origData.append(state.bms_state.status) + origData.append(state.bms_state.soc) + origData.append(state.bms_state.current) + origData.append(state.bms_state.cycle) + origData.extend(state.bms_state.bq_ntc) + origData.extend(state.bms_state.mcu_ntc) + origData.extend(state.bms_state.cell_vol) + + origData.extend(state.foot_force) + origData.extend(state.foot_force_est) + origData.append(state.tick) + origData.extend(state.wireless_remote) + origData.append(state.bit_flag) + origData.append(state.adc_reel) + origData.append(state.temperature_ntc1) + origData.append(state.temperature_ntc2) + origData.append(state.power_v) + origData.append(state.power_a) + origData.extend(state.fan_frequency) + origData.append(state.reserve) + origData.append(state.crc) + + return self.__Trans(struct.pack(self.__packFmtLowState, *origData)) + + def __PackHGLowCmd(self, cmd: HGLowCmd_): + origData = [] + origData.append(cmd.mode_pr) + origData.append(cmd.mode_machine) + + for i in range(35): + origData.append(cmd.motor_cmd[i].mode) + origData.append(cmd.motor_cmd[i].q) + origData.append(cmd.motor_cmd[i].dq) + origData.append(cmd.motor_cmd[i].tau) + origData.append(cmd.motor_cmd[i].kp) + origData.append(cmd.motor_cmd[i].kd) + origData.append(cmd.motor_cmd[i].reserve) + + origData.extend(cmd.reserve) + origData.append(cmd.crc) + + return self.__Trans(struct.pack(self.__packFmtHGLowCmd, *origData)) + + def __PackHGLowState(self, state: HGLowState_): + origData = [] + origData.extend(state.version) + origData.append(state.mode_pr) + origData.append(state.mode_machine) + origData.append(state.tick) + + origData.extend(state.imu_state.quaternion) + origData.extend(state.imu_state.gyroscope) + origData.extend(state.imu_state.accelerometer) + origData.extend(state.imu_state.rpy) + origData.append(state.imu_state.temperature) + + for i in range(35): + origData.append(state.motor_state[i].mode) + origData.append(state.motor_state[i].q) + origData.append(state.motor_state[i].dq) + origData.append(state.motor_state[i].ddq) + origData.append(state.motor_state[i].tau_est) + origData.extend(state.motor_state[i].temperature) + origData.append(state.motor_state[i].vol) + origData.extend(state.motor_state[i].sensor) + origData.append(state.motor_state[i].motorstate) + origData.extend(state.motor_state[i].reserve) + + origData.extend(state.wireless_remote) + origData.extend(state.reserve) + origData.append(state.crc) + + return self.__Trans(struct.pack(self.__packFmtHGLowState, *origData)) + + def __Trans(self, packData): + calcData = [] + calcLen = ((len(packData)>>2)-1) + + for i in range(calcLen): + d = ((packData[i*4+3] << 24) | (packData[i*4+2] << 16) | (packData[i*4+1] << 8) | (packData[i*4])) + calcData.append(d) + + return calcData + + def _crc_py(self, data): + bit = 0 + crc = 0xFFFFFFFF + polynomial = 0x04c11db7 + + for i in range(len(data)): + bit = 1 << 31 + current = data[i] + + for b in range(32): + if crc & 0x80000000: + crc = (crc << 1) & 0xFFFFFFFF + crc ^= polynomial + else: + crc = (crc << 1) & 0xFFFFFFFF + + if current & bit: + crc ^= polynomial + + bit >>= 1 + + return crc + + def _crc_ctypes(self, data): + uint32_array = (ctypes.c_uint32 * len(data))(*data) + length = len(data) + crc=self.crc_lib.crc32_core(uint32_array, length) + return crc + + def __Crc32(self, data): + if self.platform == "Linux": + return self._crc_ctypes(data) + else: + return self._crc_py(data) diff --git a/unitree_sdk2py/utils/future.py b/unitree_sdk2py/utils/future.py new file mode 100644 index 0000000..f539087 --- /dev/null +++ b/unitree_sdk2py/utils/future.py @@ -0,0 +1,104 @@ +from threading import Condition +from typing import Any +from enum import Enum + +""" +" Enum RequtestFutureState +""" +class FutureState(Enum): + DEFER = 0 + READY = 1 + FAILED = 2 + +""" +" class FutureException +""" +class FutureResult: + FUTURE_SUCC = 0 + FUTUTE_ERR_TIMEOUT = 1 + FUTURE_ERR_FAILED = 2 + FUTURE_ERR_UNKNOWN = 3 + + def __init__(self, code: int, msg: str, value: Any = None): + self.code = code + self.msg = msg + self.value = value + + def __str__(self): + return f"FutureResult(code={str(self.code)}, msg='{self.msg}', value={self.value})" + +class Future: + def __init__(self): + self.__state = FutureState.DEFER + self.__msg = None + self.__condition = Condition() + + def GetResult(self, timeout: float = None): + with self.__condition: + return self.__WaitResult(timeout) + + def Wait(self, timeout: float = None): + with self.__condition: + return self.__Wait(timeout) + + def Ready(self, value): + with self.__condition: + ready = self.__Ready(value) + self.__condition.notify() + return ready + + def Fail(self, reason: str): + with self.__condition: + fail = self.__Fail(reason) + self.__condition.notify() + return fail + + def __Wait(self, timeout: float = None): + if not self.__IsDeferred(): + return True + try: + if timeout is None: + return self.__condition.wait() + else: + return self.__condition.wait(timeout) + except: + print("[Future] future wait error") + return False + + def __WaitResult(self, timeout: float = None): + if not self.__Wait(timeout): + return FutureResult(FutureResult.FUTUTE_ERR_TIMEOUT, "future wait timeout") + + if self.__IsReady(): + return FutureResult(FutureResult.FUTURE_SUCC, "success", self.__value) + elif self.__IsFailed(): + return FutureResult(FutureResult.FUTURE_ERR_FAILED, self.__msg) + else: + return FutureResult(FutureResult.FUTURE_ERR_UNKNOWN, "future state error:" + str(self.__state)) + + def __Ready(self, value): + if not self.__IsDeferred(): + print("[Future] futrue state is not defer") + return False + else: + self.__value = value + self.__state = FutureState.READY + return True + + def __Fail(self, message: str): + if not self.__IsDeferred(): + print("[Future] futrue state is not DEFER") + return False + else: + self.__msg = message + self.__state = FutureState.FAILED + return True + + def __IsDeferred(self): + return self.__state == FutureState.DEFER + + def __IsReady(self): + return self.__state == FutureState.READY + + def __IsFailed(self): + return self.__state == FutureState.FAILED \ No newline at end of file diff --git a/unitree_sdk2py/utils/hz_sample.py b/unitree_sdk2py/utils/hz_sample.py new file mode 100644 index 0000000..962fe3c --- /dev/null +++ b/unitree_sdk2py/utils/hz_sample.py @@ -0,0 +1,24 @@ +import time +from threading import Lock +from .thread import RecurrentThread + +class HZSample: + def __init__(self, interval: float = 1.0): + self.__count = 0 + self.__inter = interval if interval > 0.0 else 1.0 + self.__lock = Lock() + self.__thread = RecurrentThread(self.__inter, target=self.TimerFunc) + + def Start(self): + self.__thread.Start() + + def Sample(self): + with self.__lock: + self.__count += 1 + + def TimerFunc(self): + count = 0 + with self.__lock: + count = self.__count + self.__count = 0 + print("HZ: {}".format(count/self.__inter)) diff --git a/unitree_sdk2py/utils/joystick.py b/unitree_sdk2py/utils/joystick.py new file mode 100644 index 0000000..aeda672 --- /dev/null +++ b/unitree_sdk2py/utils/joystick.py @@ -0,0 +1,251 @@ +import math +import struct +import os +os.environ['PYGAME_HIDE_SUPPORT_PROMPT'] = "hide" # Disable pygame welcome message +import pygame +import time + +class Button: + def __init__(self) -> None: + self.pressed = False + self.on_pressed = False + self.on_released = False + self.data = 0 + self.click_count = 0 # 记录连续点击次数 + self.last_pressed_time = 0 # 上次按下时间 + + def __call__(self, data) -> None: + current_time = time.perf_counter() + # print('before',self.data) + + self.pressed = (data != 0) + self.on_pressed = self.pressed and self.data == 0 + self.on_released = not self.pressed and self.data != 0 + + # print('after',self.data) + # 处理连续点击 + if self.on_pressed: + # print('on_pressed') + # print('on_pressed current_time',current_time) + # print('on_pressed last_pressed_time',self.last_pressed_time) + # print('on_pressed diff',current_time-self.last_pressed_time) + + if current_time - self.last_pressed_time <= 0.3: # 0.1 秒以内的连续点击 + self.click_count += 1 + # print(self.click_count) + else: + self.click_count = 0 # 超过时间间隔,重置计数器 + self.last_pressed_time = current_time + self.data = data + + def reset_click_count(self): + """手动重置连续点击计数器""" + self.click_count = 0 + +class Axis: + def __init__(self) -> None: + self.data = 0.0 + self.pressed = False + self.on_pressed = False + self.on_released = False + + self.smooth = 0.03 + self.deadzone = 0.01 + self.threshold = 0.5 + + def __call__(self, data) -> None: + data_deadzone = 0.0 if math.fabs(data) < self.deadzone else data + new_data = self.data * (1 - self.smooth) + data_deadzone * self.smooth + self.pressed = math.fabs(new_data) > self.threshold + self.on_pressed = self.pressed and math.fabs(self.data) < self.threshold + self.on_released = not self.pressed and math.fabs(self.data) > self.threshold + self.data = new_data + + +class Joystick: + def __init__(self) -> None: + # Buttons + self.back = Button() + self.start = Button() + # self.LS = Button() + # self.RS = Button() + self.LB = Button() + self.RB = Button() + self.LT = Button() + self.RT = Button() + self.A = Button() + self.B = Button() + self.X = Button() + self.Y = Button() + self.up = Button() + self.down = Button() + self.left = Button() + self.right = Button() + self.F1 = Button() + self.F2 = Button() + + # Axes + # self.LT = Axis() + # self.RT = Axis() + self.lx = Axis() + self.ly = Axis() + self.rx = Axis() + self.ry = Axis() + + self.last_active_time = time.perf_counter() # 最后一次活动时间 + self.inactive_timeout = 0.5 # 超时时间(单位:秒) + def update(self): + """ + Update the current handle key based on the original data + Used to update flag bits such as on_pressed + + Examples: + >>> new_A_data = 1 + >>> self.A( new_A_data ) + """ + pass + + def extract(self, wireless_remote): + """ + Extract data from unitree_joystick + wireless_remote: uint8_t[40] + """ + # Buttons + button1 = [int(data) for data in f'{wireless_remote[2]:08b}'] + button2 = [int(data) for data in f'{wireless_remote[3]:08b}'] + self.LT(button1[2]) + self.RT(button1[3]) + self.back(button1[4]) + self.start(button1[5]) + self.LB(button1[6]) + self.RB(button1[7]) + self.left(button2[0]) + self.down(button2[1]) + self.right(button2[2]) + self.up(button2[3]) + self.Y(button2[4]) + self.X(button2[5]) + self.B(button2[6]) + self.A(button2[7]) + # Axes + self.lx( struct.unpack('f', bytes(wireless_remote[4:8]))[0] ) + self.rx( struct.unpack('f', bytes(wireless_remote[8:12]))[0] ) + self.ry( struct.unpack('f', bytes(wireless_remote[12:16]))[0] ) + self.ly( struct.unpack('f', bytes(wireless_remote[20:24]))[0] ) + + + # 检查是否有按键按下 + if any([ + self.LT.pressed, self.RT.pressed, self.back.pressed, self.start.pressed, + self.LB.pressed, self.RB.pressed, self.left.pressed, self.down.pressed, + self.right.pressed, self.up.pressed, self.Y.pressed, self.X.pressed, + self.B.pressed, self.A.pressed + ]): + self.last_active_time = time.perf_counter() # 更新最后一次活动时间 + elif time.perf_counter() - self.last_active_time > self.inactive_timeout: + # 超过设定的超时时间未按下任何键,重置所有按键的点击计数 + self.reset_all_click_counts() + self.last_active_time = time.perf_counter() # 重置最后活动时间 + + def reset_all_click_counts(self): + """重置所有按键的连续点击计数器""" + for button in [ + self.LT, self.RT, self.back, self.start, self.LB, self.RB, + self.left, self.down, self.right, self.up, self.Y, self.X, self.B, self.A + ]: + button.reset_click_count() + + def combine(self): + """ + Merge data from Joystick to wireless_remote + """ + # prepare an empty list + wireless_remote = [0 for _ in range(40)] + + # Buttons + wireless_remote[2] = int(''.join([f'{key}' for key in [ + 0, 0, round(self.LT.data), round(self.RT.data), + self.back.data, self.start.data, self.LB.data, self.RB.data, + ]]), 2) + wireless_remote[3] = int(''.join([f'{key}' for key in [ + self.left.data, self.down.data, self.right.data, + self.up.data, self.Y.data, self.X.data, self.B.data, self.A.data, + ]]), 2) + + # Axes + sticks = [self.lx.data, self.rx.data, self.ry.data, self.ly.data] + packs = list(map(lambda x: struct.pack('f', x), sticks)) + wireless_remote[4:8] = packs[0] + wireless_remote[8:12] = packs[1] + wireless_remote[12:16] = packs[2] + wireless_remote[20:24] = packs[3] + return wireless_remote + +class PyGameJoystick(Joystick): + def __init__(self) -> None: + super().__init__() + + pygame.init() + pygame.joystick.init() + if pygame.joystick.get_count() <= 0: + raise Exception("No joystick found!") + + self._joystick = pygame.joystick.Joystick(0) + self._joystick.init() + + def print(self): + print("\naxes: ") + for i in range(self._joystick.get_numaxes()): + print(self._joystick.get_axis(i), end=" ") + print("\nbuttons: ") + for i in range(self._joystick.get_numbuttons()): + print(self._joystick.get_button(i), end=" ") + print("\nhats: ") + for i in range(self._joystick.get_numhats()): + print(self._joystick.get_hat(i), end=" ") + print("\nballs: ") + for i in range(self._joystick.get_numballs()): + print(self._joystick.get_ball(i), end=" ") + print("\n") + +class LogicJoystick(PyGameJoystick): + """ Logic F710 """ + def __init__(self) -> None: + super().__init__() + + def update(self): + pygame.event.pump() + + self.back(self._joystick.get_button(6)) + self.start(self._joystick.get_button(7)) + self.LS(self._joystick.get_button(9)) + self.RS(self._joystick.get_button(10)) + self.LB(self._joystick.get_button(4)) + self.RB(self._joystick.get_button(5)) + self.A(self._joystick.get_button(0)) + self.B(self._joystick.get_button(1)) + self.X(self._joystick.get_button(2)) + self.Y(self._joystick.get_button(3)) + + self.LT((self._joystick.get_axis(2) + 1)/2) + self.RT((self._joystick.get_axis(5) + 1)/2) + self.rx(self._joystick.get_axis(3)) + self.ry(-self._joystick.get_axis(4)) + + + # Logitech controller has 2 modes + # mode 1: light down + self.up(1 if self._joystick.get_hat(0)[1] > 0.5 else 0) + self.down(1 if self._joystick.get_hat(0)[1] < -0.5 else 0) + self.left(1 if self._joystick.get_hat(0)[0] < -0.5 else 0) + self.right(1 if self._joystick.get_hat(0)[0] > 0.5 else 0) + self.lx(self._joystick.get_axis(0)) + self.ly(-self._joystick.get_axis(1)) + # mode 2: light up + # self.up(1 if self._joystick.get_axis(1) < -0.5 else 0) + # self.down(1 if self._joystick.get_axis(0) > 0.5 else 0) + # self.left(1 if self._joystick.get_axis(0) < -0.5 else 0) + # self.right(1 if self._joystick.get_axis(0) > 0.5 else 0) + # self.lx(self._joystick.get_hat(0)[1]) + # self.ly(self._joystick.get_hat(0)[1]) + diff --git a/unitree_sdk2py/utils/lib/crc_aarch64.so b/unitree_sdk2py/utils/lib/crc_aarch64.so new file mode 100644 index 0000000000000000000000000000000000000000..878df74577e4fc4c90ff2d011c2344633c9798da GIT binary patch literal 7928 zcmeHMU2Ggz6+XMOaenMN8&eUJRAgQ9P?~1E2@cprqH8Diy2x>1vk@vnn#}&#Ua~*# z?5wbxh;9H?mEgf4mC^@jD}+QT70N?sE2vtxLMW&_M6^_Sp+r!GrAES01$0I2<(zxZ zSx74K}p`a}EokY=IEsyr<7=*5HNUM#|bSH@FWEW$*7~2W0vcAx5+C9+Y z&~=67e!8Fagpw|`FZ|ifQ2#glkbXL(v;c&P-51f0ADuOBO~Ncr@OYi_a+Tv3%B*^} z+tG)CSA6;;Jh=YcPf!2#%>zefGDni%+R?T5b5klD%HLMJ$W8$vP(u?&t@|InZ|Yv> zyMZ3U@}M3y1NtBwmWZ@q0!hT9Bi(yC;1o%-Ur)ZlIO=28_Sw4l!{i_ zwH?>8z`8$q+{$E~>};;=W}W2mqxn)Xo3vB;td_NxSm_1Zn#mRIeD2{aq@DDq4qNGx zlf`vQ5n;YL4>2Bp*oVK*a>La3+QMqQ76Z6ktJimvf3ijV5}bnb=a3E{y$|5sWq>5|O9MCJ zH5>I;jli>jz>x_wK+4qZi2j8)!ea60fC{eXwD_cIIXE zobPo*?E;Q@Dis@v1>gw!U4nPwHKdo-7~5jC*X#9**YJu!HE}8hBky&`YHMd+Q@ME? zpMm0EG2q$17=gP73>f;;^WRK#LG`x))xJ+W@w7woEsHZR21C_E04^nnf5(8kVPW5i zrvM%bf${n3rRttnAn;Y{51b90sD`V1#zOGWtLydTuR?IX4qc~L*6K+;AJsmhGFLKB zfxX6OqX0nb;-&R^eG=&nq+daLPrY8BN9rPd9O+r4&mj%tMJ@1f0zwNP5A5yPr!e~5 z=h2q@Q6oKiXCFf>hLlrl)ww?6cr-u&abH&QS!P#PEaAeRl z`L9)&cHEp+_nHe(;8;5+BTd>k}%vXl}8L+HO z$(qfVQg+_TxFx4-*%b_=RG80a-E77jIW#=dUWpC>bC&Hm_M(+7y3QiZICddxWh#Zj zBAR$O3pL#)RXj7qpe$=5F?xL58lOH!hmpq~oE|-X|51eTAW}dpQ!ZI^b}>UolH>=) zc$906PqOjku>`1Cz=}^jFg7}6JuoqGVmxUjN5`hd(QU`mN_G0#{)F>Z=c3I=s9=^C z3$C3)>N=XvNv~LPvnI~JnX2USnS;3uC~nR!&w-g)ETW~Rt^=l%&D#WWZ$9sWsh-z# zvkTa#bc30lBnLN1L1m(T~^OyxLZyEd4qav4mV>jKW7=WY4$ zU8-ZL7L@w2)9(o~g74n~m?-!=)`ns)^{vqTY$$c3)S2RM7&}zkioMiJLYG;Q#w8zO zFLh~*aj}=WO6Vz+dmDZZn%X3C0XwV&q!giiSqCh;pLc$@Rt zOC2dx#u0sg{6)5x{CE0Ys*^pPy;6u`-$*1UbV&@E`s05TaXR3Y`IY^h{BGsf7hdRh z(RQcDUh3Rob!xmZ->9OR*a>|SQ3_SYm;dAPyI_^`FL@I?$?K2MmQ=)E{_ieRP}uI$ zq;VH}p>%fcwU_#O4jQFYiC?lO=YKIYh|-+dpL>&8k?rs|bA)+SwoA N0ekkh+n0u4X zx##CQ_s%zW_ilI3eJ@j)Akxq z%J$pA$RsO``%eeMlV>grpAY1|Z5f^@Yg_+mZsLSY22{E{yUapD)f5AY0mXn~Krx^g zPz)#r6a$I@#eiZ!F>r$z2rMprWEqTwzrAVGwjBal3o;H;{A}BKl+f_ERcwKM9U?GT z9aubXPQ@tvz=zm7;qU98Y+L>`SXJFzRr6@Da&JXmY+AJ8fi=tSK^)@Y-*_?3acG2w zm|gHU2xGdxb)rKx#eiZ!F`yVw3@8Q^1BwB~fMP%~pcwdHF~D`ETvs}e?~dwB=aU|% zdf0`ebG_10?KJAsRD{ZPzhhKhx|86a2>mUJg(>6+SIf`Ti(^3OIbOsu1>Gl zYgg6fq+0jv>eYH}{R%SsGtAbp7Pt()P?&8M0-tvY)H{dhd9%NY>;pdg-DKzW!tv{% z6M%0Sw2))r+T$i^4+>rnj#r4Mp@ZY{`eXYuGQP^Khi3aL&?z+kV)yl$%rjrStZ{}J zSt!p@8DA~@&*NQbzsBTxM9s_LNy5XLUrqlip19!vEw<4LiwRq-O5_I-d?>&%#^(wR?_If!uKrH z$H&q}Un1QdO&BpNoyi)}+@R=5CkGOyWybW{!Vy>u-)}@Sndp#VrmW16=*>ivrV+~} zlS2UUXa+=DvqGVM9;Ra$%^i(xVI$nW1q<`H>}+prYiR;A6y>wgh-K48JerDOc|PU= zHyl$i!Vv;TwsZ(N7h!B|-L|>0)!5eDyd&IcbT)2o4MW5*VLWsPsCRB$Ak=sN3(IE$A(gn%#l_` z=ovE+MWfK=jq3vmOYcitLbuF8xZ(p4x)~>`<1v7+=0F_Iok;FOzG$+)2gXfXm=T7H zT2Y~QXR|_wr=Em|Szwv|XA|x(_?}MN#Wm-7G+#!3zh^TZ8}j0do#)|r+BR4fjnKOU zdjyZq`xeV(6v;UM_>X}f_bkTqzQ%Ht@O&nQ@w`9n06*?cjOTrljkG**FjDA412A*9gbb_crNIFZTHGwFF@K zPk3B}-tj{OV0oX9Fn_*%K0Loqv*gc55GI@d{_|kPA((%mfr3qwSNZ+D({rwV{7Yc= z;+Jbq9LoVmb+5dB*l-v+xR>+i8~)tJ=fC{%th0Ozut5)=_wfVx!h*(ejy9vS{TMiK z?eO@#zw&uLKDWo80~yE90Y5C_{WG4=H%&ohAvR53XD*Cqc^q6`ya-Wjts{AzlhwT+ z#(xYBFP``N8p3m&AJ6(J=wJ-bUkf=Ntq2~+^0v=GK^uj;F2=8PEl!8=Ug@qqPwaL| w_yjrc03ZHF#P`Fz;OAwYy9X}DRy&%(1Ci6G%42ke@N?=Nz*pX+(D&p20-