Skip to content

Commit d3baa8b

Browse files
URJalaurfeex
andauthored
Giving force mode parameters as arguments when calling startForceMode (#208)
Co-authored-by: Felix Exner <[email protected]>
1 parent ddbea36 commit d3baa8b

File tree

8 files changed

+422
-86
lines changed

8 files changed

+422
-86
lines changed

examples/force_mode_example.cpp

Lines changed: 60 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,21 @@ const std::string CALIBRATION_CHECKSUM = "calib_12788084448423163542";
5555
std::unique_ptr<UrDriver> g_my_driver;
5656
std::unique_ptr<DashboardClient> g_my_dashboard;
5757

58+
std::condition_variable g_program_running_cv_;
59+
std::mutex g_program_running_mutex_;
60+
bool g_program_running;
61+
5862
// We need a callback function to register. See UrDriver's parameters for details.
5963
void handleRobotProgramState(bool program_running)
6064
{
6165
// Print the text in green so we see it better
6266
std::cout << "\033[1;32mProgram running: " << std::boolalpha << program_running << "\033[0m\n" << std::endl;
67+
if (program_running)
68+
{
69+
std::lock_guard<std::mutex> lk(g_program_running_mutex_);
70+
g_program_running = program_running;
71+
g_program_running_cv_.notify_one();
72+
}
6373
}
6474

6575
void sendFreedriveMessageOrDie(const control::FreedriveControlMessage freedrive_action)
@@ -72,6 +82,17 @@ void sendFreedriveMessageOrDie(const control::FreedriveControlMessage freedrive_
7282
}
7383
}
7484

85+
bool waitForProgramRunning(int milliseconds = 100)
86+
{
87+
std::unique_lock<std::mutex> lk(g_program_running_mutex_);
88+
if (g_program_running_cv_.wait_for(lk, std::chrono::milliseconds(milliseconds)) == std::cv_status::no_timeout ||
89+
g_program_running == true)
90+
{
91+
return true;
92+
}
93+
return false;
94+
}
95+
7596
int main(int argc, char* argv[])
7697
{
7798
urcl::setLogLevel(urcl::LogLevel::INFO);
@@ -130,7 +151,16 @@ int main(int argc, char* argv[])
130151
std::unique_ptr<ToolCommSetup> tool_comm_setup;
131152
const bool HEADLESS = true;
132153
g_my_driver.reset(new UrDriver(robot_ip, SCRIPT_FILE, OUTPUT_RECIPE, INPUT_RECIPE, &handleRobotProgramState, HEADLESS,
133-
std::move(tool_comm_setup), CALIBRATION_CHECKSUM));
154+
std::move(tool_comm_setup)));
155+
156+
if (!g_my_driver->checkCalibration(CALIBRATION_CHECKSUM))
157+
{
158+
URCL_LOG_ERROR("Calibration checksum does not match actual robot.");
159+
URCL_LOG_ERROR("Use the ur_calibration tool to extract the correct calibration from the robot and pass that into "
160+
"the description. See "
161+
"[https://github.com/UniversalRobots/Universal_Robots_ROS_Driver#extract-calibration-information] "
162+
"for details.");
163+
}
134164

135165
// Once RTDE communication is started, we have to make sure to read from the interface buffer, as
136166
// otherwise we will get pipeline overflows. Therefore, do this directly before starting your main
@@ -141,15 +171,37 @@ int main(int argc, char* argv[])
141171
std::chrono::duration<double> timeout(second_to_run);
142172
auto stopwatch_last = std::chrono::steady_clock::now();
143173
auto stopwatch_now = stopwatch_last;
144-
g_my_driver->writeKeepalive();
174+
// Make sure that external control script is running
175+
if (!waitForProgramRunning())
176+
{
177+
URCL_LOG_ERROR("External Control script not running.");
178+
return 1;
179+
}
145180
// Task frame at the robot's base with limits being large enough to cover the whole workspace
146181
// Compliance in z axis and rotation around z axis
147-
g_my_driver->startForceMode({ 0, 0, 0, 0, 0, 0 }, // Task frame at the robot's base
148-
{ 0, 0, 1, 0, 0, 1 }, // Compliance in z axis and rotation around z axis
149-
{ 0, 0, 0, 0, 0, 0 }, // do not apply any active wrench
150-
2, // do not transform the force frame at all
151-
{ 0.1, 0.1, 1.5, 3.14, 3.14, 0.5 }); // limits. See ScriptManual for
152-
// details.
182+
bool success;
183+
if (g_my_driver->getVersion().major < 5)
184+
success = g_my_driver->startForceMode({ 0, 0, 0, 0, 0, 0 }, // Task frame at the robot's base
185+
{ 0, 0, 1, 0, 0, 1 }, // Compliance in z axis and rotation around z axis
186+
{ 0, 0, 0, 0, 0, 0 }, // do not apply any active wrench
187+
2, // do not transform the force frame at all
188+
{ 0.1, 0.1, 1.5, 3.14, 3.14, 0.5 }, // limits
189+
0.025); // damping_factor. See ScriptManual for details.
190+
else
191+
{
192+
success = g_my_driver->startForceMode({ 0, 0, 0, 0, 0, 0 }, // Task frame at the robot's base
193+
{ 0, 0, 1, 0, 0, 1 }, // Compliance in z axis and rotation around z axis
194+
{ 0, 0, 0, 0, 0, 0 }, // do not apply any active wrench
195+
2, // do not transform the force frame at all
196+
{ 0.1, 0.1, 1.5, 3.14, 3.14, 0.5 }, // limits
197+
0.025, // damping_factor
198+
0.8); // gain_scaling. See ScriptManual for details.
199+
}
200+
if (!success)
201+
{
202+
URCL_LOG_ERROR("Failed to start force mode.");
203+
return 1;
204+
}
153205

