This tutorial shows a demo implementation for teach by demonstration: free-drive the robot and record a series of Cartesian poses, which are then reproduced by the robot.
#include <iostream>
#include <mutex>
#include <thread>
#include <atomic>
namespace {
std::string g_userInput;
std::mutex g_userInputMutex;
const std::vector<double> k_maxContactWrench = {50.0, 50.0, 50.0, 15.0, 15.0, 15.0};
}
void printDescription()
{
std::cout
<< "This tutorial shows a demo implementation for teach by demonstration: free-drive the "
"robot and record a series of Cartesian poses, which are then reproduced by the robot."
<< std::endl
<< std::endl;
}
void printHelp()
{
std::cout << "Required arguments: [robot IP] [local IP]" << std::endl;
std::cout << " robot IP: address of the robot server" << std::endl;
std::cout << " local IP: address of this PC" << std::endl;
std::cout << "Optional arguments: None" << std::endl;
std::cout << std::endl;
}
int main(int argc, char* argv[])
{
if (argc < 3 ||
flexiv::utility::programArgsExistAny(argc, argv, {
"-h",
"--help"})) {
printHelp();
return 1;
}
std::string robotIP = argv[1];
std::string localIP = argv[2];
log.
info(
"Tutorial description:");
printDescription();
try {
if (robot.isFault()) {
log.
warn(
"Fault occurred on robot server, trying to clear ...");
robot.clearFault();
std::this_thread::sleep_for(std::chrono::seconds(2));
if (robot.isFault()) {
log.
error(
"Fault cannot be cleared, exiting ...");
return 1;
}
log.
info(
"Fault on robot server is cleared");
}
log.
info(
"Enabling robot ...");
robot.enable();
while (!robot.isOperational()) {
std::this_thread::sleep_for(std::chrono::seconds(1));
}
log.
info(
"Robot is now operational");
std::vector<std::vector<double>> savedPoses = {};
log.
info(
"Accepted key inputs:");
std::cout << "[n] - start new teaching process" << std::endl;
std::cout << "[r] - record current robot pose" << std::endl;
std::cout << "[e] - finish recording and start execution" << std::endl;
std::string inputBuffer;
while (true) {
std::cin >> inputBuffer;
if (inputBuffer == "n") {
savedPoses.clear();
robot.setMode(
flexiv::Mode::NRT_PLAN_EXECUTION);
robot.executePlan("PLAN-FreeDriveAuto");
log.
info(
"New teaching process started");
log.
warn(
"Hold down the enabling button on the motion bar to activate free drive");
}
else if (inputBuffer == "r") {
if (!robot.isBusy()) {
log.
warn(
"Please start a new teaching process first");
continue;
}
robot.getRobotStates(robotStates);
savedPoses.push_back(robotStates.
tcpPose);
log.
info(
"New pose saved: " +
flexiv::utility::vec2Str(robotStates.
tcpPose));
log.
info(
"Number of saved poses: " + std::to_string(savedPoses.size()));
}
else if (inputBuffer == "e") {
if (savedPoses.empty()) {
log.
warn(
"No pose is saved yet");
continue;
}
robot.setMode(
flexiv::Mode::NRT_PRIMITIVE_EXECUTION);
for (size_t i = 0; i < savedPoses.size(); i++) {
log.
info(
"Executing pose " + std::to_string(i + 1) +
"/"
+ std::to_string(savedPoses.size()));
std::vector<double> targetPos
= {savedPoses[i][0], savedPoses[i][1], savedPoses[i][2]};
std::vector<double> targetQuat
= {savedPoses[i][3], savedPoses[i][4], savedPoses[i][5], savedPoses[i][6]};
auto targetEulerDeg
robot.executePrimitive(
"MoveCompliance(target="
+ flexiv::utility::vec2Str(targetPos)
+ flexiv::utility::vec2Str(targetEulerDeg)
+ "WORLD WORLD_ORIGIN, maxVel=0.3, enableMaxContactWrench=1, maxContactWrench="
+ flexiv::utility::vec2Str(k_maxContactWrench)+ ")");
while (
flexiv::utility::parsePtStates(robot.getPrimitiveStates(),
"reachedTarget")
!= "1") {
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
"All saved poses are executed, enter 'n' to start a new teaching process, 'r' "
"to record more poses, 'e' to repeat execution");
robot.setMode(flexiv::Mode::NRT_PLAN_EXECUTION);
robot.executePlan("PLAN-FreeDriveAuto");
} else {
log.
warn(
"Invalid input");
}
}
return 1;
}
return 0;
}
double rad2Deg(double rad)
Convert radians to degrees for a single value.
Base class for all custom runtime exception classes.
Helper functions to print messages with timestamp and coloring. Logging raw data to csv file coming s...
void warn(const std::string &message) const
[Non-blocking] Print warning message with timestamp and coloring.
void info(const std::string &message) const
[Non-blocking] Print info message with timestamp and coloring.
void error(const std::string &message) const
[Non-blocking] Print error message with timestamp and coloring.
Main interface with the robot, containing several function categories and background services.
Data struct containing the joint- and Cartesian-space robot states.
std::vector< double > tcpPose