5050namespace ur_robot_driver
5151{
5252DashboardClientROS::DashboardClientROS (const rclcpp::Node::SharedPtr& node, const std::string& robot_ip)
53- : node_(node), primary_client_(robot_ip, notifier_)
53+ : node_(node), robot_ip_(robot_ip), primary_client_(robot_ip, notifier_)
5454{
5555 node_->declare_parameter <double >(" receive_timeout" , 20 );
56+ node_->declare_parameter <bool >(" autoconnect" , true );
5657
5758 param_callback_handle_ = node_->add_on_set_parameters_callback (
5859 std::bind (&DashboardClientROS::parametersCallback, this , std::placeholders::_1));
5960
61+ reconnect_service_ = node_->create_service <std_srvs::srv::Trigger>(
62+ " ~/connect" ,
63+ [&](const std_srvs::srv::Trigger::Request::SharedPtr /* req*/ , std_srvs::srv::Trigger::Response::SharedPtr resp) {
64+ try {
65+ resp->success = connect ();
66+ } catch (const urcl::UrException& e) {
67+ RCLCPP_ERROR (rclcpp::get_logger (" Dashboard_Client" ), " Service Call failed: '%s'" , e.what ());
68+ resp->message = e.what ();
69+ resp->success = false ;
70+ }
71+ return true ;
72+ });
73+
74+ if (node_->get_parameter (" autoconnect" ).as_bool ()) {
75+ while (!connect ()) {
76+ RCLCPP_ERROR (node_->get_logger (),
77+ " Failed to connect to Dashboard Server at %s. Please check the IP address and ensure the robot is "
78+ " powered on and has the dashboard server enabled. Retrying in 5 seconds." ,
79+ robot_ip_.c_str ());
80+ if (rclcpp::ok ()) {
81+ rclcpp::sleep_for (std::chrono::seconds (5 ));
82+ } else {
83+ RCLCPP_ERROR (node_->get_logger (), " ROS is shutting down, exiting now." );
84+ return ;
85+ }
86+ }
87+ } else {
88+ RCLCPP_INFO (node_->get_logger (),
89+ " Dashboard client started with autoconnect disabled. Call the ~/connect service to connect to %s." ,
90+ robot_ip_.c_str ());
91+ }
92+ }
93+
94+ bool DashboardClientROS::connect ()
95+ {
96+ if (client_) {
97+ timeval tv;
98+ double time_buffer = 0 ;
99+ node_->get_parameter (" receive_timeout" , time_buffer);
100+ tv.tv_sec = time_buffer;
101+ tv.tv_usec = (time_buffer - static_cast <int >(time_buffer)) * 1e6 ;
102+ client_->setReceiveTimeout (tv);
103+ return client_->connect ();
104+ }
105+
60106 primary_client_.start (10 , std::chrono::seconds (10 ));
61107 auto robot_version = primary_client_.getRobotVersion ();
62108 primary_client_.stop ();
@@ -73,25 +119,36 @@ DashboardClientROS::DashboardClientROS(const rclcpp::Node::SharedPtr& node, cons
73119 dashboard_policy = urcl::DashboardClient::ClientPolicy::POLYSCOPE_X ;
74120 }
75121
76- RCLCPP_INFO (node_->get_logger (), " Connecting to Dashboard Server at %s with policy %s" , robot_ip .c_str (),
122+ RCLCPP_INFO (node_->get_logger (), " Connecting to Dashboard Server at %s with policy %s" , robot_ip_ .c_str (),
77123 dashboard_policy == urcl::DashboardClient::ClientPolicy::G5 ? " G5" : " Polyscope X" );
78- client_ = std::make_unique<urcl::DashboardClient>(robot_ip, dashboard_policy);
79-
80- while (!connect ()) {
81- RCLCPP_ERROR (node_->get_logger (),
82- " Failed to connect to Dashboard Server at %s. Please check the IP address and ensure the robot is "
83- " powered on and has the dashboard server enabled. Retrying in 5 seconds." ,
84- robot_ip.c_str ());
85- if (rclcpp::ok ()) {
86- rclcpp::sleep_for (std::chrono::seconds (5 ));
87- } else {
88- RCLCPP_ERROR (node_->get_logger (), " ROS is shutting down, exiting now." );
89- return ;
90- }
124+ client_ = std::make_unique<urcl::DashboardClient>(robot_ip_, dashboard_policy);
125+
126+ timeval tv;
127+ // Timeout after which a call to the dashboard server will be considered failure if no answer has been received.
128+ double time_buffer = 0 ;
129+ node_->get_parameter (" receive_timeout" , time_buffer);
130+ tv.tv_sec = time_buffer;
131+ tv.tv_usec = (time_buffer - static_cast <int >(time_buffer)) * 1e6 ;
132+ bool connected = false ;
133+ try {
134+ client_->setReceiveTimeout (tv);
135+ connected = client_->connect ();
136+ } catch (const urcl::UrException& e) {
137+ RCLCPP_ERROR (rclcpp::get_logger (" Dashboard_Client" ), " Connect failed: '%s'" , e.what ());
91138 }
139+ if (!connected) {
140+ client_.reset ();
141+ return false ;
142+ }
143+
92144 RCLCPP_INFO (node_->get_logger (), " Successfully connected to Dashboard Server at %s. Robot has version %s" ,
93- robot_ip.c_str (), robot_version->toString ().c_str ());
145+ robot_ip_.c_str (), robot_version->toString ().c_str ());
146+ initServices (dashboard_policy);
147+ return true ;
148+ }
94149
150+ void DashboardClientROS::initServices (urcl::DashboardClient::ClientPolicy dashboard_policy)
151+ {
95152 // Service to release the brakes. If the robot is currently powered off, it will get powered on on the fly.
96153 brake_release_service_ = createDashboardTriggerSrv (
97154 " ~/brake_release" , std::bind (&urcl::DashboardClient::commandBrakeReleaseWithResponse, client_.get ()));
@@ -183,7 +240,7 @@ DashboardClientROS::DashboardClientROS(const rclcpp::Node::SharedPtr& node, cons
183240 });
184241
185242 // Load a robot program from a file
186- load_program_service_ = node ->create_service <ur_dashboard_msgs::srv::Load>(
243+ load_program_service_ = node_ ->create_service <ur_dashboard_msgs::srv::Load>(
187244 " ~/load_program" , [&](const ur_dashboard_msgs::srv::Load::Request::SharedPtr req,
188245 ur_dashboard_msgs::srv::Load::Response::SharedPtr resp) {
189246 auto dashboard_response = dashboardCallWithChecks (
@@ -231,7 +288,7 @@ DashboardClientROS::DashboardClientROS(const rclcpp::Node::SharedPtr& node, cons
231288 });
232289
233290 // Service to get serial number of the robot
234- get_serial_number_service_ = node ->create_service <ur_dashboard_msgs::srv::GetSerialNumber>(
291+ get_serial_number_service_ = node_ ->create_service <ur_dashboard_msgs::srv::GetSerialNumber>(
235292 " ~/get_serial_number" , [&](const ur_dashboard_msgs::srv::GetSerialNumber::Request::SharedPtr /* unused*/ ,
236293 ur_dashboard_msgs::srv::GetSerialNumber::Response::SharedPtr resp) {
237294 auto dashboard_response =
@@ -258,14 +315,14 @@ DashboardClientROS::DashboardClientROS(const rclcpp::Node::SharedPtr& node, cons
258315 std::bind (&DashboardClientROS::handleRobotModeQuery, this , std::placeholders::_1, std::placeholders::_2));
259316
260317 // Service to add a message to the robot's log
261- add_to_log_service_ = node ->create_service <ur_dashboard_msgs::srv::AddToLog>(
318+ add_to_log_service_ = node_ ->create_service <ur_dashboard_msgs::srv::AddToLog>(
262319 " ~/add_to_log" , [&](const ur_dashboard_msgs::srv::AddToLog::Request::SharedPtr req,
263320 ur_dashboard_msgs::srv::AddToLog::Response::SharedPtr resp) {
264321 dashboardCallWithChecks ([this , req]() { return client_->commandAddToLogWithResponse (req->message ); }, resp);
265322 return true ;
266323 });
267324 // Service to get the polyscope version running on the robot
268- get_polyscope_version_service_ = node ->create_service <ur_dashboard_msgs::srv::GetPolyScopeVersion>(
325+ get_polyscope_version_service_ = node_ ->create_service <ur_dashboard_msgs::srv::GetPolyScopeVersion>(
269326 " ~/get_polyscope_version" , std::bind (&DashboardClientROS::handleGetPolyScopeVersionQuery, this ,
270327 std::placeholders::_1, std::placeholders::_2));
271328
@@ -282,20 +339,6 @@ DashboardClientROS::DashboardClientROS(const rclcpp::Node::SharedPtr& node, cons
282339 return true ;
283340 });
284341
285- // Service to reconnect to the dashboard server
286- reconnect_service_ = node_->create_service <std_srvs::srv::Trigger>(
287- " ~/connect" ,
288- [&](const std_srvs::srv::Trigger::Request::SharedPtr req, std_srvs::srv::Trigger::Response::SharedPtr resp) {
289- try {
290- resp->success = connect ();
291- } catch (const urcl::UrException& e) {
292- RCLCPP_ERROR (rclcpp::get_logger (" Dashboard_Client" ), " Service Call failed: '%s'" , e.what ());
293- resp->message = e.what ();
294- resp->success = false ;
295- }
296- return true ;
297- });
298-
299342 // Disconnect from the dashboard service.
300343 quit_service_ =
301344 createDashboardTriggerSrv (" ~/quit" , std::bind (&urcl::DashboardClient::commandQuitWithResponse, client_.get ()));
@@ -370,7 +413,7 @@ DashboardClientROS::DashboardClientROS(const rclcpp::Node::SharedPtr& node, cons
370413 });
371414
372415 // Service to set the user role on the robot (Only valid for CB3 robots)
373- set_user_role_service_ = node ->create_service <ur_dashboard_msgs::srv::SetUserRole>(
416+ set_user_role_service_ = node_ ->create_service <ur_dashboard_msgs::srv::SetUserRole>(
374417 " ~/set_user_role" , [&](const ur_dashboard_msgs::srv::SetUserRole::Request::SharedPtr req,
375418 ur_dashboard_msgs::srv::SetUserRole::Response::SharedPtr resp) {
376419 dashboardCallWithChecks ([this , req]() { return client_->commandSetUserRoleWithResponse (req->user_role .role ); },
@@ -379,7 +422,7 @@ DashboardClientROS::DashboardClientROS(const rclcpp::Node::SharedPtr& node, cons
379422 });
380423
381424 // Service to get the current user role (Only valid for CB3)
382- get_user_role_service_ = node ->create_service <ur_dashboard_msgs::srv::GetUserRole>(
425+ get_user_role_service_ = node_ ->create_service <ur_dashboard_msgs::srv::GetUserRole>(
383426 " ~/get_user_role" , [&](const ur_dashboard_msgs::srv::GetUserRole::Request::SharedPtr /* unused*/ ,
384427 ur_dashboard_msgs::srv::GetUserRole::Response::SharedPtr resp) {
385428 auto dashboard_response =
@@ -395,7 +438,7 @@ DashboardClientROS::DashboardClientROS(const rclcpp::Node::SharedPtr& node, cons
395438 });
396439
397440 // Service to set the operational mode. (e-series only)
398- set_operational_mode_service_ = node ->create_service <ur_dashboard_msgs::srv::SetOperationalMode>(
441+ set_operational_mode_service_ = node_ ->create_service <ur_dashboard_msgs::srv::SetOperationalMode>(
399442 " ~/set_operational_mode" , [&](const ur_dashboard_msgs::srv::SetOperationalMode::Request::SharedPtr req,
400443 ur_dashboard_msgs::srv::SetOperationalMode::Response::SharedPtr resp) {
401444 dashboardCallWithChecks (
@@ -404,7 +447,7 @@ DashboardClientROS::DashboardClientROS(const rclcpp::Node::SharedPtr& node, cons
404447 });
405448
406449 // Service to get the current operational mode (e-series only)
407- get_operational_mode_service_ = node ->create_service <ur_dashboard_msgs::srv::GetOperationalMode>(
450+ get_operational_mode_service_ = node_ ->create_service <ur_dashboard_msgs::srv::GetOperationalMode>(
408451 " ~/get_operational_mode" , [&](const ur_dashboard_msgs::srv::GetOperationalMode::Request::SharedPtr /* unused*/ ,
409452 ur_dashboard_msgs::srv::GetOperationalMode::Response::SharedPtr resp) {
410453 auto dashboard_response =
@@ -420,7 +463,7 @@ DashboardClientROS::DashboardClientROS(const rclcpp::Node::SharedPtr& node, cons
420463 });
421464
422465 // Service to get the robot model as a string
423- get_robot_model_service_ = node ->create_service <ur_dashboard_msgs::srv::GetRobotModel>(
466+ get_robot_model_service_ = node_ ->create_service <ur_dashboard_msgs::srv::GetRobotModel>(
424467 " ~/get_robot_model" , [&](const ur_dashboard_msgs::srv::GetRobotModel::Request::SharedPtr /* unused*/ ,
425468 ur_dashboard_msgs::srv::GetRobotModel::Response::SharedPtr resp) {
426469 auto dashboard_response =
@@ -436,12 +479,12 @@ DashboardClientROS::DashboardClientROS(const rclcpp::Node::SharedPtr& node, cons
436479 });
437480
438481 // Service to get robot safety status as a string
439- get_safety_status_service_ = node ->create_service <ur_dashboard_msgs::srv::GetSafetyStatus>(
482+ get_safety_status_service_ = node_ ->create_service <ur_dashboard_msgs::srv::GetSafetyStatus>(
440483 " ~/get_safety_status" ,
441484 std::bind (&DashboardClientROS::handleSafetyStatusQuery, this , std::placeholders::_1, std::placeholders::_2));
442485
443486 // Service to generate flight report, defaults to system type
444- generate_flight_report_service_ = node ->create_service <ur_dashboard_msgs::srv::GenerateFlightReport>(
487+ generate_flight_report_service_ = node_ ->create_service <ur_dashboard_msgs::srv::GenerateFlightReport>(
445488 " ~/generate_flight_report" , [&](const ur_dashboard_msgs::srv::GenerateFlightReport::Request::SharedPtr req,
446489 ur_dashboard_msgs::srv::GenerateFlightReport::Response::SharedPtr resp) {
447490 auto dashboard_response = dashboardCallWithChecks (
@@ -462,7 +505,7 @@ DashboardClientROS::DashboardClientROS(const rclcpp::Node::SharedPtr& node, cons
462505 });
463506
464507 // Service to generate support file, defaults to saving the file in /programs
465- generate_support_file_service_ = node ->create_service <ur_dashboard_msgs::srv::GenerateSupportFile>(
508+ generate_support_file_service_ = node_ ->create_service <ur_dashboard_msgs::srv::GenerateSupportFile>(
466509 " ~/generate_support_file" , [&](const ur_dashboard_msgs::srv::GenerateSupportFile::Request::SharedPtr req,
467510 ur_dashboard_msgs::srv::GenerateSupportFile::Response::SharedPtr resp) {
468511 auto dashboard_response = dashboardCallWithChecks (
@@ -483,18 +526,6 @@ DashboardClientROS::DashboardClientROS(const rclcpp::Node::SharedPtr& node, cons
483526 });
484527}
485528
486- bool DashboardClientROS::connect ()
487- {
488- timeval tv;
489- // Timeout after which a call to the dashboard server will be considered failure if no answer has been received.
490- double time_buffer = 0 ;
491- node_->get_parameter (" receive_timeout" , time_buffer);
492- tv.tv_sec = time_buffer;
493- tv.tv_usec = (time_buffer - static_cast <int >(time_buffer)) * 1e6 ;
494- client_->setReceiveTimeout (tv);
495- return client_->connect ();
496- }
497-
498529bool DashboardClientROS::handleRunningQuery (const ur_dashboard_msgs::srv::IsProgramRunning::Request::SharedPtr req,
499530 ur_dashboard_msgs::srv::IsProgramRunning::Response::SharedPtr resp)
500531{
@@ -720,12 +751,14 @@ DashboardClientROS::parametersCallback(const std::vector<rclcpp::Parameter>& par
720751
721752 for (const auto & parameter : parameters) {
722753 if (parameter.get_name () == " receive_timeout" ) {
723- timeval tv;
724- double time_buffer = parameter.as_double ();
725- tv.tv_sec = time_buffer;
726- tv.tv_usec = (time_buffer - static_cast <int >(time_buffer)) * 1e6 ;
727- client_->setReceiveTimeout (tv);
728- RCLCPP_INFO (node_->get_logger (), " Set receive_timeout to %f seconds" , time_buffer);
754+ if (client_) {
755+ timeval tv;
756+ double time_buffer = parameter.as_double ();
757+ tv.tv_sec = time_buffer;
758+ tv.tv_usec = (time_buffer - static_cast <int >(time_buffer)) * 1e6 ;
759+ client_->setReceiveTimeout (tv);
760+ }
761+ RCLCPP_INFO (node_->get_logger (), " Set receive_timeout to %f seconds" , parameter.as_double ());
729762 } else {
730763 result.successful = false ;
731764 result.reason = " Requested to change parameter '" + parameter.get_name () +
0 commit comments