11 #include <spdlog/spdlog.h>
19 using namespace flexiv;
23 constexpr
double kLoopPeriod = 0.001;
26 constexpr
double kSineAmp = 0.035;
27 constexpr
double kSineFreq = 0.3;
30 std::atomic<bool> g_stop_sched = {
false};
37 std::cout <<
"Required arguments: [robot_sn]" << std::endl;
38 std::cout <<
" robot_sn: Serial number of the robot to connect. Remove any space, e.g. Enlight-L-123456" << std::endl;
39 std::cout <<
"Optional arguments: [--hold]" << std::endl;
40 std::cout <<
" --hold: robot holds current joint positions, otherwise do a sine-sweep" << std::endl;
41 std::cout << std::endl;
46 void PeriodicTask(
rdk::Robot& robot,
const std::string& motion_type,
47 const std::map<rdk::JointGroup, std::string>& single_arm_groups,
51 static unsigned int loop_counter = 0;
56 throw std::runtime_error(
57 "PeriodicTask: Fault occurred on the connected robot, exiting ...");
60 std::map<rdk::JointGroup, rdk::RtJointPositionCmd> rt_cmds;
62 if ((motion_type !=
"hold") && (motion_type !=
"sine-sweep")) {
63 throw std::invalid_argument(
64 "PeriodicTask: Unknown motion type. Accepted motion types: hold, sine-sweep");
67 for (
const auto& [group, init_pos] : all_init_pos) {
68 std::vector<double> target_pos(init_pos.size());
69 std::vector<double> target_vel(init_pos.size());
70 std::vector<double> target_acc(init_pos.size());
72 if (motion_type ==
"hold") {
73 target_pos = init_pos;
75 for (
size_t i = 0; i < target_pos.size(); ++i) {
78 + kSineAmp * sin(2 * M_PI * kSineFreq * loop_counter * kLoopPeriod);
86 if (loop_counter == 5000) {
87 for (
const auto& [group, _] : single_arm_groups) {
89 for (
auto& v : new_Kq) {
93 spdlog::info(
"[{}] Joint stiffness set to: [{}]", rdk::kJointGroupNames.at(group),
94 rdk::utility::Vec2Str(new_Kq));
99 if (loop_counter == 10000) {
100 for (
const auto& [group, _] : single_arm_groups) {
101 const auto nominal_Kq = robot.
info().
K_q_nom.at(group);
103 spdlog::info(
"[{}] Joint stiffness reset to nominal: [{}]",
104 rdk::kJointGroupNames.at(group), rdk::utility::Vec2Str(nominal_Kq));
114 }
catch (
const std::exception& e) {
115 spdlog::error(e.what());
120 int main(
int argc,
char* argv[])
125 if (argc < 2 || rdk::utility::ProgramArgsExistAny(argc, argv, {
"-h",
"--help"})) {
130 std::string robot_sn = argv[1];
134 ">>> Tutorial description <<<\nThis tutorial runs real-time joint impedance control to "
135 "hold or sine-sweep all robot joints.\n");
138 std::string motion_type =
"";
139 if (rdk::utility::ProgramArgsExist(argc, argv,
"--hold")) {
140 spdlog::info(
"Robot holding current pose");
141 motion_type =
"hold";
143 spdlog::info(
"Robot running joint sine-sweep");
144 motion_type =
"sine-sweep";
155 spdlog::warn(
"Fault occurred on the connected robot, trying to clear ...");
158 spdlog::error(
"Fault cannot be cleared, exiting ...");
161 spdlog::info(
"Fault on the connected robot is cleared");
165 spdlog::info(
"Servo on the robot ...");
170 std::this_thread::sleep_for(std::chrono::seconds(1));
172 spdlog::info(
"Robot is now operational");
175 spdlog::info(
"Moving to home pose");
182 if (single_arm_groups.empty()) {
183 throw std::runtime_error(
"No single-arm joint group found on the connected robot");
186 auto exe_groups = single_arm_groups;
187 if (robot.
info().
all_groups.contains(rdk::JointGroup::EXT_AXIS)) {
189 rdk::JointGroup::EXT_AXIS, robot.
info().
all_groups.at(rdk::JointGroup::EXT_AXIS));
193 robot.
SwitchMode(rdk::Mode::RT_JOINT_IMPEDANCE);
196 std::map<rdk::JointGroup, std::vector<double>> all_init_pos;
197 const auto robot_states = robot.
states();
198 for (
const auto& [group, _] : exe_groups) {
199 all_init_pos[group] = robot_states.at(group).q;
200 spdlog::info(
"[{}] Initial joint positions: {}", rdk::kJointGroupNames.at(group),
201 rdk::utility::Vec2Str(all_init_pos.at(group)));
207 scheduler.
AddTask(std::bind(PeriodicTask, std::ref(robot), std::ref(motion_type),
208 std::cref(single_arm_groups), std::cref(all_init_pos)),
214 while (!g_stop_sched) {
215 std::this_thread::sleep_for(std::chrono::milliseconds(1));
220 }
catch (
const std::exception& e) {
221 spdlog::error(e.what());
Main interface to control the robot, containing several function categories and background services.
RobotInfo info() const
[Non-blocking] General information about the robot.
void Home(const std::vector< JointGroup > &groups={})
[Blocking] Move the specified joint groups to the home posture using Home primitive.
void StreamJointPosition(const std::map< JointGroup, RtJointPositionCmd > &cmds)
[Non-blocking] Continuously stream joint position, velocity, and acceleration commands of the specifi...
void SetJointImpedance(JointGroup group, const std::vector< double > &K_q, const std::vector< double > &Z_q={})
[Blocking] Set impedance properties of the robot's joint motion controller used in the joint impedanc...
void SwitchMode(Mode mode)
[Blocking] Switch the robot to a new control mode and wait for the mode transition to finish.
std::map< JointGroup, RobotStates > states() const
[Non-blocking] Current states data of all existing joint groups of the robot.
bool operational() const
[Non-blocking] Whether the robot is ready to be operated, which requires the following conditions to ...
void ServoOn()
[Blocking] Servo on the robot. If E-stop is released and there's no fault, the robot will release bra...
bool fault() const
[Non-blocking] Whether the robot is in fault state.
bool ClearFault(unsigned int timeout_sec=30)
[Blocking] Try to clear minor or critical fault for the robot without a power cycle.
Real-time scheduler that can simultaneously run multiple periodic tasks. Parameters for each task are...
int max_priority() const
[Non-blocking] Maximum available priority for user tasks.
void AddTask(std::function< void(void)> &&callback, const std::string &task_name, int interval, int priority, int cpu_affinity=-1)
[Non-blocking] Add a new periodic task to the scheduler's task pool. Each task in the pool is assigne...
void Stop()
[Blocking] Stop all added tasks. The periodic execution will stop and all task threads will be closed...
void Start()
[Blocking] Start all added tasks. A dedicated thread will be created for each added task and the peri...
JointGroup
All possible joint groups of the robot.
std::map< JointGroup, std::vector< double > > K_q_nom
std::map< JointGroup, std::string > single_arm_groups
std::map< JointGroup, std::string > all_groups
Commands data for real-time joint position control.