From 6e11930b343f5137e7aed6a9fd69bd87b1795ea9 Mon Sep 17 00:00:00 2001 From: Johann Mantel <j-mantel@gmx.net> Date: Fri, 18 Jun 2021 12:01:48 +0200 Subject: [PATCH] implement parameters as ArmarX properties --- .../drivers/SickLaserUnit/SickLaserUnit.cpp | 476 +++++++++--------- .../drivers/SickLaserUnit/SickLaserUnit.h | 57 ++- 2 files changed, 273 insertions(+), 260 deletions(-) diff --git a/source/RobotAPI/drivers/SickLaserUnit/SickLaserUnit.cpp b/source/RobotAPI/drivers/SickLaserUnit/SickLaserUnit.cpp index a38cc31d3..4ee9c8b0b 100644 --- a/source/RobotAPI/drivers/SickLaserUnit/SickLaserUnit.cpp +++ b/source/RobotAPI/drivers/SickLaserUnit/SickLaserUnit.cpp @@ -28,216 +28,222 @@ // #include <SimoxUtility/color/Color.h> -namespace armarx { - -armarx::PropertyDefinitionsPtr SickLaserUnit::createPropertyDefinitions() { - armarx::PropertyDefinitionsPtr def = - new ComponentPropertyDefinitions(getConfigIdentifier()); - // Publish to a topic (passing the TopicListenerPrx). - // def->topic(myTopicListener); - - // Subscribe to a topic (passing the topic name). - // def->topic<PlatformUnitListener>("MyTopic"); - - // Use (and depend on) another component (passing the ComponentInterfacePrx). - // def->component(myComponentProxy) - - // Add a required property. - def->required(properties.laserScannerTopicName, "laserScannerTopicName", - "Name of the published Topic"); - - // Add an optionalproperty. - def->optional(properties.updatePeriod, "updatePeriod", "Update every ? ms"); - def->optional(properties.angleOffset, "angleOffset", - "Offset to the LaserScanner Angle"); - def->optional(properties.devices, "devices", "List of Device Names"); - - return def; -} - -void SickLaserUnit::onInitComponent() { - // Topics and properties defined above are automagically registered. - - // Keep debug observer data until calling `sendDebugObserverBatch()`. - // (Requies the armarx::DebugObserverComponentPluginUser.) - // setDebugObserverBatchModeEnabled(true); - - std::string topicName = - getProperty<std::string>("laserScannerTopicName").getValue(); - offeringTopic(topicName); - ARMARX_INFO << "Going to report on topic " << topicName; - int updatePeriod = getProperty<int>("updatePeriod").getValue(); - float angleOffset = getProperty<float>("angleOffset").getValue(); - - std::string deviceStrings = getProperty<std::string>("devices").getValue(); - std::vector<std::string> splitDeviceStrings = Split(deviceStrings, ";"); - - ARMARX_INFO_S << "SickLaserUnit sagt Hallo Welt!"; - - std::string scannerName; - if (false == nhPriv.getParam("scanner_type", scannerName)) { - ROS_ERROR("cannot find parameter " - "scanner_type" - " in the param set. Please specify scanner_type."); - ROS_ERROR("Try to set %s as fallback.\n", nodeName.c_str()); - scannerName = nodeName; - } - - bool useTCP = false; - std::string hostname; - if (nhPriv.getParam("hostname", hostname)) { - useTCP = true; - } - bool changeIP = false; - std::string sNewIp; - if (nhPriv.getParam("new_IP_address", sNewIp)) { - changeIP = true; - } - std::string port; - nhPriv.param<std::string>("port", port, "2112"); - - int timelimit; - nhPriv.param("timelimit", timelimit, 5); - - bool subscribe_datagram; - int device_number; - nhPriv.param("subscribe_datagram", subscribe_datagram, false); - nhPriv.param("device_number", device_number, 0); - - sick_scan::SickGenericParser *parser = - new sick_scan::SickGenericParser(scannerName); - - double param; - char colaDialectId = 'A'; // A or B (Ascii or Binary) - - if (nhPriv.getParam("range_min", param)) { - parser->set_range_min(param); - } - if (nhPriv.getParam("range_max", param)) { - parser->set_range_max(param); - } - if (nhPriv.getParam("time_increment", param)) { - parser->set_time_increment(param); - } - - /* - * Check, if parameter for protocol type is set - */ - bool use_binary_protocol = true; - if (true == nhPriv.getParam("emul_sensor", emulSensor)) { - ROS_INFO("Found emul_sensor overwriting default settings. Emulation: %s\n", - emulSensor ? "True" : "False"); - } - if (true == nhPriv.getParam("use_binary_protocol", use_binary_protocol)) { - ROS_INFO("Found sopas_protocol_type param overwriting default protocol:"); - if (use_binary_protocol == true) { - ROS_INFO("Binary protocol activated"); - } else { - if (parser->getCurrentParamPtr()->getNumberOfLayers() > 4) { - nhPriv.setParam("sopas_protocol_type", true); - use_binary_protocol = true; - ROS_WARN( - "This scanner type does not support ASCII communication.\n" - "Binary communication has been activated.\n" - "The parameter \"sopas_protocol_type\" has been set to \"True\"."); - } else { - ROS_INFO("ASCII protocol activated"); - } +namespace armarx +{ + + std::string protocolToString(SickLaserUnit::Protocol protocol) + { + std::string protocolStr; + + switch (protocol) + { + case SickLaserUnit::Protocol::ASCII: + protocolStr = "ASCII"; + break; + case SickLaserUnit::Protocol::Binary: + protocolStr = "Binary"; + break; + } + return modeStr; } - parser->getCurrentParamPtr()->setUseBinaryProtocol(use_binary_protocol); - } - - if (parser->getCurrentParamPtr()->getUseBinaryProtocol()) { - colaDialectId = 'B'; - } else { - colaDialectId = 'A'; - } - - int result = sick_scan::ExitError; - - sick_scan::SickScanConfig cfg; -} - -void SickLaserUnit::onConnectComponent() { - ROS_INFO("Start initialising scanner [Ip: %s] [Port: %s]", hostname.c_str(), - port.c_str()); - // attempt to connect/reconnect - delete s; // disconnect scanner - if (useTCP) { - s = new sick_scan::SickScanCommonTcp(hostname, port, timelimit, parser, - colaDialectId); - } else { - ROS_ERROR("TCP is not switched on. Probably hostname or port not set. Use " - "roslaunch to start node."); - exit(-1); - } - - if (emulSensor) { - s->setEmulSensor(true); - } - result = s->init(); - - isInitialized = true; - signal(SIGINT, - SIG_DFL); // change back to standard signal handler after initialising - if (result == sick_scan::ExitSuccess) // OK -> loop again - { - if (changeIP) { - runState = scanner_finalize; + + armarx::PropertyDefinitionsPtr SickLaserUnit::createPropertyDefinitions() + { + armarx::PropertyDefinitionsPtr def = + new ComponentPropertyDefinitions(getConfigIdentifier()); + // Publish to a topic (passing the TopicListenerPrx). + // def->topic(myTopicListener); + + // Subscribe to a topic (passing the topic name). + // def->topic<PlatformUnitListener>("MyTopic"); + + // Use (and depend on) another component (passing the ComponentInterfacePrx). + // def->component(myComponentProxy) + + //communication parameters + def->optional(properties.hostname, "hostname", "Hostname of the LaserScanner"); + def->optional(properties.newIpAddress, "newIpAddress", "New IP address for the LaserScanner"); + def->optional(properties.port, "port", "port to use on the LaserScanner"); + def->optional(properties.timelimit, "timelimit", "timelimit for communication"); + def->optional(properties.subscribeDatagram, "subscribeDatagram", "subscribe to Datagram in communication or not"); + def->optional(properties.protocol, "protocol", "Either use ASCII or Binary protocol") + .map(protocolToString(Protocol::ASCII), Protocol::ASCII) + .map(protocolToString(Protocol::Binary), Protocol::Binary); + def->optional(properties.sopasProtocolType, "sopasProtocolType", "Automatically set to true if the Scanner does not support ASCII communication"); + //Scanner parameters + def->required(properties.scannerType, "scannerType", "Name of the LaserScanner"); + def->optional(properties.deviceNumber, "deviceNumber", "number of the LaserScanner Device"); + def->required(properties.rangeMin, "rangeMin", "minimum Range of the Scanner"); + def->required(properties.rangeMax, "rangeMax", "maximum Range of the Scanner"); + def->optional(properties.timeIncrement, "timeIncrement", "timeIncrement??"); + //Additional configuration + def->optional(properties.emulSensor, "emulateSensor", "overwrite the default Settings and don't connect to Scanner"); + + return def; } - runState = scanner_run; // after initialising switch to run state - } else { - runState = scanner_init; // If there was an error, try to restart scanner - } - // Do things after connecting to topics and components. - - /* (Requies the armarx::DebugObserverComponentPluginUser.) - // Use the debug observer to log data over time. - // The data can be viewed in the ObserverView and the LivePlotter. - // (Before starting any threads, we don't need to lock mutexes.) - { - setDebugObserverDatafield("numBoxes", properties.numBoxes); - setDebugObserverDatafield("boxLayerName", properties.boxLayerName); - sendDebugObserverBatch(); - } - */ - - /* (Requires the armarx::ArVizComponentPluginUser.) - // Draw boxes in ArViz. - // (Before starting any threads, we don't need to lock mutexes.) - drawBoxes(properties, arviz); - */ - - /* (Requires the armarx::LightweightRemoteGuiComponentPluginUser.) - // Setup the remote GUI. - { - createRemoteGuiTab(); - RemoteGui_startRunningTask(); - } - */ -} - -void SickLaserUnit::run() { - while (!task->isStopped()) { - if (result == sick_scan::ExitSuccess) // OK -> loop again + + void SickLaserUnit::onInitComponent() { - ros::spinOnce(); - result = s->loopOnce(); - } else { - runState = scanner_finalize; // interrupt + // Topics and properties defined above are automagically registered. + + // Keep debug observer data until calling `sendDebugObserverBatch()`. + // (Requies the armarx::DebugObserverComponentPluginUser.) + // setDebugObserverBatchModeEnabled(true); + + ARMARX_INFO_S << "SickLaserUnit sagt Hallo Welt!"; + + bool useTCP = false; + if (properties.hostname != "") + { + useTCP = true; + } + bool changeIP = false; + if (sNewIp != "") + { + changeIP = true; + } + //scanner Parameters + sick_scan::SickGenericParser* parser = new sick_scan::SickGenericParser(properties.scannerType); + parser->set_range_min(properties.rangeMin); + parser->set_range_max(properties.rangeMax); + parser->set_time_increment(properties.timeIncrement); + char colaDialectId = 'A'; // A or B (Ascii or Binary) + + if (properties.emulSensor) + { + ARMARX_INFO("Found paraemter emulSensor overwriting default settings. Emulation: True\n"); + } + switch (properties.protocol) + { + case Protocol::ASCII: + if (parser->getCurrentParamPtr()->getNumberOfLayers() > 4) + { + ARMARX_WARNING( + "This scanner type does not support ASCII communication.\n" + "Binary communication has been activated.\n" + "The parameter \"sopasProtocolType\" has been set to \"true\"."); + properties.sopasProtocolType = true; + properties.protocol = Protocol::Binary; + } + else + { + ARMARX_INFO("ASCII protocol activated"); + } + break; + case Protocol::Binary: + ARMARX_INFO("Binary protocol activated"); + break; + default: + ARMARX_WARNING("Unknown protocol type. Defaulting to Binary protocol.\n"); + properties.protocol = Protocol::Binary; + } + if (properties.protocol == Protocol::ASCII) + { + parser->getCurrentParamPtr()->setUseBinaryProtocol(false); + colaDialectId = 'A'; + } + else + { + parser->getCurrentParamPtr()->setUseBinaryProtocol(true); + colaDialectId = 'B'; + } } - } -} -void SickLaserUnit::onDisconnectComponent() {} + void SickLaserUnit::onConnectComponent() + { + ARMARX_INFO("Start initialising scanner [Ip: %s] [Port: %s]", hostname.c_str(), + port.c_str()); + // attempt to connect/reconnect + delete s; // disconnect scanner + if (useTCP) + { + s = new sick_scan::SickScanCommonTcp(hostname, port, timelimit, parser, + colaDialectId); + } + else + { + ROS_ERROR("TCP is not switched on. Probably hostname or port not set. Use " + "roslaunch to start node."); + exit(-1); + } -void SickLaserUnit::onExitComponent() {} + if (emulSensor) + { + s->setEmulSensor(true); + } + result = s->init(); -std::string SickLaserUnit::getDefaultName() const { return "SickLaserUnit"; } + isInitialized = true; + signal(SIGINT, + SIG_DFL); // change back to standard signal handler after initialising + if (result == sick_scan::ExitSuccess) // OK -> loop again + { + if (changeIP) + { + runState = scanner_finalize; + } + runState = scanner_run; // after initialising switch to run state + } + else + { + runState = scanner_init; // If there was an error, try to restart scanner + } + // Do things after connecting to topics and components. -/* (Requires the armarx::LightweightRemoteGuiComponentPluginUser.) -void SickLaserUnit::createRemoteGuiTab() -{ + /* (Requies the armarx::DebugObserverComponentPluginUser.) + // Use the debug observer to log data over time. + // The data can be viewed in the ObserverView and the LivePlotter. + // (Before starting any threads, we don't need to lock mutexes.) + { + setDebugObserverDatafield("numBoxes", properties.numBoxes); + setDebugObserverDatafield("boxLayerName", properties.boxLayerName); + sendDebugObserverBatch(); + } + */ + + /* (Requires the armarx::ArVizComponentPluginUser.) + // Draw boxes in ArViz. + // (Before starting any threads, we don't need to lock mutexes.) + drawBoxes(properties, arviz); + */ + + /* (Requires the armarx::LightweightRemoteGuiComponentPluginUser.) + // Setup the remote GUI. + { + createRemoteGuiTab(); + RemoteGui_startRunningTask(); + } + */ + } + + void SickLaserUnit::run() + { + while (!task->isStopped()) + { + if (result == sick_scan::ExitSuccess) // OK -> loop again + { + ros::spinOnce(); + result = s->loopOnce(); + } + else + { + runState = scanner_finalize; // interrupt + } + } + } + + void SickLaserUnit::onDisconnectComponent() {} + + void SickLaserUnit::onExitComponent() {} + + std::string SickLaserUnit::getDefaultName() const + { + return "SickLaserUnit"; + } + + /* (Requires the armarx::LightweightRemoteGuiComponentPluginUser.) + void SickLaserUnit::createRemoteGuiTab() + { using namespace armarx::RemoteGui::Client; // Setup the widgets. @@ -254,62 +260,62 @@ void SickLaserUnit::createRemoteGuiTab() GridLayout grid; int row = 0; { - grid.add(Label("Box Layer"), {row, 0}).add(tab.boxLayerName, {row, 1}); - ++row; + grid.add(Label("Box Layer"), {row, 0}).add(tab.boxLayerName, {row, 1}); + ++row; - grid.add(Label("Num Boxes"), {row, 0}).add(tab.numBoxes, {row, 1}); - ++row; + grid.add(Label("Num Boxes"), {row, 0}).add(tab.numBoxes, {row, 1}); + ++row; - grid.add(tab.drawBoxes, {row, 0}, {2, 1}); - ++row; + grid.add(tab.drawBoxes, {row, 0}, {2, 1}); + ++row; } VBoxLayout root = {grid, VSpacer()}; RemoteGui_createTab(getName(), root, &tab); -} + } -void SickLaserUnit::RemoteGui_update() -{ + void SickLaserUnit::RemoteGui_update() + { if (tab.boxLayerName.hasValueChanged() || tab.numBoxes.hasValueChanged()) { - std::scoped_lock lock(propertiesMutex); - properties.boxLayerName = tab.boxLayerName.getValue(); - properties.numBoxes = tab.numBoxes.getValue(); + std::scoped_lock lock(propertiesMutex); + properties.boxLayerName = tab.boxLayerName.getValue(); + properties.numBoxes = tab.numBoxes.getValue(); - { - setDebugObserverDatafield("numBoxes", properties.numBoxes); - setDebugObserverDatafield("boxLayerName", properties.boxLayerName); - sendDebugObserverBatch(); - } + { + setDebugObserverDatafield("numBoxes", properties.numBoxes); + setDebugObserverDatafield("boxLayerName", properties.boxLayerName); + sendDebugObserverBatch(); + } } if (tab.drawBoxes.wasClicked()) { - // Lock shared variables in methods running in seperate threads - // and pass them to functions. This way, the called functions do - // not need to think about locking. - std::scoped_lock lock(propertiesMutex, arvizMutex); - drawBoxes(properties, arviz); + // Lock shared variables in methods running in seperate threads + // and pass them to functions. This way, the called functions do + // not need to think about locking. + std::scoped_lock lock(propertiesMutex, arvizMutex); + drawBoxes(properties, arviz); } -} -*/ + } + */ -/* (Requires the armarx::ArVizComponentPluginUser.) -void SickLaserUnit::drawBoxes(const SickLaserUnit::Properties& p, viz::Client& -arviz) -{ + /* (Requires the armarx::ArVizComponentPluginUser.) + void SickLaserUnit::drawBoxes(const SickLaserUnit::Properties& p, viz::Client& + arviz) + { // Draw something in ArViz (requires the armarx::ArVizComponentPluginUser. // See the ArVizExample in RobotAPI for more examples. viz::Layer layer = arviz.layer(p.boxLayerName); for (int i = 0; i < p.numBoxes; ++i) { - layer.add(viz::Box("box_" + std::to_string(i)) - .position(Eigen::Vector3f(i * 100, 0, 0)) - .size(20).color(simox::Color::blue())); + layer.add(viz::Box("box_" + std::to_string(i)) + .position(Eigen::Vector3f(i * 100, 0, 0)) + .size(20).color(simox::Color::blue())); } arviz.commit(layer); -} -*/ + } + */ } // namespace armarx diff --git a/source/RobotAPI/drivers/SickLaserUnit/SickLaserUnit.h b/source/RobotAPI/drivers/SickLaserUnit/SickLaserUnit.h index 5eaf5a13c..b4233d8c9 100644 --- a/source/RobotAPI/drivers/SickLaserUnit/SickLaserUnit.h +++ b/source/RobotAPI/drivers/SickLaserUnit/SickLaserUnit.h @@ -22,19 +22,19 @@ #pragma once - // #include <mutex> #include <ArmarXCore/core/Component.h> -// #include <ArmarXCore/libraries/ArmarXCoreComponentPlugins/DebugObserverComponentPlugin.h> +// #include +// <ArmarXCore/libraries/ArmarXCoreComponentPlugins/DebugObserverComponentPlugin.h> -// #include <ArmarXGui/libraries/ArmarXGuiComponentPlugins/LightweightRemoteGuiComponentPlugin.h> +// #include +// <ArmarXGui/libraries/ArmarXGuiComponentPlugins/LightweightRemoteGuiComponentPlugin.h> // #include <RobotAPI/libraries/RobotAPIComponentPlugins/ArVizComponentPlugin.h> -# include <vector> - +#include <vector> namespace armarx { @@ -50,20 +50,21 @@ namespace armarx * * Detailed description of class SickLaserUnit. */ - class SickLaserUnit : - virtual public armarx::Component + class SickLaserUnit : virtual public armarx::Component // , virtual public armarx::DebugObserverComponentPluginUser // , virtual public armarx::LightweightRemoteGuiComponentPluginUser // , virtual public armarx::ArVizComponentPluginUser { public: - /// @see armarx::ManagedIceObject::getDefaultName() std::string getDefaultName() const override; - + enum class Protocol + { + ASCII, + Binary + }; protected: - /// @see PropertyUser::createPropertyDefinitions() armarx::PropertyDefinitionsPtr createPropertyDefinitions() override; @@ -79,7 +80,6 @@ namespace armarx /// @see armarx::ManagedIceObject::onExitComponent() void onExitComponent() override; - /* (Requires armarx::LightweightRemoteGuiComponentPluginUser.) /// This function should be called once in onConnect() or when you /// need to re-create the Remote GUI tab. @@ -91,9 +91,7 @@ namespace armarx void RemoteGui_update() override; */ - private: - // Private methods go here. // Forward declare `Properties` if you used it before its defined. @@ -104,27 +102,39 @@ namespace armarx void drawBoxes(const Properties& p, viz::Client& arviz); */ - private: - // Private member variables go here. - /// Properties shown in the Scenario GUI. struct Properties { - std::string laserScannerTopicName; - int updatePeriod = 1; - float angleOffset = 0.0; - std::string devices = "Device1; Scanner2"; + //communication parameters + std::string hostname = ""; + std::string newIpAddress = ""; + std::string port = "2112"; + int timelimit = 5; + bool subscribeDatagram = false; + Protocol protocol = Protocol::Binary; + bool sopasProtocolType = false; + //scanner parameters + std::string scannerType; + int deviceNumber = 0; + double rangeMin; + double rangeMax; + double timeIncrement; + //additional parameters + bool emulSensor = false; }; Properties properties; + + char colaDialectId = 'B'; + int result = sick_scan::ExitError; + sick_scan::SickScanConfig cfg; /* Use a mutex if you access variables from different threads * (e.g. ice functions and RemoteGui_update()). std::mutex propertiesMutex; */ - /* (Requires the armarx::LightweightRemoteGuiComponentPluginUser.) /// Tab shown in the Remote GUI. struct RemoteGuiTab : armarx::RemoteGui::Client::Tab @@ -137,13 +147,10 @@ namespace armarx RemoteGuiTab tab; */ - /* (Requires the armarx::ArVizComponentPluginUser.) * When used from different threads, an ArViz client needs to be synchronized. /// Protects the arviz client inherited from the ArViz plugin. std::mutex arvizMutex; */ - - }; -} +} // namespace armarx -- GitLab