12 #include <spdlog/spdlog.h>
19 using namespace flexiv;
23 constexpr
size_t kLoopFreq = 1000;
26 constexpr
double kLoopPeriod = 0.001;
29 constexpr
double kSwingAmp = 0.1;
32 constexpr
double kSwingFreq = 0.3;
35 constexpr
double kExtForceThreshold = 10.0;
38 constexpr
double kExtTorqueThreshold = 5.0;
41 std::atomic<bool> g_stop_sched = {
false};
48 std::cout <<
"Required arguments: [robot_sn]" << std::endl;
49 std::cout <<
" robot_sn: Serial number of the robot to connect. Remove any space, e.g. Rizon4s-123456" << std::endl;
50 std::cout <<
"Optional arguments: [--hold] [--collision]" << std::endl;
51 std::cout <<
" --hold: robot holds current TCP pose, otherwise do a sine-sweep" << std::endl;
52 std::cout <<
" --collision: enable collision detection, robot will stop upon collision" << std::endl;
53 std::cout << std::endl;
58 void PeriodicTask(
rdk::Robot& robot,
const std::array<double, rdk::kPoseSize>& init_pose,
59 const std::vector<double>& init_q,
bool enable_hold,
bool enable_collision)
62 static uint64_t loop_counter = 0;
67 throw std::runtime_error(
68 "PeriodicTask: Fault occurred on the connected robot, exiting ...");
72 auto target_pose = init_pose;
76 target_pose[1] = init_pose[1]
77 + kSwingAmp * sin(2 * M_PI * kSwingFreq * loop_counter * kLoopPeriod);
86 switch (loop_counter % (20 * kLoopFreq)) {
88 case (3 * kLoopFreq): {
89 std::vector<double> preferred_jnt_pos
90 = {0.938, -1.108, -1.254, 1.464, 1.073, 0.278, -0.658};
92 spdlog::info(
"Reference joint positions set to: "
93 + rdk::utility::Vec2Str(preferred_jnt_pos));
96 case (6 * kLoopFreq): {
98 for (
auto& v : new_K) {
102 spdlog::info(
"Cartesian stiffness set to: {}", rdk::utility::Arr2Str(new_K));
105 case (9 * kLoopFreq): {
106 std::vector<double> preferred_jnt_pos
107 = {-0.938, -1.108, 1.254, 1.464, -1.073, 0.278, 0.658};
109 spdlog::info(
"Reference joint positions set to: "
110 + rdk::utility::Vec2Str(preferred_jnt_pos));
113 case (12 * kLoopFreq): {
115 spdlog::info(
"Cartesian impedance properties are reset");
118 case (14 * kLoopFreq): {
120 spdlog::info(
"Reference joint positions are reset");
123 case (16 * kLoopFreq): {
124 std::array<double, rdk::kCartDoF> max_wrench = {10.0, 10.0, 10.0, 2.0, 2.0, 2.0};
126 spdlog::info(
"Max contact wrench set to: {}", rdk::utility::Arr2Str(max_wrench));
129 case (19 * kLoopFreq): {
130 std::array<double, rdk::kCartDoF> inf;
131 inf.fill(std::numeric_limits<double>::infinity());
133 spdlog::info(
"Max contact wrench regulation is disabled");
141 if (enable_collision) {
142 bool collision_detected =
false;
145 if (ext_force.norm() > kExtForceThreshold) {
146 collision_detected =
true;
149 if (fabs(v) > kExtTorqueThreshold) {
150 collision_detected =
true;
153 if (collision_detected) {
155 spdlog::warn(
"Collision detected, stopping robot and exit program ...");
163 }
catch (
const std::exception& e) {
164 spdlog::error(e.what());
169 int main(
int argc,
char* argv[])
174 if (argc < 2 || rdk::utility::ProgramArgsExistAny(argc, argv, {
"-h",
"--help"})) {
179 std::string robot_sn = argv[1];
183 ">>> Tutorial description <<<\nThis tutorial runs real-time Cartesian-space pure motion "
184 "control to hold or sine-sweep the robot TCP. A simple collision detection is also "
188 bool enable_hold =
false;
189 if (rdk::utility::ProgramArgsExist(argc, argv,
"--hold")) {
190 spdlog::info(
"Robot holding current TCP pose");
193 spdlog::info(
"Robot running TCP sine-sweep");
197 bool enable_collision =
false;
198 if (rdk::utility::ProgramArgsExist(argc, argv,
"--collision")) {
199 spdlog::info(
"Collision detection enabled");
200 enable_collision =
true;
202 spdlog::info(
"Collision detection disabled");
213 spdlog::warn(
"Fault occurred on the connected robot, trying to clear ...");
216 spdlog::error(
"Fault cannot be cleared, exiting ...");
219 spdlog::info(
"Fault on the connected robot is cleared");
223 spdlog::info(
"Enabling robot ...");
228 std::this_thread::sleep_for(std::chrono::seconds(1));
230 spdlog::info(
"Robot is now operational");
233 spdlog::info(
"Moving to home pose");
234 robot.
SwitchMode(rdk::Mode::NRT_PLAN_EXECUTION);
237 while (robot.
busy()) {
238 std::this_thread::sleep_for(std::chrono::seconds(1));
243 robot.
SwitchMode(rdk::Mode::NRT_PRIMITIVE_EXECUTION);
245 robot.
ExecutePrimitive(
"ZeroFTSensor", std::map<std::string, rdk::FlexivDataTypes> {});
250 "Zeroing force/torque sensors, make sure nothing is in contact with the robot");
253 while (robot.
busy()) {
254 std::this_thread::sleep_for(std::chrono::seconds(1));
256 spdlog::info(
"Sensor zeroing complete");
269 robot.
SwitchMode(rdk::Mode::RT_CARTESIAN_MOTION_FORCE);
273 std::array<bool, rdk::kCartDoF> {
false,
false,
false,
false,
false,
false});
279 auto init_q = robot.
states().
q;
284 scheduler.
AddTask(std::bind(PeriodicTask, std::ref(robot), std::ref(init_pose),
285 std::ref(init_q), enable_hold, enable_collision),
291 while (!g_stop_sched) {
292 std::this_thread::sleep_for(std::chrono::milliseconds(1));
297 }
catch (
const std::exception& e) {
298 spdlog::error(e.what());
Main interface with the robot, containing several function categories and background services.
void ExecutePlan(unsigned int index, bool continue_exec=false, bool block_until_started=true)
[Blocking] Execute a plan by specifying its index.
void SetMaxContactWrench(const std::array< double, kCartDoF > &max_wrench)
[Blocking] Set maximum contact wrench for the motion control part of the Cartesian motion-force contr...
const RobotStates states() const
[Non-blocking] Current states data of the robot.
void ExecutePrimitive(const std::string &primitive_name, const std::map< std::string, FlexivDataTypes > &input_params, const std::map< std::string, FlexivDataTypes > &properties={}, bool block_until_started=true)
[Blocking] Execute a primitive by specifying its name and parameters, which can be found in the Flexi...
const RobotInfo info() const
[Non-blocking] General information about the connected robot.
bool operational(bool verbose=true) const
[Non-blocking] Whether the robot is ready to be operated, which requires the following conditions to ...
void StreamCartesianMotionForce(const std::array< double, kPoseSize > &pose, const std::array< double, kCartDoF > &wrench={}, const std::array< double, kCartDoF > &velocity={}, const std::array< double, kCartDoF > &acceleration={})
[Non-blocking] Continuously stream Cartesian motion and/or force command for the robot to track using...
void Stop()
[Blocking] Stop the robot and transit robot mode to IDLE.
void SwitchMode(Mode mode)
[Blocking] Switch to a new control mode and wait until mode transition is finished.
void SetCartesianImpedance(const std::array< double, kCartDoF > &K_x, const std::array< double, kCartDoF > &Z_x={0.7, 0.7, 0.7, 0.7, 0.7, 0.7})
[Blocking] Set impedance properties of the robot's Cartesian motion controller used in the Cartesian ...
void SetForceControlAxis(const std::array< bool, kCartDoF > &enabled_axes, const std::array< double, kCartDoF/2 > &max_linear_vel={1.0, 1.0, 1.0})
[Blocking] Set Cartesian axes to enable force control while in the Cartesian motion-force control mod...
void Enable()
[Blocking] Enable the robot, if E-stop is released and there's no fault, the robot will release brake...
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 of the robot without a power cycle.
bool busy() const
[Non-blocking] Whether the robot is currently executing a task. This includes any user commanded oper...
void SetNullSpacePosture(const std::vector< double > &ref_positions)
[Blocking] Set reference joint positions for the null-space posture control module used in the Cartes...
Real-time scheduler that can simultaneously run multiple periodic tasks. Parameters for each task are...
int max_priority() const
[Non-blocking] Get 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...
std::array< double, kCartDoF > K_x_nom
std::array< double, kCartDoF > ext_wrench_in_world
std::vector< double > tau_ext
std::array< double, kPoseSize > tcp_pose