Visual Servoing Platform version 3.7.0
Loading...
Searching...
No Matches
vpRobotUniversalRobots.cpp
1/*
2 * ViSP, open source Visual Servoing Platform software.
3 * Copyright (C) 2005 - 2025 by Inria. All rights reserved.
4 *
5 * This software is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 * See the file LICENSE.txt at the root directory of this source
10 * distribution for additional information about the GNU GPL.
11 *
12 * For using ViSP with software that can not be combined with the GNU
13 * GPL, please contact Inria about acquiring a ViSP Professional
14 * Edition License.
15 *
16 * See https://visp.inria.fr for more information.
17 *
18 * This software was developed at:
19 * Inria Rennes - Bretagne Atlantique
20 * Campus Universitaire de Beaulieu
21 * 35042 Rennes Cedex
22 * France
23 *
24 * If you have questions regarding the use of this file, please contact
25 * Inria at visp@inria.fr
26 *
27 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
28 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
29 *
30 * Description:
31 * Interface for Universal Robots.
32 */
33
34#include <visp3/core/vpConfig.h>
35
36#if defined(VISP_HAVE_UR_RTDE)
37
38#include <visp3/core/vpIoTools.h>
39#include <visp3/robot/vpRobotUniversalRobots.h>
40
53
58
68 : m_rtde_receive(nullptr), m_rtde_control(nullptr), m_eMc()
69{
70 init();
71 connect(ur_address);
72}
73
80void vpRobotUniversalRobots::connect(const std::string &ur_address)
81{
82 if (!m_rtde_receive) {
83 m_rtde_receive = std::make_shared<ur_rtde::RTDEReceiveInterface>(ur_address);
84 }
85 if (!m_rtde_control) {
86 m_rtde_control = std::make_shared<ur_rtde::RTDEControlInterface>(ur_address);
87 }
88 if (!m_db_client) {
89 m_db_client = std::make_shared<ur_rtde::DashboardClient>(ur_address);
90 }
91 if (!m_rtde_receive->isConnected()) {
92 m_rtde_receive->reconnect();
93 if (!m_rtde_receive->isConnected()) {
94 throw(vpException(vpException::fatalError, "Cannot connect UR robot to receive interface"));
95 }
96 }
97 if (!m_rtde_control->isConnected()) {
98 m_rtde_control->reconnect();
99 if (!m_rtde_control->isConnected()) {
100 throw(vpException(vpException::fatalError, "Cannot connect UR robot to control interface"));
101 }
102 }
103 if (!m_db_client->isConnected()) {
104 m_db_client->connect();
105 if (!m_db_client->isConnected()) {
106 throw(vpException(vpException::fatalError, "Cannot connect UR robot to dashboard client"));
107 }
108 }
109}
110
115{
116 if (m_rtde_receive && m_rtde_receive->isConnected()) {
117 m_rtde_receive->disconnect();
118 }
119 if (m_rtde_control && m_rtde_control->isConnected()) {
120 m_rtde_control->disconnect();
121 }
122 if (m_db_client && m_db_client->isConnected()) {
123 m_db_client->disconnect();
124 }
125}
126
131{
132 nDof = 6;
134 m_max_joint_speed = vpMath::rad(180.); // deg/s
135 m_max_joint_acceleration = vpMath::rad(800.); // deg/s^2
136 m_max_linear_speed = 0.5; // m/s
137 m_max_linear_acceleration = 2.5; // m/s^2
139}
140
158
173{
175 throw(vpException(vpException::fatalError, "Cannot get UR robot forward kinematics: robot is not connected"));
176 }
177 if (q.size() != 6) {
179 "Cannot get UR robot forward kinematics: joint position vector is not 6-dim (%d)", q.size()));
180 }
181 // Robot modes:
182 // https://sdurobotics.gitlab.io/ur_rtde/api/api.html#_CPPv4N7ur_rtde20RTDEReceiveInterface12getRobotModeEv
183 if (m_rtde_receive->getRobotMode() != 7) {
184 throw(vpException(vpException::fatalError, "Cannot get UR robot forward kinematics: brakes are not released"));
185 }
186
187 const std::vector<double> q_std = q.toStdVector();
188 std::vector<double> tcp_pose = m_rtde_control->getForwardKinematics(q_std);
189
190 vpPoseVector f_P_e;
191 for (size_t i = 0; i < 6; i++) {
192 f_P_e[i] = tcp_pose[i];
193 }
194 vpHomogeneousMatrix fMe(f_P_e);
195 return fMe;
196}
197
217
231
243
254{
255 if (!m_rtde_receive) {
256 throw(vpException(vpException::fatalError, "Cannot get UR robot force/torque: robot is not connected"));
257 }
258
259 std::vector<double> eFe = m_rtde_receive->getActualTCPForce();
260
261 switch (frame) {
262 case JOINT_STATE: {
263 throw(vpException(vpException::fatalError, "Cannot get UR force/torque in joint space"));
264 break;
265 }
266 case END_EFFECTOR_FRAME: {
267 force = eFe;
268 break;
269 }
270 case TOOL_FRAME: {
271 // Transform in tool frame
273 vpForceTwistMatrix cWe(cMe);
274 force = cWe * eFe;
275 break;
276 }
277 default: {
278 throw(vpException(vpException::fatalError, "Cannot get UR force/torque: frame not supported"));
279 }
280 }
281}
282
287{
288 if (!m_db_client) {
289 throw(vpException(vpException::fatalError, "Cannot get UR robot PolyScope verson: robot is not connected"));
290 }
291 return m_db_client->polyscopeVersion();
292}
293
309{
310 if (!m_rtde_receive) {
311 throw(vpException(vpException::fatalError, "Cannot get UR robot position: robot is not connected"));
312 }
313 // Robot modes:
314 // https://sdurobotics.gitlab.io/ur_rtde/api/api.html#_CPPv4N7ur_rtde20RTDEReceiveInterface12getRobotModeEv
315 if (m_rtde_receive->getRobotMode() < 4) {
316 throw(vpException(vpException::fatalError, "Cannot get UR robot position: robot is not powered on"));
317 }
318
319 switch (frame) {
320 case JOINT_STATE: {
321 position = m_rtde_receive->getActualQ();
322 break;
323 }
324 case END_EFFECTOR_FRAME: {
325 std::vector<double> tcp_pose = m_rtde_receive->getActualTCPPose();
326 position.resize(6);
327 for (size_t i = 0; i < tcp_pose.size(); i++) {
328 position[i] = tcp_pose[i];
329 }
330
331 break;
332 }
333 case TOOL_FRAME: { // same a CAMERA_FRAME
334 std::vector<double> tcp_pose = m_rtde_receive->getActualTCPPose();
335 vpPoseVector fPe;
336 for (size_t i = 0; i < tcp_pose.size(); i++) {
337 fPe[i] = tcp_pose[i];
338 }
339
340 vpHomogeneousMatrix fMe(fPe);
341 vpHomogeneousMatrix fMc = fMe * m_eMc;
342 vpPoseVector fPc(fMc);
343 position.resize(6);
344 for (size_t i = 0; i < 6; i++) {
345 position[i] = fPc[i];
346 }
347 break;
348 }
349 default: {
350 throw(vpException(vpException::fatalError, "Cannot get UR cartesian position: wrong method"));
351 }
352 }
353}
354
365{
366 if (!m_rtde_receive) {
367 throw(vpException(vpException::fatalError, "Cannot get UR robot position: robot is not connected"));
368 }
369 if (frame == JOINT_STATE) {
370 throw(vpException(vpException::fatalError, "Cannot get UR joint position as a pose vector"));
371 }
372
373 switch (frame) {
375 case TOOL_FRAME: {
376 vpColVector position;
377 getPosition(frame, position);
378 for (size_t i = 0; i < 6; i++) {
379 pose[i] = position[i];
380 }
381 break;
382 }
383 default: {
384 throw(vpException(vpException::fatalError, "Cannot get Franka cartesian position: not implemented"));
385 }
386 }
387}
388
393{
394 if (!m_db_client) {
395 throw(vpException(vpException::fatalError, "Cannot get UR robot model: robot is not connected"));
396 }
397 return m_db_client->getRobotModel();
398}
399
404{
405 if (!m_rtde_receive) {
406 throw(vpException(vpException::fatalError, "Cannot get UR robot mode: robot is not connected"));
407 }
408 // Robot modes:
409 // https://sdurobotics.gitlab.io/ur_rtde/api/api.html#_CPPv4N7ur_rtde20RTDEReceiveInterface12getRobotModeEv
410 return (m_rtde_receive->getRobotMode());
411}
412
419
434{
435 if (frame == vpRobot::JOINT_STATE) {
436 throw(vpException(vpException::fatalError, "Cannot set UR robot cartesian position: joint state is specified"));
437 }
438 vpColVector position(pose);
439 setPosition(frame, position);
440}
441
457{
458 if (!m_rtde_control) {
459 throw(vpException(vpException::fatalError, "Cannot set UR robot position: robot is not connected"));
460 }
461
462 // Robot modes:
463 // https://sdurobotics.gitlab.io/ur_rtde/api/api.html#_CPPv4N7ur_rtde20RTDEReceiveInterface12getRobotModeEv
464 if (m_rtde_receive->getRobotMode() != 7) {
465 throw(vpException(vpException::fatalError, "Cannot set UR robot position: brakes are not released"));
466 }
467
468 if (position.size() != 6) {
470 "Cannot set UR robot position: position vector is not a 6-dim vector (%d)", position.size()));
471 }
472
474 std::cout << "Robot is not in position-based control. "
475 "Modification of the robot state"
476 << std::endl;
478 }
479
480 if (frame == vpRobot::JOINT_STATE) {
481 double speed_factor = m_positioningVelocity / 100.;
482 std::vector<double> new_q = position.toStdVector();
483 m_rtde_control->moveJ(new_q, m_max_joint_speed * speed_factor);
484 }
485 else if (frame == vpRobot::END_EFFECTOR_FRAME) {
486 double speed_factor = m_positioningVelocity / 100.;
487 std::vector<double> new_pose = position.toStdVector();
488 // Move synchronously to ensure a the blocking behaviour
489 m_rtde_control->moveL(new_pose, m_max_linear_speed * speed_factor);
490 }
491 else if (frame == vpRobot::CAMERA_FRAME) {
492 double speed_factor = m_positioningVelocity / 100.;
493
494 vpTranslationVector f_t_c(position.extract(0, 3));
495 vpThetaUVector f_tu_c(position.extract(3, 3));
496 vpHomogeneousMatrix fMc(f_t_c, f_tu_c);
497 vpHomogeneousMatrix fMe = fMc * m_eMc.inverse();
498 vpPoseVector fPe(fMe);
499 std::vector<double> new_pose = fPe.toStdVector();
500 // Move synchronously to ensure a the blocking behaviour
501 m_rtde_control->moveL(new_pose, m_max_linear_speed * speed_factor);
502 }
503 else {
505 "Cannot move the robot to a cartesian position. Only joint positioning is implemented"));
506 }
507}
508
601{
604 "Cannot send a velocity to the robot: robot is not in velocity control state "
605 "use setRobotState(vpRobot::STATE_VELOCITY_CONTROL) first) ");
606 }
607
608 vpColVector vel_sat(6);
609 m_vel_control_frame = frame;
610
611 // Velocity saturation
612 switch (frame) {
613 // saturation in cartesian space
617 case vpRobot::MIXT_FRAME: {
618 vpColVector vel_max(6);
619
620 for (unsigned int i = 0; i < 3; i++)
621 vel_max[i] = getMaxTranslationVelocity();
622 for (unsigned int i = 3; i < 6; i++)
623 vel_max[i] = getMaxRotationVelocity();
624
625 vel_sat = vpRobot::saturateVelocities(vel, vel_max, true);
626
627 break;
628 }
629 // Saturation in joint space
631 vpColVector vel_max(6);
632 vel_max = getMaxRotationVelocity();
633 vel_sat = vpRobot::saturateVelocities(vel, vel_max, true);
634 }
635 }
636
637 if (frame == vpRobot::JOINT_STATE) {
638 double dt = 1.0 / 1000; // 2ms
639 double acceleration = 0.5;
640 m_rtde_control->speedJ(vel_sat.toStdVector(), acceleration, dt);
641 }
642 else if (frame == vpRobot::REFERENCE_FRAME) {
643 double dt = 1.0 / 1000; // 2ms
644 double acceleration = 0.25;
645 m_rtde_control->speedL(vel_sat.toStdVector(), acceleration, dt);
646 }
647 else if (frame == vpRobot::END_EFFECTOR_FRAME) {
648 double dt = 1.0 / 1000; // 2ms
649 double acceleration = 0.25;
650 vpVelocityTwistMatrix fVe(get_fMe(), false);
651 m_rtde_control->speedL((fVe * vel_sat).toStdVector(), acceleration, dt);
652 }
653 else if (frame == vpRobot::CAMERA_FRAME) {
654 double dt = 1.0 / 1000; // 2ms
655 double acceleration = 0.25;
657 m_rtde_control->speedL(w_v_e.toStdVector(), acceleration, dt);
658 }
659 else {
661 "Cannot move the robot in velocity in the specified frame: not implemented"));
662 }
663}
664
673{
674 if (!m_rtde_control) {
675 throw(vpException(vpException::fatalError, "Cannot stop UR robot: robot is not connected"));
676 }
677
679}
680
689void vpRobotUniversalRobots::move(const std::string &filename, double velocity_percentage)
690{
691 vpColVector q;
692
693 readPosFile(filename, q);
695 setPositioningVelocity(velocity_percentage);
697}
698
736bool vpRobotUniversalRobots::readPosFile(const std::string &filename, vpColVector &q)
737{
738 std::ifstream fd(filename.c_str(), std::ios::in);
739
740 if (!fd.is_open()) {
741 return false;
742 }
743
744 std::string line;
745 std::string key("R:");
746 std::string id("#UR - Joint position file");
747 bool pos_found = false;
748 int lineNum = 0;
749 size_t njoints = static_cast<size_t>(nDof);
750
751 q.resize(njoints);
752
753 while (std::getline(fd, line)) {
754 lineNum++;
755 if (lineNum == 1) {
756 if (!(line.compare(0, id.size(), id) == 0)) { // check if Afma6 position file
757 std::cout << "Error: this position file " << filename << " is not for Universal Robots" << std::endl;
758 return false;
759 }
760 }
761 if ((line.compare(0, 1, "#") == 0)) { // skip comment
762 continue;
763 }
764 if ((line.compare(0, key.size(), key) == 0)) { // decode position
765 // check if there are at least njoint values in the line
766 std::vector<std::string> chain = vpIoTools::splitChain(line, std::string(" "));
767 if (chain.size() < njoints + 1) // try to split with tab separator
768 chain = vpIoTools::splitChain(line, std::string("\t"));
769 if (chain.size() < njoints + 1)
770 continue;
771
772 std::istringstream ss(line);
773 std::string key_;
774 ss >> key_;
775 for (unsigned int i = 0; i < njoints; i++)
776 ss >> q[i];
777 pos_found = true;
778 break;
779 }
780 }
781
782 // converts rotations from degrees into radians
783 for (unsigned int i = 0; i < njoints; i++) {
784 q[i] = vpMath::rad(q[i]);
785 }
786
787 fd.close();
788
789 if (!pos_found) {
790 std::cout << "Error: unable to find a position for UR robot in " << filename << std::endl;
791 return false;
792 }
793
794 return true;
795}
796
814bool vpRobotUniversalRobots::savePosFile(const std::string &filename, const vpColVector &q)
815{
816
817 FILE *fd;
818 fd = fopen(filename.c_str(), "w");
819 if (fd == nullptr)
820 return false;
821
822 fprintf(fd, "#UR - Joint position file\n"
823 "#\n"
824 "# R: q1 q2 q3 q4 q5 q6\n"
825 "# with joint positions q1 to q6 expressed in degrees\n"
826 "#\n");
827
828 // Save positions in mm and deg
829 fprintf(fd, "R: %lf %lf %lf %lf %lf %lf\n", vpMath::deg(q[0]), vpMath::deg(q[1]), vpMath::deg(q[2]),
830 vpMath::deg(q[3]), vpMath::deg(q[4]), vpMath::deg(q[5]));
831
832 fclose(fd);
833 return (true);
834}
835
842{
843 switch (newState) {
844 case vpRobot::STATE_STOP: {
845 // Start primitive STOP only if the current state is Velocity
847 if (!m_rtde_control) {
848 throw(vpException(vpException::fatalError, "Cannot stop UR robot: robot is not connected"));
849 }
850 m_rtde_control->speedStop();
851 }
852 break;
853 }
856 if (!m_rtde_control) {
857 throw(vpException(vpException::fatalError, "Cannot stop UR robot: robot is not connected"));
858 }
859 m_rtde_control->speedStop();
860 }
861 else {
862 // std::cout << "Change the control mode from stop to position control" << std::endl;
863 }
864 break;
865 }
868 std::cout << "Change the control mode from stop to velocity control.\n";
869 }
870 break;
871 }
872 default:
873 break;
874 }
875
876 return vpRobot::setRobotState(newState);
877}
878END_VISP_NAMESPACE
879#elif !defined(VISP_BUILD_SHARED_LIBS)
880// Work around to avoid warning: libvisp_robot.a(vpRobotUniversalRobots.cpp.o) has no symbols
881void dummy_vpRobotUniversalRobots() { }
882#endif
unsigned int size() const
Return the number of elements of the 2D array.
Definition vpArray2D.h:435
Implementation of column vector and the associated operations.
vpColVector extract(unsigned int r, unsigned int colsize) const
std::vector< double > toStdVector() const
void resize(unsigned int i, bool flagNullify=true)
error that can be emitted by ViSP classes.
Definition vpException.h:60
@ functionNotImplementedError
Function not implemented.
Definition vpException.h:66
@ fatalError
Fatal error.
Definition vpException.h:72
Implementation of an homogeneous matrix and operations on such kind of matrices.
vpHomogeneousMatrix inverse() const
static std::vector< std::string > splitChain(const std::string &chain, const std::string &sep)
static double rad(double deg)
Definition vpMath.h:129
static double deg(double rad)
Definition vpMath.h:119
Implementation of a pose vector and operations on poses.
std::vector< double > toStdVector() const
Error that can be emitted by the vpRobot class and its derivatives.
@ wrongStateError
Wrong robot state.
void setVelocity(const vpRobot::vpControlFrameType frame, const vpColVector &vel) VP_OVERRIDE
vpHomogeneousMatrix get_eMc() const
void setPositioningVelocity(double velocity)
void setPosition(const vpRobot::vpControlFrameType frame, const vpColVector &position) VP_OVERRIDE
vpRobot::vpRobotStateType setRobotState(vpRobot::vpRobotStateType newState)
void move(const std::string &filename, double velocity_percentage=10.)
void getPosition(const vpRobot::vpControlFrameType frame, vpColVector &position) VP_OVERRIDE
void connect(const std::string &ur_address)
bool savePosFile(const std::string &filename, const vpColVector &q)
void set_eMc(const vpHomogeneousMatrix &eMc)
std::shared_ptr< ur_rtde::DashboardClient > m_db_client
vpRobot::vpControlFrameType m_vel_control_frame
void getForceTorque(const vpRobot::vpControlFrameType frame, vpColVector &force)
std::shared_ptr< ur_rtde::RTDEReceiveInterface > m_rtde_receive
std::shared_ptr< ur_rtde::RTDEControlInterface > m_rtde_control
bool readPosFile(const std::string &filename, vpColVector &q)
int nDof
number of degrees of freedom
Definition vpRobot.h:101
virtual vpRobotStateType getRobotState(void) const
Definition vpRobot.h:152
static vpColVector saturateVelocities(const vpColVector &v_in, const vpColVector &v_max, bool verbose=false)
Definition vpRobot.cpp:162
vpControlFrameType
Definition vpRobot.h:74
@ REFERENCE_FRAME
Definition vpRobot.h:75
@ JOINT_STATE
Definition vpRobot.h:79
@ TOOL_FRAME
Definition vpRobot.h:83
@ MIXT_FRAME
Definition vpRobot.h:85
@ CAMERA_FRAME
Definition vpRobot.h:81
@ END_EFFECTOR_FRAME
Definition vpRobot.h:80
vpRobotStateType
Definition vpRobot.h:62
@ STATE_POSITION_CONTROL
Initialize the position controller.
Definition vpRobot.h:65
@ STATE_VELOCITY_CONTROL
Initialize the velocity controller.
Definition vpRobot.h:64
@ STATE_STOP
Stops robot motion especially in velocity and acceleration control.
Definition vpRobot.h:63
double getMaxRotationVelocity(void) const
Definition vpRobot.cpp:272
virtual vpRobotStateType setRobotState(const vpRobot::vpRobotStateType newState)
Definition vpRobot.cpp:200
double getMaxTranslationVelocity(void) const
Definition vpRobot.cpp:250
Implementation of a rotation vector as axis-angle minimal representation.
Class that consider the case of a translation vector.