Skip to content

Commit a457828

Browse files
urmahpurfeex
andcommitted
Added commands to set pd controller gains and maximum joint torques (#342)
Co-authored-by: Felix Exner <[email protected]>
1 parent f470af0 commit a457828

File tree

8 files changed

+272
-8
lines changed

8 files changed

+272
-8
lines changed

doc/architecture/script_command_interface.rst

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ At the time of writing the ``ScriptCommandInterface`` provides the following fun
2222
for more information.
2323
- ``setFrictionCompensation()``: Set friction compensation for torque command.
2424
- ``ftRtdeInputEnable()``: Enable/disable FT RTDE input processing.
25+
- ``setPDControllerGains()``: Set PD gains for the PD control loop running in the external control script.
26+
- ``setMaxJointTorques()``: Set Max joint torques for the PD control loop running in the external control script.
2527

2628
Communication protocol
2729
----------------------
@@ -52,6 +54,8 @@ The robot reads from the "script_command_socket" expecting a 32 bit integer repr
5254
- 6: endToolContact
5355
- 7: setFrictionCompensation
5456
- 8: ftRtdeInputEnable
57+
- 9: setPDControllerGains
58+
- 10: setMaxJointTorques
5559
1-27 data fields specific to the command
5660
===== =====
5761

@@ -144,6 +148,24 @@ The robot reads from the "script_command_socket" expecting a 32 bit integer repr
144148
2 sensor_mass in kg (floating point)
145149
3-5 sensor_mesurement_offset in m, displacement from the tool flange (3d floating point)
146150
6-9 sensor_cog in m, displacement from the tool flange (3d floating point)
151+
152+
.. table:: With setPDControllerGains command
153+
:widths: auto
154+
155+
===== =====
156+
index meaning
157+
===== =====
158+
1-6 Kp gains for each joint, used in the PD control loop running in the external control script (floating point)
159+
7-12 Kd gains for each joint, used in the PD control loop running in the external control script (floating point)
160+
===== =====
161+
162+
.. table:: With setMaxJointTorques command
163+
:widths: auto
164+
165+
===== =====
166+
index meaning
167+
===== =====
168+
1-6 max_joint_torques for each joint, used to clamp the torques between +-max_joint_torques before applying them to the robot in the PD control loop running in the external control script (floating point)
147169
===== =====
148170

149171
.. note::

examples/script_command_interface.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,12 @@ void sendScriptCommands()
7474
run_cmd("Disabling tool contact mode", []() { g_my_robot->getUrDriver()->endToolContact(); });
7575
run_cmd("Setting friction_compensation variable to `true`",
7676
[]() { g_my_robot->getUrDriver()->setFrictionCompensation(true); });
77+
run_cmd("Setting PD controller gains", []() {
78+
g_my_robot->getUrDriver()->setPDControllerGains({ 500.0, 500.0, 300.0, 124.0, 124.0, 124.0 },
79+
{ 44.72, 44.72, 34.64, 22.27, 22.27, 22.27 });
80+
});
81+
run_cmd("Setting max joint torques",
82+
[]() { g_my_robot->getUrDriver()->setMaxJointTorques({ 27.0, 27.0, 14.0, 4.5, 4.5, 4.5 }); });
7783
}
7884
URCL_LOG_INFO("Script command thread finished.");
7985
}

include/ur_client_library/control/script_command_interface.h

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -158,11 +158,11 @@ class ScriptCommandInterface : public ReverseInterface
158158
bool endToolContact();
159159

160160
/*!
161-
* \brief Set friction compensation for the torque_command. If true the torque command will compensate for friction,
162-
* if false it will not.
161+
* \brief Set friction compensation for the direct_torque command. If true the torque command will compensate for
162+
* friction, if false it will not.
163163
*
164164
* \param friction_compensation_enabled Will set a friction_compensation_enabled variable in urscript, which will be
165-
* used when calling torque_command
165+
* used when calling direct_torque.
166166
*
167167
* \returns True, if the write was performed successfully, false otherwise.
168168
*/
@@ -188,6 +188,32 @@ class ScriptCommandInterface : public ReverseInterface
188188
const vector3d_t& sensor_measuring_offset = { 0.0, 0.0, 0.0 },
189189
const vector3d_t& sensor_cog = { 0.0, 0.0, 0.0 });
190190

