Skip to content

Commit 03a62bd

Browse files
authored
Add set_target_payload support to ScriptCommandInterface (UniversalRobots#515)
Adds support for the URScript `set_target_payload()` command through the `ScriptCommandInterface`, allowing users to set the payload mass, center of gravity, inertia matrix, and transition time.
1 parent e61b18d commit 03a62bd

11 files changed

Lines changed: 218 additions & 5 deletions

doc/architecture/script_command_interface.rst

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ At the time of writing the ``ScriptCommandInterface`` provides the following fun
2525
- ``setGravity()``: Set the gravity vector for the robot.
2626
- ``setTcpOffset()``: Set the TCP offset of the robot.
2727
- ``setFrictionScales()``: Set viscous and Coulomb friction scale factors for direct torque control.
28+
- ``setTargetPayload()``: Set the active payload mass, center of gravity, inertia matrix and transition time.
2829

2930
Communication protocol
3031
----------------------
@@ -58,6 +59,7 @@ The robot reads from the "script_command_socket" expecting a 32 bit integer repr
5859
- 9: setGravity
5960
- 10: setTcpOffset
6061
- 11: setFrictionScales
62+
- 12: setTargetPayload
6163
1-27 data fields specific to the command
6264
===== =====
6365

@@ -77,7 +79,7 @@ The robot reads from the "script_command_socket" expecting a 32 bit integer repr
7779
index meaning
7880
===== =====
7981
1 Payload mass in kg (floating point)
80-
2-4 Payload center of gravity in m, displacement from the toolmpount (floating point)
82+
2-4 Payload center of gravity in m, displacement from the tool mount (floating point)
8183
===== =====
8284

8385
.. table:: With setToolVoltage command
@@ -180,6 +182,18 @@ The robot reads from the "script_command_socket" expecting a 32 bit integer repr
180182
7-12 Coulomb friction scale factors. One number per joint, range [0-1]. 0 means no compensation for that joint. 1 means full compensation. Default is [0.8, 0.8, 0.7, 0.8, 0.8, 0.8]. (floating point)
181183
===== =====
182184

185+
.. table:: With setTargetPayload command
186+
:widths: auto
187+
188+
===== =====
189+
index meaning
190+
===== =====
191+
1 Payload mass in kg (floating point)
192+
2-4 Payload center of gravity in m, displacement from the tool mount (floating point)
193+
5-10 Payload inertia matrix [Ixx, Iyy, Izz, Ixy, Ixz, Iyz] in kg·m² (floating point)
194+
11 Payload transition time in seconds (floating point)
195+
===== =====
196+
183197
.. note::
184198
In URScript the ``socket_read_binary_integer()`` function is used to read the data from the
185199
script command socket. The first index in that function's return value is the number of integers read,
@@ -188,9 +202,9 @@ The robot reads from the "script_command_socket" expecting a 32 bit integer repr
188202
function. E.g. reading the boolean value for friction compensation in the
189203
``setFrictionCompensation`` command would be done by accessing index 2 of the result array.
190204

191-
All floating point data is encoded into an integer representation and has to be divided by the
192-
``MULT_JOINTSTATE`` constant to get the actual floating point value. This constant is defined in
193-
``ReverseInterface`` class.
205+
All floating point data is encoded into an integer representation and has to be divided by either the
206+
``MULT_JOINTSTATE`` or ``MULT_TIME`` constant to get the actual floating point value. These constants
207+
are defined in the ``ReverseInterface`` class.
194208

195209
Data sent from the robot
196210
^^^^^^^^^^^^^^^^^^^^^^^^

examples/script_command_interface.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,9 @@ void sendScriptCommands()
8080
run_cmd("Disabling tool contact mode", []() { g_my_robot->getUrDriver()->endToolContact(); });
8181
run_cmd("Setting TCP offset to [0.0, 0.0, 0.10, 0.0, 0.0, 0.0]",
8282
[]() { g_my_robot->getUrDriver()->setTcpOffset({ 0.0, 0.0, 0.10, 0.0, 0.0, 0.0 }); });
83+
run_cmd("Setting payload to 2.0kg with custom inertia and 0.5s transition time", []() {
84+
g_my_robot->getUrDriver()->setTargetPayload(2.0, { 0.0, 0.0, 0.1 }, { 0.003, 0.003, 0.003, 0.0, 0.0, 0.0 }, 0.5);
85+
});
8386

8487
if (g_support_set_friction_scales)
8588
{

include/ur_client_library/control/reverse_interface.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ class ReverseInterface
8282
{
8383
public:
8484
static const int32_t MULT_JOINTSTATE = 1000000;
85+
static const int32_t MULT_TIME = 1000000;
8586

8687
ReverseInterface() = delete;
8788
/*!

include/ur_client_library/control/script_command_interface.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,20 @@ class ScriptCommandInterface : public ReverseInterface
9191
*/
9292
bool setPayload(const double mass, const vector3d_t* cog);
9393

94+
/*!
95+
* \brief Set the target payload mass, center of gravity and inertia matrix
96+
*
97+
* \param mass mass in kilograms
98+
* \param cog Center of Gravity, a vector [CoGx, CoGy, CoGz] specifying the displacement (in meters) from the
99+
* toolmount
100+
* \param inertia Inertia matrix elements [Ixx, Iyy, Izz, Ixy, Ixz, Iyz]
101+
* \param transition_time Duration of the payload property changes in seconds
102+
*
103+
* \returns True, if the write was performed successfully, false otherwise.
104+
*/
105+
bool setTargetPayload(const double mass, const vector3d_t* cog, const vector6d_t* inertia,
106+
const double transition_time = 0.0);
107+
94108
/*!
95109
* \brief Set the gravity vector
96110
*
@@ -264,6 +278,7 @@ class ScriptCommandInterface : public ReverseInterface
264278
SET_GRAVITY = 9, ///< Set gravity vector
265279
SET_TCP_OFFSET = 10, ///< Set TCP offset
266280
SET_FRICTION_SCALES = 11, ///< Set viscous and Coulomb friction scales for direct_torque
281+
SET_TARGET_PAYLOAD = 12, ///< Set target payload
267282
};
268283

269284
/*!

include/ur_client_library/control/trajectory_point_interface.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@ std::string trajectoryResultToString(const TrajectoryResult result);
6363
class TrajectoryPointInterface : public ReverseInterface
6464
{
6565
public:
66-
static const int32_t MULT_TIME = 1000000;
6766
static const int MESSAGE_LENGTH = 21;
6867

6968
TrajectoryPointInterface() = delete;

include/ur_client_library/ur/ur_driver.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -631,6 +631,21 @@ class UrDriver
631631
*/
632632
bool setPayload(const float mass, const vector3d_t& cog);
633633

634+
/*!
635+
* \brief Set the target payload mass, center of gravity and inertia matrix
636+
*
637+
* \param mass mass in kilograms
638+
* \param cog Center of Gravity, a vector [CoGx, CoGy, CoGz] specifying the displacement (in meters) from the
639+
* toolmount
640+
* \param inertia Inertia matrix elements [Ixx, Iyy, Izz, Ixy, Ixz, Iyz]
641+
* \param transition_time Duration of the payload property changes in seconds
642+
*
643+
* \returns True, if the write was performed successfully, false otherwise.
644+
*/
645+
bool setTargetPayload(const float mass, const vector3d_t& cog,
646+
const vector6d_t& inertia = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 },
647+
const double transition_time = 0.0);
648+
634649
/*!
635650
* \brief Set the gravity vector. Note: It requires the external control script to be running or
636651
* the robot to be in headless mode.

resources/external_control.urscript

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ FT_RTDE_INPUT_ENABLE = 8
6767
SET_GRAVITY = 9
6868
SET_TCP_OFFSET = 10
6969
SET_FRICTION_SCALES = 11
70+
SET_TARGET_PAYLOAD = 12
7071
SCRIPT_COMMAND_DATA_DIMENSION = 28
7172

7273
FREEDRIVE_MODE_START = 1
@@ -938,6 +939,17 @@ thread script_commands():
938939
friction_compensation_mode = FRICTION_COMP_MODE_FRICTION_SCALES
939940
viscous_scale = [raw_command[2] / MULT_jointstate, raw_command[3] / MULT_jointstate, raw_command[4] / MULT_jointstate, raw_command[5] / MULT_jointstate, raw_command[6] / MULT_jointstate, raw_command[7] / MULT_jointstate]
940941
coulomb_scale = [raw_command[8] / MULT_jointstate, raw_command[9] / MULT_jointstate, raw_command[10] / MULT_jointstate, raw_command[11] / MULT_jointstate, raw_command[12] / MULT_jointstate, raw_command[13] / MULT_jointstate]
942+
elif command == SET_TARGET_PAYLOAD:
943+
mass = raw_command[2] / MULT_jointstate
944+
cog = [raw_command[3] / MULT_jointstate, raw_command[4] / MULT_jointstate, raw_command[5] / MULT_jointstate]
945+
inertia = [raw_command[6] / MULT_jointstate, raw_command[7] / MULT_jointstate, raw_command[8] / MULT_jointstate, raw_command[9] / MULT_jointstate, raw_command[10] / MULT_jointstate, raw_command[11] / MULT_jointstate]
946+
transition_time = raw_command[12] / MULT_time
947+
{% if ROBOT_SOFTWARE_VERSION >= v5.10.0 %}
948+
set_target_payload(mass, cog, inertia, transition_time)
949+
{% else %}
950+
set_payload(mass, cog)
951+
textmsg("PolyScope < 5.10.0. Inertia and transition_time ignored.")
952+
{% endif %}
941953
elif command == FT_RTDE_INPUT_ENABLE:
942954
if raw_command[2] == 0:
943955
enabled = False

src/control/script_command_interface.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,44 @@ bool ScriptCommandInterface::setPayload(const double mass, const vector3d_t* cog
9191
return server_.write(client_fd_, buffer, sizeof(buffer), written);
9292
}
9393

94+
bool ScriptCommandInterface::setTargetPayload(const double mass, const vector3d_t* cog, const vector6d_t* inertia,
95+
const double transition_time)
96+
{
97+
const int message_length = 12;
98+
uint8_t buffer[sizeof(int32_t) * MAX_MESSAGE_LENGTH];
99+
uint8_t* b_pos = buffer;
100+
int32_t val = htobe32(toUnderlying(ScriptCommand::SET_TARGET_PAYLOAD));
101+
b_pos += append(b_pos, val);
102+
103+
val = htobe32(static_cast<int32_t>(round(mass * MULT_JOINTSTATE)));
104+
b_pos += append(b_pos, val);
105+
106+
for (auto const& center_of_mass : *cog)
107+
{
108+
val = htobe32(static_cast<int32_t>(round(center_of_mass * MULT_JOINTSTATE)));
109+
b_pos += append(b_pos, val);
110+
}
111+
112+
for (auto const& inertia_val : *inertia)
113+
{
114+
val = htobe32(static_cast<int32_t>(round(inertia_val * MULT_JOINTSTATE)));
115+
b_pos += append(b_pos, val);
116+
}
117+
118+
val = htobe32(static_cast<int32_t>(round(transition_time * MULT_TIME)));
119+
b_pos += append(b_pos, val);
120+
121+
// writing zeros to allow usage with other script commands
122+
for (size_t i = message_length; i < MAX_MESSAGE_LENGTH; i++)
123+
{
124+
val = htobe32(0);
125+
b_pos += append(b_pos, val);
126+
}
127+
size_t written;
128+
129+
return server_.write(client_fd_, buffer, sizeof(buffer), written);
130+
}
131+
94132
bool ScriptCommandInterface::setGravity(const vector3d_t* gravity)
95133
{
96134
const int message_length = 4;

src/ur/ur_driver.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,41 @@ bool UrDriver::setPayload(const float mass, const vector3d_t& cog)
313313
}
314314
}
315315

316+
bool UrDriver::setTargetPayload(const float mass, const vector3d_t& cog, const vector6d_t& inertia,
317+
const double transition_time)
318+
{
319+
if (script_command_interface_->clientConnected())
320+
{
321+
return script_command_interface_->setTargetPayload(mass, &cog, &inertia, transition_time);
322+
}
323+
else
324+
{
325+
URCL_LOG_WARN("Script command interface is not running. Falling back to sending plain script code. On e-Series "
326+
"robots this will only work, if the robot is in remote_control mode.");
327+
328+
std::stringstream cmd;
329+
cmd.imbue(std::locale::classic()); // Make sure, decimal divider is actually '.'
330+
331+
if ((getVersion().major > 5) || (getVersion().major == 5 && getVersion().minor >= 10))
332+
{
333+
cmd << "sec setup():" << std::endl
334+
<< " set_target_payload(" << mass << ", [" << cog[0] << ", " << cog[1] << ", " << cog[2] << "] , ["
335+
<< inertia[0] << ", " << inertia[1] << ", " << inertia[2] << ", " << inertia[3] << ", " << inertia[4] << ", "
336+
<< inertia[5] << "] , " << transition_time << ")" << std::endl
337+
<< "end";
338+
}
339+
else
340+
{
341+
cmd << "sec setup():" << std::endl
342+
<< " set_payload(" << mass << ", [" << cog[0] << ", " << cog[1] << ", " << cog[2] << "])" << std::endl
343+
<< " textmsg(\"PolyScope < 5.10.0. Inertia and transition_time ignored.\")" << std::endl
344+
<< "end";
345+
}
346+
347+
return sendScript(cmd.str());
348+
}
349+
}
350+
316351
bool UrDriver::setGravity(const vector3d_t& gravity)
317352
{
318353
if (script_command_interface_->clientConnected())

tests/test_script_command_interface.cpp

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,54 @@ TEST_F(ScriptCommandInterfaceTest, test_set_payload)
225225
EXPECT_EQ(message_sum, expected_message_sum);
226226
}
227227

228+
TEST_F(ScriptCommandInterfaceTest, test_set_target_payload)
229+
{
230+
// Wait for the client to connect to the server
231+
waitForClientConnection();
232+
233+
double mass = 1.0;
234+
vector3d_t cog = { 0.2, 0.3, 0.1 };
235+
vector6d_t inertia = { 0.4, 0.7, 0.8, 0.2, 0.5, 0.6 };
236+
double transition_time = 0.002;
237+
script_command_interface_->setTargetPayload(mass, &cog, &inertia, transition_time);
238+
int32_t command;
239+
std::vector<int32_t> message;
240+
client_->readMessage(command, message);
241+
242+
// 12 is set target payload
243+
int32_t expected_command = 12;
244+
EXPECT_EQ(command, expected_command);
245+
246+
// Test mass
247+
double received_mass = (double)message[0] / script_command_interface_->MULT_JOINTSTATE;
248+
EXPECT_EQ(received_mass, mass);
249+
250+
// Test cog
251+
vector3d_t received_cog;
252+
for (unsigned int i = 0; i < cog.size(); ++i)
253+
{
254+
received_cog[i] = (double)message[i + 1] / script_command_interface_->MULT_JOINTSTATE;
255+
EXPECT_EQ(received_cog[i], cog[i]);
256+
}
257+
258+
// Test inertia
259+
vector6d_t received_inertia;
260+
for (unsigned int i = 0; i < inertia.size(); ++i)
261+
{
262+
received_inertia[i] = (double)message[i + 4] / script_command_interface_->MULT_JOINTSTATE;
263+
EXPECT_EQ(received_inertia[i], inertia[i]);
264+
}
265+
266+
// Test transition time
267+
double received_transition_time = (double)message[10] / script_command_interface_->MULT_TIME;
268+
EXPECT_EQ(received_transition_time, transition_time);
269+
270+
// The rest of the message should be zero
271+
int32_t message_sum = std::accumulate(std::begin(message) + 11, std::end(message), 0);
272+
int32_t expected_message_sum = 0;
273+
EXPECT_EQ(message_sum, expected_message_sum);
274+
}
275+
228276
TEST_F(ScriptCommandInterfaceTest, test_set_tool_voltage)
229277
{
230278
// Wait for the client to connect to the server

0 commit comments

Comments
 (0)