Skip to content

Commit 30405b3

Browse files
author
Jichao.Wang
committed
add user control example
1 parent 7694ddf commit 30405b3

File tree

1 file changed

+248
-0
lines changed

1 file changed

+248
-0
lines changed
Lines changed: 248 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,248 @@
1+
#include <array>
2+
#include <chrono>
3+
#include <iostream>
4+
#include <thread>
5+
6+
#include <unitree/idl/hg/LowCmd_.hpp>
7+
#include <unitree/idl/hg/LowState_.hpp>
8+
#include <unitree/robot/channel/channel_publisher.hpp>
9+
#include <unitree/robot/channel/channel_subscriber.hpp>
10+
#include "unitree/robot/g1/loco/g1_loco_api.hpp"
11+
#include "unitree/robot/g1/loco/g1_loco_client.hpp"
12+
13+
static const std::string kTopicUserCtrl = "rt/user_lowcmd";
14+
static const std::string kTopicState = "rt/lowstate";
15+
16+
enum JointIndex {
17+
// Left leg
18+
kLeftHipPitch,
19+
kLeftHipRoll,
20+
kLeftHipYaw,
21+
kLeftKnee,
22+
kLeftAnkle,
23+
kLeftAnkleRoll,
24+
25+
// Right leg
26+
kRightHipPitch,
27+
kRightHipRoll,
28+
kRightHipYaw,
29+
kRightKnee,
30+
kRightAnkle,
31+
kRightAnkleRoll,
32+
33+
kWaistYaw,
34+
kWaistRoll,
35+
kWaistPitch,
36+
37+
// Left arm
38+
kLeftShoulderPitch,
39+
kLeftShoulderRoll,
40+
kLeftShoulderYaw,
41+
kLeftElbow,
42+
kLeftWristRoll,
43+
kLeftWristPitch,
44+
kLeftWristYaw,
45+
// Right arm
46+
kRightShoulderPitch,
47+
kRightShoulderRoll,
48+
kRightShoulderYaw,
49+
kRightElbow,
50+
kRightWristRoll,
51+
kRightWristPitch,
52+
kRightWristYaw,
53+
54+
kNotUsedJoint,
55+
kNotUsedJoint1,
56+
kNotUsedJoint2,
57+
kNotUsedJoint3,
58+
kNotUsedJoint4,
59+
kNotUsedJoint5
60+
};
61+
62+
int main(int argc, char const *argv[]) {
63+
if (argc < 2) {
64+
std::cout << "Usage: " << argv[0] << " networkInterface" << std::endl;
65+
exit(-1);
66+
}
67+
68+
unitree::robot::ChannelFactory::Instance()->Init(0, argv[1]);
69+
70+
unitree::robot::ChannelPublisherPtr<unitree_hg::msg::dds_::LowCmd_>
71+
user_ctrl_publisher;
72+
unitree_hg::msg::dds_::LowCmd_ msg;
73+
74+
user_ctrl_publisher.reset(
75+
new unitree::robot::ChannelPublisher<unitree_hg::msg::dds_::LowCmd_>(
76+
kTopicUserCtrl));
77+
user_ctrl_publisher->InitChannel();
78+
79+
unitree::robot::ChannelSubscriberPtr<unitree_hg::msg::dds_::LowState_>
80+
low_state_subscriber;
81+
82+
// create subscriber
83+
unitree_hg::msg::dds_::LowState_ state_msg;
84+
low_state_subscriber.reset(
85+
new unitree::robot::ChannelSubscriber<unitree_hg::msg::dds_::LowState_>(
86+
kTopicState));
87+
low_state_subscriber->InitChannel([&](const void *msg) {
88+
auto s = ( const unitree_hg::msg::dds_::LowState_* )msg;
89+
memcpy( &state_msg, s, sizeof( unitree_hg::msg::dds_::LowState_ ) );
90+
}, 1);
91+
92+
unitree::robot::g1::LocoClient client;
93+
client.Init();
94+
client.SetTimeout(5.f);
95+
int current_fsm_id;
96+
client.GetFsmId(current_fsm_id);
97+
if(current_fsm_id != 1){
98+
std::cout << "Current fsm is not PASSIVE, exitting ..." <<std::endl;
99+
exit(-1);
100+
}
101+
102+
float kp = 60.f;
103+
float kd = 1.5f;
104+
float dq = 0.f;
105+
float tau_ff = 0.f;
106+
107+
float control_dt = 0.02f;
108+
float max_joint_velocity = 0.5f;
109+
110+
float max_joint_delta = max_joint_velocity * control_dt;
111+
auto sleep_time =
112+
std::chrono::milliseconds(static_cast<int>(control_dt / 0.001f));
113+
114+
std::array<float, 29> init_pos{-0.1, 0, 0, 0.3, -0.2, 0,
115+
-0.1, 0, 0, 0.3, -0.2, 0,
116+
0, 0, 0,
117+
0.2, 0.2, 0, 0.9, 0, 0, 0,
118+
0.2, -0.2, 0, 0.9, 0, 0, 0};
119+
120+
std::array<float, 29> target_pos = {-1.0, 0, 0, 1.5, 0.2, 0,
121+
-1.0, 0, 0, 1.5, 0.2, 0,
122+
0, 0, 0,
123+
0, 0.2, 0, 0, 0, 0, 0,
124+
0, -0.2, 0, 0, 0, 0, 0};
125+
126+
// wait for init
127+
std::cout << "Press ENTER to init user control ...";
128+
std::cin.get();
129+
for (int j = 0; j < init_pos.size(); ++j) {
130+
msg.motor_cmd().at(j).q(0);
131+
msg.motor_cmd().at(j).dq(0);
132+
msg.motor_cmd().at(j).kp(0);
133+
msg.motor_cmd().at(j).kd(kd);
134+
msg.motor_cmd().at(j).tau(0);
135+
}
136+
user_ctrl_publisher->Write(msg);
137+
138+
client.SwitchToUserCtrl();
139+
140+
// get current joint position
141+
std::array<float, 29> current_jpos{};
142+
std::cout<<"Current joint position: ";
143+
for (int i = 0; i < init_pos.size(); ++i) {
144+
current_jpos.at(i) = state_msg.motor_state().at(i).q();
145+
std::cout << current_jpos.at(i) << " ";
146+
}
147+
std::cout << std::endl;
148+
149+
// set init pos
150+
std::cout << "Initailizing motors ...";
151+
float init_time = 2.0f;
152+
int init_time_steps = static_cast<int>(init_time / control_dt);
153+
154+
for (int i = 0; i < init_time_steps; ++i) {
155+
156+
float phase = 1.0 * i / init_time_steps;
157+
std::cout << "Phase: " << phase << std::endl;
158+
159+
// set control joints
160+
for (int j = 0; j < init_pos.size(); ++j) {
161+
msg.motor_cmd().at(j).q(init_pos.at(j) * phase + current_jpos.at(j) * (1 - phase));
162+
msg.motor_cmd().at(j).dq(dq);
163+
msg.motor_cmd().at(j).kp(kp);
164+
msg.motor_cmd().at(j).kd(kd);
165+
msg.motor_cmd().at(j).tau(tau_ff);
166+
}
167+
168+
// send dds msg
169+
user_ctrl_publisher->Write(msg);
170+
171+
// sleep
172+
std::this_thread::sleep_for(sleep_time);
173+
}
174+
175+
std::cout << "Done!" << std::endl;
176+
177+
// wait for control
178+
std::cout << "Press ENTER to start user control ..." << std::endl;
179+
std::cin.get();
180+
181+
// start control
182+
std::cout << "Start user control!" << std::endl;
183+
float period = 5.f;
184+
int num_time_steps = static_cast<int>(period / control_dt);
185+
186+
std::array<float, 29> current_jpos_des{};
187+
for (int i = 0; i < init_pos.size(); ++i) {
188+
current_jpos_des.at(i) = state_msg.motor_state().at(i).q();
189+
}
190+
191+
// lift arms up
192+
for (int i = 0; i < num_time_steps; ++i) {
193+
// update jpos des
194+
for (int j = 0; j < init_pos.size(); ++j) {
195+
current_jpos_des.at(j) +=
196+
std::clamp(target_pos.at(j) - current_jpos_des.at(j),
197+
-max_joint_delta, max_joint_delta);
198+
}
199+
200+
// set control joints
201+
for (int j = 0; j < init_pos.size(); ++j) {
202+
msg.motor_cmd().at(j).q(current_jpos_des.at(j));
203+
msg.motor_cmd().at(j).dq(dq);
204+
msg.motor_cmd().at(j).kp(kp);
205+
msg.motor_cmd().at(j).kd(kd);
206+
msg.motor_cmd().at(j).tau(tau_ff);
207+
}
208+
209+
// send dds msg
210+
user_ctrl_publisher->Write(msg);
211+
212+
// sleep
213+
std::this_thread::sleep_for(sleep_time);
214+
}
215+
216+
// put arms down
217+
for (int i = 0; i < num_time_steps; ++i) {
218+
// update jpos des
219+
for (int j = 0; j < init_pos.size(); ++j) {
220+
current_jpos_des.at(j) +=
221+
std::clamp(init_pos.at(j) - current_jpos_des.at(j), -max_joint_delta,
222+
max_joint_delta);
223+
}
224+
225+
// set control joints
226+
for (int j = 0; j < init_pos.size(); ++j) {
227+
msg.motor_cmd().at(j).q(current_jpos_des.at(j));
228+
msg.motor_cmd().at(j).dq(dq);
229+
msg.motor_cmd().at(j).kp(kp);
230+
msg.motor_cmd().at(j).kd(kd);
231+
msg.motor_cmd().at(j).tau(tau_ff);
232+
}
233+
234+
// send dds msg
235+
user_ctrl_publisher->Write(msg);
236+
237+
// sleep
238+
std::this_thread::sleep_for(sleep_time);
239+
}
240+
241+
// stop control
242+
std::cout << "Stoping user control ...";
243+
client.SwitchToInternalCtrl(unitree::robot::g1::InternalFsmMode::LAST);
244+
245+
std::cout << "Done!" << std::endl;
246+
247+
return 0;
248+
}

0 commit comments

Comments
 (0)