191+
/*!
192+
* \brief Set gains for the PD controller running in the external control script. The PD controller computes joint
193+
* torques based on either tcp poses or joint poses and applies the torques to the robot using the direct_torque
194+
* function. The gains can be used to change the response of the controller. Be aware that changing the controller
195+
* response can make it unstable.
196+
* The PD controller can be used without explicitly defining those gains, as it contains a set of default gains for
197+
* each robot model.
198+
*
199+
* \param kp A vector6d of proportional gains for each of the joints in the robot.
200+
* \param kd A vector6d of derivative gains for each of the joints in the robot.
201+
*
202+
* \returns True, if the write was performed successfully, false otherwise.
203+
*/
204+
bool setPDControllerGains(const urcl::vector6d_t* kp, const urcl::vector6d_t* kd);
205+
206+
/*!
207+
* \brief Set the maximum joint torques for the PD controller running in the external control script. The PD
208+
* controller will clamp the torques between +-max_joint_torques before aplying them to the robot using the
209+
* direct_torque function.
210+
*
211+
* \param max_joint_torques A vector6d of the maximum joint torques for each of the joints.
212+
*
213+
* \returns True, if the write was performed successfully, false otherwise.
214+
*/
215+
bool setMaxJointTorques(const urcl::vector6d_t* max_joint_torques);
216+
191217
/*!
192218
* \brief Returns whether a client/robot is connected to this server.
193219
*
@@ -227,6 +253,8 @@ class ScriptCommandInterface : public ReverseInterface
227253
END_TOOL_CONTACT = 6, ///< End detecting tool contact
228254
SET_FRICTION_COMPENSATION = 7, ///< Set friction compensation
229255
FT_RTDE_INPUT_ENABLE = 8, ///< Enable FT RTDE input
256+
SET_PD_CONTROLLER_GAINS = 9, ///< Set PD controller gains
257+
SET_MAX_JOINT_TORQUES = 10, ///< Set max joint torques
230258
};
231259

232260
/*!

include/ur_client_library/ur/ur_driver.h

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -716,11 +716,11 @@ class UrDriver
716716
bool endToolContact();
717717

718718
/*!
719-
* \brief Set friction compensation for the torque_command. If true the torque command will compensate for friction,
720-
* if false it will not.
719+
* \brief Set friction compensation for the direct_torque command. If true the torque command will compensate for
720+
* friction, if false it will not.
721721
*
722722
* \param friction_compensation_enabled Will set a friction_compensation_enabled variable in urscript, which will be
723-
* used when calling torque_command
723+
* used when calling direct_torque.
724724
*
725725
* \returns True, if the write was performed successfully, false otherwise.
726726
*/
@@ -746,6 +746,32 @@ class UrDriver
746746
const vector3d_t& sensor_measuring_offset = { 0.0, 0.0, 0.0 },
747747
const vector3d_t& sensor_cog = { 0.0, 0.0, 0.0 });
748748

