1+ import time
2+ import sys
3+
4+ from unitree_sdk2py .core .channel import ChannelPublisher , ChannelFactoryInitialize
5+ from unitree_sdk2py .core .channel import ChannelSubscriber , ChannelFactoryInitialize
6+ from unitree_sdk2py .idl .default import unitree_hg_msg_dds__LowCmd_
7+ from unitree_sdk2py .idl .default import unitree_hg_msg_dds__LowState_
8+ from unitree_sdk2py .idl .unitree_hg .msg .dds_ import LowCmd_
9+ from unitree_sdk2py .idl .unitree_hg .msg .dds_ import LowState_
10+ from unitree_sdk2py .utils .crc import CRC
11+ from unitree_sdk2py .utils .thread import RecurrentThread
12+ from unitree_sdk2py .comm .motion_switcher .motion_switcher_client import MotionSwitcherClient
13+
14+ import numpy as np
15+
16+ H1_2_NUM_MOTOR = 27
17+
18+ class H1_2_JointIndex :
19+ # legs
20+ LeftHipYaw = 0
21+ LeftHipPitch = 1
22+ LeftHipRoll = 2
23+ LeftKnee = 3
24+ LeftAnklePitch = 4
25+ LeftAnkleB = 4
26+ LeftAnkleRoll = 5
27+ LeftAnkleA = 5
28+ RightHipYaw = 6
29+ RightHipPitch = 7
30+ RightHipRoll = 8
31+ RightKnee = 9
32+ RightAnklePitch = 10
33+ RightAnkleB = 10
34+ RightAnkleRoll = 11
35+ RightAnkleA = 11
36+ # torso
37+ WaistYaw = 12
38+ # arms
39+ LeftShoulderPitch = 13
40+ LeftShoulderRoll = 14
41+ LeftShoulderYaw = 15
42+ LeftElbow = 16
43+ LeftWristRoll = 17
44+ LeftWristPitch = 18
45+ LeftWristYaw = 19
46+ RightShoulderPitch = 20
47+ RightShoulderRoll = 21
48+ RightShoulderYaw = 22
49+ RightElbow = 23
50+ RightWristRoll = 24
51+ RightWristPitch = 25
52+ RightWristYaw = 26
53+
54+
55+ class Mode :
56+ PR = 0 # Series Control for Pitch/Roll Joints
57+ AB = 1 # Parallel Control for A/B Joints
58+
59+ class Custom :
60+ def __init__ (self ):
61+ self .time_ = 0.0
62+ self .control_dt_ = 0.002 # [2ms]
63+ self .duration_ = 3.0 # [3 s]
64+ self .counter_ = 0
65+ self .mode_pr_ = Mode .PR
66+ self .mode_machine_ = 0
67+ self .low_cmd = unitree_hg_msg_dds__LowCmd_ ()
68+ self .low_state = None
69+ self .update_mode_machine_ = False
70+ self .crc = CRC ()
71+
72+ def Init (self ):
73+ self .msc = MotionSwitcherClient ()
74+ self .msc .SetTimeout (5.0 )
75+ self .msc .Init ()
76+
77+ status , result = self .msc .CheckMode ()
78+ while result ['name' ]:
79+ self .msc .ReleaseMode ()
80+ status , result = self .msc .CheckMode ()
81+ time .sleep (1 )
82+
83+ # create publisher #
84+ self .lowcmd_publisher_ = ChannelPublisher ("rt/lowcmd" , LowCmd_ )
85+ self .lowcmd_publisher_ .Init ()
86+
87+ # create subscriber #
88+ self .lowstate_subscriber = ChannelSubscriber ("rt/lowstate" , LowState_ )
89+ self .lowstate_subscriber .Init (self .LowStateHandler , 10 )
90+
91+ def Start (self ):
92+ self .lowCmdWriteThreadPtr = RecurrentThread (
93+ interval = self .control_dt_ , target = self .LowCmdWrite , name = "control"
94+ )
95+ while self .update_mode_machine_ == False :
96+ time .sleep (1 )
97+
98+ if self .update_mode_machine_ == True :
99+ self .lowCmdWriteThreadPtr .Start ()
100+
101+ def LowStateHandler (self , msg : LowState_ ):
102+ self .low_state = msg
103+
104+ if self .update_mode_machine_ == False :
105+ self .mode_machine_ = self .low_state .mode_machine
106+ self .update_mode_machine_ = True
107+
108+ self .counter_ += 1
109+ if (self .counter_ % 500 == 0 ) :
110+ self .counter_ = 0
111+ print (self .low_state .imu_state .rpy )
112+
113+ def LowCmdWrite (self ):
114+ self .time_ += self .control_dt_
115+ self .low_cmd .mode_pr = Mode .PR
116+ self .low_cmd .mode_machine = self .mode_machine_
117+ for i in range (H1_2_NUM_MOTOR ):
118+ ratio = np .clip (self .time_ / self .duration_ , 0.0 , 1.0 )
119+ self .low_cmd .motor_cmd [i ].mode = 1 # 1:Enable, 0:Disable
120+ self .low_cmd .motor_cmd [i ].tau = 0.0
121+ self .low_cmd .motor_cmd [i ].q = 0.0
122+ self .low_cmd .motor_cmd [i ].dq = 0.0
123+ self .low_cmd .motor_cmd [i ].kp = 100.0 if i < 13 else 50.0
124+ self .low_cmd .motor_cmd [i ].kd = 1.0
125+
126+ if self .time_ < self .duration_ :
127+ # [Stage 1]: set robot to zero posture
128+ for i in range (H1_2_NUM_MOTOR ):
129+ ratio = np .clip (self .time_ / self .duration_ , 0.0 , 1.0 )
130+ self .low_cmd .mode_pr = Mode .PR
131+ self .low_cmd .mode_machine = self .mode_machine_
132+ self .low_cmd .motor_cmd [i ].mode = 1 # 1:Enable, 0:Disable
133+ self .low_cmd .motor_cmd [i ].tau = 0.
134+ self .low_cmd .motor_cmd [i ].q = (1.0 - ratio ) * self .low_state .motor_state [i ].q
135+ self .low_cmd .motor_cmd [i ].dq = 0.
136+ self .low_cmd .motor_cmd [i ].kp = 100.0 if i < 13 else 50.0
137+ self .low_cmd .motor_cmd [i ].kd = 1.0
138+ else :
139+ # [Stage 2]: swing ankle using PR mode
140+ max_P = 0.25
141+ max_R = 0.25
142+ t = self .time_ - self .duration_
143+ L_P_des = max_P * np .cos (2.0 * np .pi * t )
144+ L_R_des = max_R * np .sin (2.0 * np .pi * t )
145+ R_P_des = max_P * np .cos (2.0 * np .pi * t )
146+ R_R_des = - max_R * np .sin (2.0 * np .pi * t )
147+
148+ Kp_Pitch = 80
149+ Kd_Pitch = 1
150+ Kp_Roll = 80
151+ Kd_Roll = 1
152+
153+ self .low_cmd .mode_pr = Mode .PR
154+ self .low_cmd .mode_machine = self .mode_machine_
155+ self .low_cmd .motor_cmd [H1_2_JointIndex .LeftAnklePitch ].q = L_P_des
156+ self .low_cmd .motor_cmd [H1_2_JointIndex .LeftAnklePitch ].dq = 0
157+ self .low_cmd .motor_cmd [H1_2_JointIndex .LeftAnklePitch ].kp = Kp_Pitch
158+ self .low_cmd .motor_cmd [H1_2_JointIndex .LeftAnklePitch ].kd = Kd_Pitch
159+ self .low_cmd .motor_cmd [H1_2_JointIndex .LeftAnkleRoll ].q = L_R_des
160+ self .low_cmd .motor_cmd [H1_2_JointIndex .LeftAnkleRoll ].dq = 0
161+ self .low_cmd .motor_cmd [H1_2_JointIndex .LeftAnkleRoll ].kp = Kp_Roll
162+ self .low_cmd .motor_cmd [H1_2_JointIndex .LeftAnkleRoll ].kd = Kd_Roll
163+ self .low_cmd .motor_cmd [H1_2_JointIndex .RightAnklePitch ].q = R_P_des
164+ self .low_cmd .motor_cmd [H1_2_JointIndex .RightAnklePitch ].dq = 0
165+ self .low_cmd .motor_cmd [H1_2_JointIndex .RightAnklePitch ].kp = Kp_Pitch
166+ self .low_cmd .motor_cmd [H1_2_JointIndex .RightAnklePitch ].kd = Kd_Pitch
167+ self .low_cmd .motor_cmd [H1_2_JointIndex .RightAnkleRoll ].q = R_R_des
168+ self .low_cmd .motor_cmd [H1_2_JointIndex .RightAnkleRoll ].dq = 0
169+ self .low_cmd .motor_cmd [H1_2_JointIndex .RightAnkleRoll ].kp = Kp_Roll
170+ self .low_cmd .motor_cmd [H1_2_JointIndex .RightAnkleRoll ].kd = Kd_Roll
171+
172+ max_wrist_roll_angle = 0.5 ; # [rad]
173+ WristRoll_des = max_wrist_roll_angle * np .sin (2.0 * np .pi * t )
174+ self .low_cmd .motor_cmd [H1_2_JointIndex .LeftWristRoll ].q = WristRoll_des
175+ self .low_cmd .motor_cmd [H1_2_JointIndex .LeftWristRoll ].dq = 0
176+ self .low_cmd .motor_cmd [H1_2_JointIndex .LeftWristRoll ].kp = 50
177+ self .low_cmd .motor_cmd [H1_2_JointIndex .LeftWristRoll ].kd = 1
178+ self .low_cmd .motor_cmd [H1_2_JointIndex .RightWristRoll ].q = WristRoll_des
179+ self .low_cmd .motor_cmd [H1_2_JointIndex .RightWristRoll ].dq = 0
180+ self .low_cmd .motor_cmd [H1_2_JointIndex .RightWristRoll ].kp = 50
181+ self .low_cmd .motor_cmd [H1_2_JointIndex .RightWristRoll ].kd = 1
182+
183+ self .low_cmd .crc = self .crc .Crc (self .low_cmd )
184+ self .lowcmd_publisher_ .Write (self .low_cmd )
185+
186+ if __name__ == '__main__' :
187+
188+ print ("WARNING: Please ensure there are no obstacles around the robot while running this example." )
189+ input ("Press Enter to continue..." )
190+
191+ if len (sys .argv )> 1 :
192+ ChannelFactoryInitialize (0 , sys .argv [1 ])
193+ else :
194+ ChannelFactoryInitialize (0 )
195+
196+ custom = Custom ()
197+ custom .Init ()
198+ custom .Start ()
199+
200+ while True :
201+ time .sleep (1 )
0 commit comments