154206
while (true)
155207
{

include/ur_client_library/control/script_command_interface.h

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -105,14 +105,23 @@ class ScriptCommandInterface : public ReverseInterface
105105
* 2: The force frame is not transformed.
106106
* 3: The force frame is transformed in a way such that its x-axis is the projection of the robot tcp velocity vector
107107
* onto the x-y plane of the force frame
108-
* \param limits (Float) 6d vector. For compliant axes, these values are the maximum allowed tcp speed along/about the
108+
* \param limits 6d vector. For compliant axes, these values are the maximum allowed tcp speed along/about the
109109
* axis. For non-compliant axes, these values are the maximum allowed deviation along/about an axis between the actual
110110
* tcp position and the one set by the program
111111
*
112+
* \param damping_factor Sets the damping parameter in force mode. In range [0,1], default value is 0.025
113+
* A value of 1 is full damping, so the robot will decelerate quickly if no force is present. A value of 0
114+
* is no damping, here the robot will maintain the speed.
115+
*
116+
* \param gain_scaling_factor Scales the gain in force mode. scaling parameter is in range [0,2], default
117+
* is 0.5. A value larger than 1 can make force mode unstable, e.g. in case of collisions or pushing against hard
118+
* surfaces.
119+
*
112120
* \returns True, if the write was performed successfully, false otherwise.
113121
*/
114122
bool startForceMode(const vector6d_t* task_frame, const vector6uint32_t* selection_vector, const vector6d_t* wrench,
115-
const unsigned int type, const vector6d_t* limits);
123+
const unsigned int type, const vector6d_t* limits, double damping_factor,
124+
double gain_scaling_factor);
116125

117126
/*!
118127
* \brief Stop force mode and put the robot into normal operation mode.
@@ -178,7 +187,7 @@ class ScriptCommandInterface : public ReverseInterface
178187
};
179188

180189
bool client_connected_;
181-
static const int MAX_MESSAGE_LENGTH = 26;
190+
static const int MAX_MESSAGE_LENGTH = 28;
182191

183192
std::function<void(ToolContactResult)> handle_tool_contact_result_;
184193
};

include/ur_client_library/exceptions.h

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include <chrono>
3333
#include <stdexcept>
3434
#include <sstream>
35+
#include "ur/version_information.h"
3536

3637
namespace urcl
3738
{
@@ -124,5 +125,67 @@ class TimeoutException : public UrException
124125
private:
125126
std::string text_;
126127
};
128+
129+
class IncompatibleRobotVersion : public UrException
130+
{
131+
public:
132+
explicit IncompatibleRobotVersion() = delete;
133+
explicit IncompatibleRobotVersion(const std::string& text, const VersionInformation& minimum_robot_version,
134+
const VersionInformation& actual_robot_version)
135+
: std::runtime_error(text)
136+
{
137+
std::stringstream ss;
138+
ss << text << "\n"
139+
<< "The requested feature is incompatible with the connected robot. Minimum required Polyscope version: "
140+
<< minimum_robot_version << ", actual Polyscope version: " << actual_robot_version;
141+
text_ = ss.str();
142+
}
143+
virtual const char* what() const noexcept override
144+
{
145+
return text_.c_str();
146+
}
147+
148+
private:
149+
std::string text_;
150+
};
151+
152+
class InvalidRange : public UrException
153+
{
154+
private:
155+
std::string text_;
156+
157+
public:
158+
explicit InvalidRange() = delete;
159+
explicit InvalidRange(std::string text) : std::runtime_error(text)
160+
{
161+
text_ = text;
162+
}
163+
virtual const char* what() const noexcept override
164+
{
165+
return text_.c_str();
166+
}
167+
};
168+
169+
class MissingArgument : public UrException
170+
{
171+
private:
172+
std::string text_;
173+
174+
public:
175+
explicit MissingArgument() = delete;
176+
explicit MissingArgument(std::string text, std::string function_name, std::string argument_name, float default_value)
177+
: std::runtime_error("")
178+
{
179+
std::stringstream ss;
180+
ss << text << "\nMissing argument when calling function: " << function_name
181+
<< ". \nArgument missing: " << argument_name
182+
<< ". \nSet to default value if not important, default value is: " << default_value;
183+
text_ = ss.str();
184+
}
185+
virtual const char* what() const noexcept override
186+
{
187+
return text_.c_str();
188+
}
189+
};
127190
} // namespace urcl
128191
#endif // ifndef UR_CLIENT_LIBRARY_EXCEPTIONS_H_INCLUDED

0 commit comments

Comments
 (0)