749+
/*!
750+
* \brief Set gains for the PD controller running in the external control script. The PD controller computes joint
751+
* torques based on either tcp poses or joint poses and applies the torques to the robot using the direct_torque
752+
* function. The gains can be used to change the response of the controller. Be aware that changing the controller
753+
* response can make it unstable.
754+
* The PD controller can be used without explicitly defining those gains, as it contains a set of default gains for
755+
* each robot model.
756+
*
757+
* \param kp A vector6d of proportional gains for each of the joints in the robot.
758+
* \param kd A vector6d of derivative gains for each of the joints in the robot.
759+
*
760+
* \returns True, if the write was performed successfully, false otherwise.
761+
*/
762+
bool setPDControllerGains(const urcl::vector6d_t& kp, const urcl::vector6d_t& kd);
763+
764+
/*!
765+
* \brief Set the maximum joint torques for the PD controller running in the external control script. The PD
766+
* controller will clamp the torques between +-max_joint_torques before aplying them to the robot using the
767+
* direct_torque function.
768+
*
769+
* \param max_joint_torques A vector6d of the maximum joint torques for each of the joints.
770+
*
771+
* \returns True, if the write was performed successfully, false otherwise.
772+
*/
773+
bool setMaxJointTorques(const urcl::vector6d_t& max_joint_torques);
774+
749775
/*!
750776
* \brief Write a keepalive signal only.
751777
*

resources/external_control.urscript

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ START_TOOL_CONTACT = 5
5757
END_TOOL_CONTACT = 6
5858
SET_FRICTION_COMPENSATION = 7
5959
FT_RTDE_INPUT_ENABLE = 8
60+
SET_PD_CONTROLLER_GAINS = 9
61+
SET_MAX_JOINT_TORQUES = 10
6062
SCRIPT_COMMAND_DATA_DIMENSION = 28
6163

6264
FREEDRIVE_MODE_START = 1
@@ -857,6 +859,11 @@ thread script_commands():
857859
# This has a known error that the resulting torques are computed with opposite sign.
858860
enable_external_ft_sensor(enabled, sensor_mass, sensor_offset, sensor_cog)
859861
{% endif %}
862+
elif command == SET_PD_CONTROLLER_GAINS:
863+
pd_controller_gains.kp = [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]
864+
pd_controller_gains.kd = [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]
865+
elif command == SET_MAX_JOINT_TORQUES:
866+
max_joint_torques = [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]
860867
end
861868
end
862869
end

src/control/script_command_interface.cpp

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,64 @@ bool ScriptCommandInterface::ftRtdeInputEnable(const bool enabled, const double
293293
return server_.write(client_fd_, buffer, sizeof(buffer), written);
294294
}
295295

296+
bool ScriptCommandInterface::setPDControllerGains(const urcl::vector6d_t* kp, const urcl::vector6d_t* kd)
297+
{
298+
const int message_length = 13;
299+
uint8_t buffer[sizeof(int32_t) * MAX_MESSAGE_LENGTH];
300+
uint8_t* b_pos = buffer;
301+
302+
int32_t val = htobe32(toUnderlying(ScriptCommand::SET_PD_CONTROLLER_GAINS));
303+
b_pos += append(b_pos, val);
304+
305+
for (auto const& p_gain : *kp)
306+
{
307+
val = htobe32(static_cast<int32_t>(round(p_gain * MULT_JOINTSTATE)));
308+
b_pos += append(b_pos, val);
309+
}
310+
311+
for (auto const& d_gain : *kd)
312+
{
313+
val = htobe32(static_cast<int32_t>(round(d_gain * MULT_JOINTSTATE)));
314+
b_pos += append(b_pos, val);
315+
}
316+
317+
// writing zeros to allow usage with other script commands
318+
for (size_t i = message_length; i < MAX_MESSAGE_LENGTH; i++)
319+
{
320+
val = htobe32(0);
321+
b_pos += append(b_pos, val);
322+
}
323+
size_t written;
324+
325+
return server_.write(client_fd_, buffer, sizeof(buffer), written);
326+
}
327+
328+
bool ScriptCommandInterface::setMaxJointTorques(const urcl::vector6d_t* max_joint_torques)
329+
{
330+
const int message_length = 7;
331+
uint8_t buffer[sizeof(int32_t) * MAX_MESSAGE_LENGTH];
332+
uint8_t* b_pos = buffer;
333+
334+
int32_t val = htobe32(toUnderlying(ScriptCommand::SET_MAX_JOINT_TORQUES));
335+
b_pos += append(b_pos, val);
336+
337+
for (auto const& max_torque : *max_joint_torques)
338+
{
339+
val = htobe32(static_cast<int32_t>(round(max_torque * MULT_JOINTSTATE)));
340+
b_pos += append(b_pos, val);
341+
}
342+
343+
// writing zeros to allow usage with other script commands
344+
for (size_t i = message_length; i < MAX_MESSAGE_LENGTH; i++)
345+
{
346+
val = htobe32(0);
347+
b_pos += append(b_pos, val);
348+
}
349+
size_t written;
350+
351+
return server_.write(client_fd_, buffer, sizeof(buffer), written);
352+
}
353+
296354
bool ScriptCommandInterface::clientConnected()
297355
{
298356
return client_connected_;
@@ -360,4 +418,4 @@ bool ScriptCommandInterface::robotVersionSupportsCommandOrWarn(const VersionInfo
360418
}
361419

362420
} // namespace control
363-
} // namespace urcl
421+
} // namespace urcl

src/ur/ur_driver.cpp

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -571,6 +571,54 @@ bool UrDriver::ftRtdeInputEnable(const bool enabled, const double sensor_mass,
571571
}
572572
}
573573

574+
bool UrDriver::setPDControllerGains(const urcl::vector6d_t& kp, const urcl::vector6d_t& kd)
575+
{
576+
if (!std::all_of(kp.begin(), kp.end(), [](double v) { return v >= 0.0; }))
577+
{
578+
throw InvalidRange("kp should be larger than zero");
579+
}
580+
581+
if (!std::all_of(kd.begin(), kd.end(), [](double v) { return v >= 0.0; }))
582+
{
583+
throw InvalidRange("kd should be larger than zero");
584+
}
585+
586+
if (script_command_interface_->clientConnected())
587+
{
588+
return script_command_interface_->setPDControllerGains(&kp, &kd);
589+
}
590+
else
591+
{
592+
URCL_LOG_ERROR("Script command interface is not running. Unable to set PD Controller gains.");
593+
return 0;
594+
}
595+
}
596+
597+
bool UrDriver::setMaxJointTorques(const urcl::vector6d_t& max_joint_torques)
598+
{
599+
const urcl::vector6d_t max_torques_for_robot_type =
600+
control::getMaxTorquesFromRobotType(primary_client_->getRobotType());
601+
if (!std::equal(max_joint_torques.begin(), max_joint_torques.end(), max_torques_for_robot_type.begin(),
602+
[](double v1, double v2) { return v1 <= v2 && v1 >= 0.0; }))
603+
{
604+
std::stringstream ss;
605+
ss << "The max joint torques should be smaller or equal to the maximum joint torques for the robot type and larger "
606+
"than zero. Provided max joint torques "
607+
<< max_joint_torques << " and maximum joint torques for the robot type " << max_torques_for_robot_type;
608+
throw InvalidRange(ss.str().c_str());
609+
}
610+
611+
if (script_command_interface_->clientConnected())
612+
{
613+
return script_command_interface_->setMaxJointTorques(&max_joint_torques);
614+
}
615+
else
616+
{
617+
URCL_LOG_ERROR("Script command interface is not running. Unable to set max joint torques.");
618+
return 0;
619+
}
620+
}
621+
574622
bool UrDriver::writeKeepalive(const RobotReceiveTimeout& robot_receive_timeout)
575623
{
576624
vector6d_t* fake = nullptr;

tests/test_script_command_interface.cpp

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -431,7 +431,6 @@ TEST_F(ScriptCommandInterfaceTest, test_ft_rtde_input_enable)
431431
{
432432
// Wait for the client to connect to the server
433433
waitForClientConnection();
434-
435434
double sensor_mass = 1.42;
436435
vector3d_t sensor_measuring_offset = { 0.1, 0.2, 0.3 };
437436
vector3d_t sensor_cog = { 0.01, 0.02, 0.03 };
@@ -482,6 +481,76 @@ TEST_F(ScriptCommandInterfaceTest, test_ft_rtde_input_enable)
482481
EXPECT_EQ(received_enabled, false);
483482
}
484483

484+
TEST_F(ScriptCommandInterfaceTest, test_set_pd_controller_gains)
485+
{
486+
// Wait for the client to connect to the server
487+
waitForClientConnection();
488+
489+
urcl::vector6d_t kp = { 220.2, 220.2, 300.0, 10.32, 10.32, 10.32 };
490+
urcl::vector6d_t kd = { 29.68, 29.68, 35.0, 6.4, 6.4, 6.4 };
491+
script_command_interface_->setPDControllerGains(&kp, &kd);
492+
493+
int32_t command;
494+
std::vector<int32_t> message;
495+
client_->readMessage(command, message);
496+
497+
// 8 is set PD controller gains
498+
int32_t expected_command = 9;
499+
EXPECT_EQ(command, expected_command);
500+
501+
int32_t message_idx = 0;
502+
503+
for (auto& p_gain : kp)
504+
{
505+
const double received_gain = (double)message[message_idx] / script_command_interface_->MULT_JOINTSTATE;
506+
EXPECT_EQ(p_gain, received_gain);
507+
message_idx = message_idx + 1;
508+
}
509+
510+
for (auto& d_gain : kd)
511+
{
512+
const double received_gain = (double)message[message_idx] / script_command_interface_->MULT_JOINTSTATE;
513+
EXPECT_EQ(d_gain, received_gain);
514+
message_idx = message_idx + 1;
515+
}
516+
517+
// The rest of the message should be zero
518+
int32_t message_sum = std::accumulate(std::begin(message) + message_idx, std::end(message), 0);
519+
int32_t expected_message_sum = 0;
520+
EXPECT_EQ(message_sum, expected_message_sum);
521+
}
522+
523+
TEST_F(ScriptCommandInterfaceTest, test_set_max_joint_torques)
524+
{
525+
// Wait for the client to connect to the server
526+
waitForClientConnection();
527+
528+
urcl::vector6d_t max_joint_torques = { 100.0, 150.0, 21.2, 10.32, 10.32, 10.32 };
529+
script_command_interface_->setMaxJointTorques(&max_joint_torques);
530+
531+
int32_t command;
532+
std::vector<int32_t> message;
533+
client_->readMessage(command, message);
534+
535+
// 9 is set max joint torques
536+
int32_t expected_command = 10;
537+
EXPECT_EQ(command, expected_command);
538+
539+
int32_t message_idx = 0;
540+
541+
for (auto& max_torque : max_joint_torques)
542+
{
543+
const double received_max_torque = (double)message[message_idx] / script_command_interface_->MULT_JOINTSTATE;
544+
EXPECT_EQ(max_torque, received_max_torque);
545+
message_idx = message_idx + 1;
546+
}
547+
548+
// The rest of the message should be zero
549+
int32_t message_sum = std::accumulate(std::begin(message) + message_idx, std::end(message), 0);
550+
int32_t expected_message_sum = 0;
551+
EXPECT_EQ(message_sum, expected_message_sum);
552+
}
553+
485554
int main(int argc, char* argv[])
486555
{
487556
::testing::InitGoogleTest(&argc, argv);

0 commit comments

Comments
 (0)