00001
00025 #include <ros/ros.h>
00026 #include <signal.h>
00027
00028 #include <opcua_helpers.h>
00029
00030 #include "ros_opcua_msgs/Address.h"
00031 #include "ros_opcua_msgs/TypeValue.h"
00032
00033 #include "ros_opcua_srvs/CallMethod.h"
00034 #include "ros_opcua_srvs/Connect.h"
00035 #include "ros_opcua_srvs/Disconnect.h"
00036 #include "ros_opcua_srvs/ListNode.h"
00037 #include "ros_opcua_srvs/Read.h"
00038 #include "ros_opcua_srvs/Subscribe.h"
00039 #include "ros_opcua_srvs/Write.h"
00040 #include "ros_opcua_srvs/Unsubscribe.h"
00041
00042 #include <opc/ua/client/client.h>
00043 #include <opc/ua/subscription.h>
00044
00046 OpcUa::UaClient _client(false);
00048
00049 std::map<std::string, std::unique_ptr<OpcUa::Subscription>> _subscriptions;
00051
00052 std::map<std::string, ros::Publisher> _callback_publishers;
00054
00055 std::map<std::string, uint32_t> _subscription_handles;
00057 bool _connected = false;
00058
00060
00063 class SubClient : public OpcUa::SubscriptionHandler
00064 {
00072 void DataChange(uint32_t handle, const OpcUa::Node& node, const
00073 OpcUa::Variant& value, OpcUa::AttributeId attr) override
00074 {
00075 ROS_DEBUG("Callback....");
00076 _callback_publishers[OpcUa::ToString(node.GetId())].publish(convertVariantToTypeValue(value));
00077 }
00078 };
00079
00081
00082 SubClient _sclt;
00083
00090 bool connect(ros_opcua_srvs::Connect::Request &req, ros_opcua_srvs::Connect::Response &res)
00091 {
00092
00093
00094 ROS_DEBUG("Establishing connection to OPC-UA server on address: %s", req.endpoint.c_str());
00095 try {
00096 _client.Connect(req.endpoint);
00097 ROS_INFO("Connection to OPC-UA server on address '%s' established!", req.endpoint.c_str());
00098 res.success = true;
00099 _connected = true;
00100 }
00101 catch (const std::exception& exc){
00102 ROS_ERROR("OPC-UA client node %s: Connection to OPC-UA server on address %s failed! Message: %s", ros::this_node::getName().c_str(), req.endpoint.c_str(), exc.what());
00103
00104 res.success = false;
00105 char err_string[100];
00106 sprintf(err_string, "Connection to OPC-UA server on address %s failed! Message: %s", req.endpoint.c_str(), exc.what());
00107 res.error_message = err_string;
00108 }
00109 catch (...) {
00110 ROS_ERROR("Connection to OPC-UA server on address %s failed with unknown exception", req.endpoint.c_str());
00111 res.success = false;
00112 res.error_message = "'Connect' service failed with Unknown exception";
00113 }
00114 return true;
00115 }
00116
00123 bool disconnect(ros_opcua_srvs::Disconnect::Request &req, ros_opcua_srvs::Disconnect::Response &res)
00124 {
00125 ROS_DEBUG("Disconnecting from OPC-UA server...");
00126 try {
00127 _client.Disconnect();
00128 ROS_INFO("Disconnection succeded!");
00129 _connected = false;
00130 res.success = true;
00131 }
00132 catch (const std::exception& exc){
00133 ROS_ERROR("OPC-UA client node %s: Disconnection failed! (maybe client was not connected before?). Message: %s", ros::this_node::getName().c_str(), exc.what());
00134
00135 res.success = false;
00136 char err_string[100];
00137 sprintf(err_string, "Dissconect service failed with exception: %s", exc.what());
00138 res.error_message = err_string;
00139 }
00140 catch (...) {
00141 ROS_ERROR("'Disconnect' service failed with unknown exception");
00142 res.success = false;
00143 res.error_message = "'Disconnect' service failed with unknown exception";
00144 }
00145 return true;
00146 }
00147
00154 bool list_node(ros_opcua_srvs::ListNode::Request &req, ros_opcua_srvs::ListNode::Response &res)
00155 {
00156 ROS_DEBUG("OPC-UA client node %s: 'ListNode' service called with node Id: %s parameters", ros::this_node::getName().c_str(), req.node.nodeId.c_str());
00157
00158 OpcUa::Node node;
00159 try {
00160 if (req.node.nodeId == "") {
00161 node = _client.GetObjectsNode();
00162 }
00163 else {
00164 node = _client.GetNode(req.node.nodeId);
00165 }
00166
00167 for (OpcUa::Node child : node.GetChildren()){
00168 ros_opcua_msgs::Address address;
00169 address.nodeId = OpcUa::ToString(child.GetId());
00170 address.qualifiedName = child.GetBrowseName().Name;
00171 res.children.push_back(address);
00172 }
00173 res.success = true;
00174 }
00175 catch (const std::exception& exc){
00176 ROS_ERROR("OPC-UA client node %s: 'ListNode' service called with node Id: %s, parameters failed! Exception: %s", ros::this_node::getName().c_str(), req.node.nodeId.c_str(), exc.what());
00177
00178 res.success = false;
00179 char err_string[100];
00180 sprintf(err_string, "ListNode service failed with exception: %s", exc.what());
00181 res.error_message = err_string;
00182 }
00183 catch (...)
00184 {
00185 ROS_ERROR("OPC-UA client node %s: 'ListNode' service called with node Id: %s parameters failed! Unknown exception!", ros::this_node::getName().c_str(), req.node.nodeId.c_str());
00186
00187 res.success = false;
00188 res.error_message = "ListNode service failed with Unknown exception";
00189 }
00190 return true;
00191 }
00192
00193 bool call_method(ros_opcua_srvs::CallMethod::Request &req, ros_opcua_srvs::CallMethod::Response &res)
00194 {
00195 ROS_DEBUG("OPC-UA client node %s: 'CallMethod' service called with node Id: %s and %s parameters", ros::this_node::getName().c_str(), req.node.nodeId.c_str(), req.method.nodeId.c_str());
00196
00197 try {
00198 OpcUa::Node node = _client.GetNode(req.node.nodeId);
00199 OpcUa::NodeId method_id = OpcUa::ToNodeId(req.method.nodeId);
00200 std::vector<OpcUa::Variant> inputArguments;
00201
00202 for (ros_opcua_msgs::TypeValue typeValue : req.data) {
00203 std::cout << "Variant: " <<
00204 convertTypeValueToVariant(typeValue).ToString() << std::endl;
00205 inputArguments.push_back(convertTypeValueToVariant(typeValue));
00206 }
00207
00208 std::vector<OpcUa::Variant> outputArguments = node.CallMethod(method_id, inputArguments);
00209
00210 for (OpcUa::Variant variant : outputArguments) {
00211 res.data.push_back(convertVariantToTypeValue(variant));
00212 }
00213
00214 res.success = true;
00215
00216 }
00217 catch (const std::exception& exc){
00218 ROS_ERROR("OPC-UA client node %s: 'CallMethod' service called with node Id: %s and %s parameters failed! Exception: %s", ros::this_node::getName().c_str(), req.node.nodeId.c_str(), req.method.nodeId.c_str(), exc.what());
00219
00220 res.success = false;
00221 char err_string[100];
00222 sprintf(err_string, "Call method service failed with exception: %s", exc.what());
00223 res.error_message = err_string;
00224 }
00225 catch (...)
00226 {
00227 ROS_ERROR("OPC-UA client node %s: 'CallMethod' service called with node Id: %s parameters failed! Unknown exception!", ros::this_node::getName().c_str(), req.node.nodeId.c_str());
00228
00229 res.success = false;
00230 res.error_message = "Call method service failed with Unknown exception";
00231 }
00232 return true;
00233 }
00234
00241 bool read(ros_opcua_srvs::Read::Request &req, ros_opcua_srvs::Read::Response &res)
00242 {
00243 ROS_DEBUG("OPC-UA client node %s: 'Read' service called with node Id: %s parameters", ros::this_node::getName().c_str(), req.node.nodeId.c_str());
00244
00245 try {
00246 OpcUa::Node variable = _client.GetNode(req.node.nodeId);
00247
00248 res.success = true;
00249 res.data = convertVariantToTypeValue(variable.GetValue());
00250
00251 if (res.data.type == "Unknown") {
00252 res.success = false;
00253 char err_string[100];
00254 sprintf(err_string, "Unknon data type!!");
00255 res.error_message = err_string;
00256 ROS_DEBUG("Reading failed!");
00257 }
00258 }
00259 catch (const std::exception& exc){
00260 ROS_ERROR("OPC-UA client node %s: 'Read' service called with node Id: %s, parameters failed! Exception: %s", ros::this_node::getName().c_str(), req.node.nodeId.c_str(), exc.what());
00261
00262 res.success = false;
00263 char err_string[100];
00264 sprintf(err_string, "Read service failed with exception: %s", exc.what());
00265 res.error_message = err_string;
00266 }
00267 catch (...)
00268 {
00269 ROS_ERROR("OPC-UA client node %s: 'Read' service called with node Id: %s parameters failed! Unknown exception!", ros::this_node::getName().c_str(), req.node.nodeId.c_str());
00270
00271 res.success = false;
00272 res.error_message = "Read service failed with Unknown exception";
00273 }
00274 return true;
00275 }
00276
00283 bool write(ros_opcua_srvs::Write::Request &req, ros_opcua_srvs::Write::Response &res)
00284 {
00285 ROS_DEBUG("OPC-UA client node %s: 'Write' service called with node Id: %s, parameters", ros::this_node::getName().c_str(), req.node.nodeId.c_str());
00286
00287 try {
00288 OpcUa::Node variable = _client.GetNode(req.node.nodeId);
00289
00290 OpcUa::Variant variant = convertTypeValueToVariant(req.data);
00291
00292 if (!variant.IsNul()) {
00293
00294
00295
00296
00297
00298 variable.SetValue(variant);
00299 res.success = true;
00300 }
00301 else {
00302 res.success = false;
00303 char err_string[100];
00304 sprintf(err_string, "Unknon data type %s", req.data.type.c_str());
00305 res.error_message = err_string;
00306 ROS_DEBUG("Writing failed!");
00307 }
00308 }
00309 catch (const std::exception& exc){
00310 ROS_ERROR("OPC-UA client node %s: 'Write' service called with node Id: %s, type: '%s' parameters failed! Exception: %s", ros::this_node::getName().c_str(), req.node.nodeId.c_str(), req.data.type.c_str(), exc.what());
00311
00312 res.success = false;
00313 char err_string[100];
00314 sprintf(err_string, "Write service failed with exception: %s", exc.what());
00315 res.error_message = err_string;
00316 }
00317 catch (...)
00318 {
00319 ROS_ERROR("OPC-UA client node %s: 'Write' service called with node Id: %s, type: '%s' parameters failed! Unknown exception!", ros::this_node::getName().c_str(), req.node.nodeId.c_str(), req.data.type.c_str());
00320
00321 res.success = false;
00322 res.error_message = "Write service failed with Unknown exception";
00323 }
00324
00325 return true;
00326 }
00327
00335 bool subscribe(ros_opcua_srvs::Subscribe::Request &req, ros_opcua_srvs::Subscribe::Response &res)
00336 {
00337 ROS_DEBUG("OPC-UA client node %s: 'Subscribe' service called with node Id: %s parameters", ros::this_node::getName().c_str(), req.node.nodeId.c_str());
00338
00339 try {
00340
00341
00342 OpcUa::Node variable = _client.GetNode(req.node.nodeId);
00343 std::string node_string = OpcUa::ToString(variable.GetId());
00344
00345 ros::NodeHandle nodeHandle("~");
00346 _callback_publishers[node_string] = nodeHandle.advertise<ros_opcua_msgs::TypeValue>(req.callback_topic, 1);
00347
00348 _subscriptions[node_string] = _client.CreateSubscription(100, _sclt);
00349 _subscription_handles[node_string] = _subscriptions[node_string]->SubscribeDataChange(variable);
00350
00351 ROS_INFO("Node successfully subscribed!");
00352 res.success = true;
00353 }
00354 catch (const std::exception& exc){
00355 ROS_ERROR("OPC-UA client node %s: 'Subscribe' service called with node Id: %s parameters failed!", ros::this_node::getName().c_str(), req.node.nodeId.c_str());
00356
00357 res.success = false;
00358 char err_string[100];
00359 sprintf(err_string, "Subscribe service failed with exception: %s", exc.what());
00360 res.error_message = err_string;
00361 }
00362 catch (...)
00363 {
00364 ROS_ERROR("OPC-UA client node %s: 'Subscribe' service called with node Id: %s parameters failed!", ros::this_node::getName().c_str(), req.node.nodeId.c_str());
00365
00366 res.success = false;
00367 res.error_message = "Subscribe service failed with Unknown exception";
00368 }
00369
00370 return true;
00371 }
00372
00379 bool unsubscribe(ros_opcua_srvs::Unsubscribe::Request &req, ros_opcua_srvs::Unsubscribe::Response &res)
00380 {
00381 ROS_DEBUG("OPC-UA client node %s: 'Unsubscribe' service called with node Id: %s parameters", ros::this_node::getName().c_str(), req.node.nodeId.c_str());
00382
00383 try {
00384
00385
00386
00387
00388 OpcUa::Node variable = _client.GetNode(req.node.nodeId);
00389 std::string node_string = OpcUa::ToString(variable.GetId());
00390
00391 _subscriptions[node_string]->UnSubscribe(_subscription_handles[node_string]);
00392 _callback_publishers[node_string].shutdown();
00393
00394 _subscriptions.erase(node_string);
00395 _subscription_handles.erase(node_string);
00396 _callback_publishers.erase(node_string);
00397
00398 ROS_INFO("Node successfully unsubscribed!");
00399 res.success = true;
00400 }
00401 catch (const std::exception& exc){
00402 ROS_ERROR("OPC-UA client node %s: 'Unsubscribe' service called with node Id: %s parameters failed!", ros::this_node::getName().c_str(), req.node.nodeId.c_str());
00403
00404 res.success = false;
00405 char err_string[100];
00406 sprintf(err_string, "Unsubscribe service failed with exception: %s", exc.what());
00407 res.error_message = err_string;
00408 }
00409 catch (...)
00410 {
00411 ROS_ERROR("OPC-UA client node %s: 'Unsubscribe' service called with node Id: %s parameters failed!", ros::this_node::getName().c_str(), req.node.nodeId.c_str());
00412
00413 res.success = false;
00414 res.error_message = "Unsubscribe service failed with Unknown exception";
00415 }
00416
00417 return true;
00418 }
00419
00423 void on_shutdown(int sig)
00424 {
00425 _client.Disconnect();
00426
00427 ros::shutdown();
00428 }
00429
00436 int main (int argc, char** argv)
00437 {
00438 ros::init(argc, argv, "opcua_client_node");
00439 ros::NodeHandle nodeHandle("~");
00440 signal(SIGINT, on_shutdown);
00441
00442 ros::ServiceServer connect_service = nodeHandle.advertiseService("connect", connect);
00443 ROS_DEBUG("OPC-UA client node %s: 'Connect' service available on on: %s", ros::this_node::getName().c_str(), connect_service.getService().c_str());
00444 ros::ServiceServer disconnect_service = nodeHandle.advertiseService("disconnect", disconnect);
00445 ROS_DEBUG("OPC-UA client node %s: 'Disconnect' service available on: %s", ros::this_node::getName().c_str(), disconnect_service.getService().c_str());
00446
00447
00448 ros::ServiceServer list_node_service = nodeHandle.advertiseService("list_node", list_node);
00449 ROS_DEBUG("OPC-UA client node %s: 'ListNode' service available on on: %s", ros::this_node::getName().c_str(), connect_service.getService().c_str());
00450
00451
00452 ros::ServiceServer call_method_service = nodeHandle.advertiseService("call_method", call_method);
00453 ROS_DEBUG("OPC-UA client node %s: 'CallMethod' service available on: %s", ros::this_node::getName().c_str(), call_method_service.getService().c_str());
00454
00455
00456 ros::ServiceServer read_service = nodeHandle.advertiseService("read", read);
00457 ROS_DEBUG("OPC-UA client node %s: 'Read' service available on: %s", ros::this_node::getName().c_str(), read_service.getService().c_str());
00458
00459
00460 ros::ServiceServer write_service = nodeHandle.advertiseService("write", write);
00461 ROS_DEBUG("OPC-UA client node %s: 'Write' service available on: %s", ros::this_node::getName().c_str(), write_service.getService().c_str());
00462
00463
00464 ros::ServiceServer subscribe_service = nodeHandle.advertiseService("subscribe", subscribe);
00465 ROS_DEBUG("OPC-UA client node %s: 'Subscribe' service available on: %s", ros::this_node::getName().c_str(), subscribe_service.getService().c_str());
00466 ros::ServiceServer unsubscribe_service = nodeHandle.advertiseService("unsubscribe", unsubscribe);
00467 ROS_DEBUG("OPC-UA client node %s: 'Unsubscribe' service available on: %s", ros::this_node::getName().c_str(), unsubscribe_service.getService().c_str());
00468
00469
00470 ROS_INFO("OPCUA client node: %s is ready!", ros::this_node::getName().c_str());
00471
00472 ros::spin();
00473
00474 return 0;
00475 }