From eeda820dfb449201f0193536a6910e81c226b5b7 Mon Sep 17 00:00:00 2001 From: Johann Mantel <j-mantel@gmx.net> Date: Thu, 17 Jun 2021 18:09:12 +0200 Subject: [PATCH] define initial Properties and insert code example from ROS driver --- source/RobotAPI/components/CMakeLists.txt | 1 - source/RobotAPI/drivers/CMakeLists.txt | 1 + .../drivers/SickLaserUnit/CMakeLists.txt | 2 +- .../drivers/SickLaserUnit/SickLaserUnit.cpp | 376 ++++++++++++------ .../drivers/SickLaserUnit/SickLaserUnit.h | 14 +- 5 files changed, 260 insertions(+), 134 deletions(-) diff --git a/source/RobotAPI/components/CMakeLists.txt b/source/RobotAPI/components/CMakeLists.txt index 0c3653739..1294f9b62 100644 --- a/source/RobotAPI/components/CMakeLists.txt +++ b/source/RobotAPI/components/CMakeLists.txt @@ -32,4 +32,3 @@ add_subdirectory(ViewSelection) add_subdirectory(SkillObserver) add_subdirectory(ArticulatedObjectLocalizerExample) -add_subdirectory(drivers/SickLaserUnit) \ No newline at end of file diff --git a/source/RobotAPI/drivers/CMakeLists.txt b/source/RobotAPI/drivers/CMakeLists.txt index 731765e4b..f8de74539 100644 --- a/source/RobotAPI/drivers/CMakeLists.txt +++ b/source/RobotAPI/drivers/CMakeLists.txt @@ -7,3 +7,4 @@ add_subdirectory(GamepadUnit) add_subdirectory(MetaWearIMU) add_subdirectory(KITProstheticHandDriver) add_subdirectory(KITProsthesisIceDriver) +add_subdirectory(SickLaserUnit) diff --git a/source/RobotAPI/drivers/SickLaserUnit/CMakeLists.txt b/source/RobotAPI/drivers/SickLaserUnit/CMakeLists.txt index 2ff404a3f..6d65f022c 100644 --- a/source/RobotAPI/drivers/SickLaserUnit/CMakeLists.txt +++ b/source/RobotAPI/drivers/SickLaserUnit/CMakeLists.txt @@ -22,7 +22,7 @@ armarx_add_component( # ArmarXGui ## ArmarXGuiComponentPlugins # For RemoteGui plugin. # RobotAPI - ## RobotAPICore + RobotAPICore ## RobotAPIInterfaces ## RobotAPIComponentPlugins # For ArViz and other plugins. diff --git a/source/RobotAPI/drivers/SickLaserUnit/SickLaserUnit.cpp b/source/RobotAPI/drivers/SickLaserUnit/SickLaserUnit.cpp index 024eda12b..2de3d8415 100644 --- a/source/RobotAPI/drivers/SickLaserUnit/SickLaserUnit.cpp +++ b/source/RobotAPI/drivers/SickLaserUnit/SickLaserUnit.cpp @@ -28,169 +28,291 @@ // #include <SimoxUtility/color/Color.h> +namespace armarx { -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"); +armarx::PropertyDefinitionsPtr SickLaserUnit::createPropertyDefinitions() { + armarx::PropertyDefinitionsPtr def = + new ComponentPropertyDefinitions(getConfigIdentifier()); + // Publish to a topic (passing the TopicListenerPrx). + // def->topic(myTopicListener); - // Use (and depend on) another component (passing the ComponentInterfacePrx). - // def->component(myComponentProxy) + // 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.boxLayerName, "p.box.LayerName", "Name of the box layer in ArViz."); + // Add a required property. + def->required(properties.laserScannerTopicName, "laserScannerTopicName", + "Name of the published Topic"); - // Add an optionalproperty. - def->optional(properties.numBoxes, "p.box.Number", "Number of boxes to draw in ArViz."); + // 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; +} - 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"); + } } + parser->getCurrentParamPtr()->setUseBinaryProtocol(use_binary_protocol); + } + if (parser->getCurrentParamPtr()->getUseBinaryProtocol()) { + colaDialectId = 'B'; + } else { + colaDialectId = 'A'; + } - void SickLaserUnit::onInitComponent() - { - // Topics and properties defined above are automagically registered. - - // Keep debug observer data until calling `sendDebugObserverBatch()`. - // (Requies the armarx::DebugObserverComponentPluginUser.) - // setDebugObserverBatchModeEnabled(true); - } + int result = sick_scan::ExitError; + sick_scan::SickScanConfig cfg; +} - void SickLaserUnit::onConnectComponent() - { - // 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::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; } + 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::onDisconnectComponent() +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() - { - - } +void SickLaserUnit::onExitComponent() {} +std::string SickLaserUnit::getDefaultName() const { return "SickLaserUnit"; } - std::string SickLaserUnit::getDefaultName() const - { - return "SickLaserUnit"; - } +/* (Requires the armarx::LightweightRemoteGuiComponentPluginUser.) +void SickLaserUnit::createRemoteGuiTab() +{ + using namespace armarx::RemoteGui::Client; + // Setup the widgets. - /* (Requires the armarx::LightweightRemoteGuiComponentPluginUser.) - void SickLaserUnit::createRemoteGuiTab() - { - using namespace armarx::RemoteGui::Client; + tab.boxLayerName.setValue(properties.boxLayerName); - // Setup the widgets. + tab.numBoxes.setValue(properties.numBoxes); + tab.numBoxes.setRange(0, 100); - tab.boxLayerName.setValue(properties.boxLayerName); + tab.drawBoxes.setLabel("Draw Boxes"); - tab.numBoxes.setValue(properties.numBoxes); - tab.numBoxes.setRange(0, 100); + // Setup the layout. - tab.drawBoxes.setLabel("Draw Boxes"); + GridLayout grid; + int row = 0; + { + grid.add(Label("Box Layer"), {row, 0}).add(tab.boxLayerName, {row, 1}); + ++row; - // Setup the layout. + grid.add(Label("Num Boxes"), {row, 0}).add(tab.numBoxes, {row, 1}); + ++row; - GridLayout grid; - int row = 0; - { - grid.add(Label("Box Layer"), {row, 0}).add(tab.boxLayerName, {row, 1}); - ++row; + grid.add(tab.drawBoxes, {row, 0}, {2, 1}); + ++row; + } - grid.add(Label("Num Boxes"), {row, 0}).add(tab.numBoxes, {row, 1}); - ++row; + VBoxLayout root = {grid, VSpacer()}; + RemoteGui_createTab(getName(), root, &tab); +} - grid.add(tab.drawBoxes, {row, 0}, {2, 1}); - ++row; - } - VBoxLayout root = {grid, VSpacer()}; - RemoteGui_createTab(getName(), root, &tab); +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(); + + { + setDebugObserverDatafield("numBoxes", properties.numBoxes); + setDebugObserverDatafield("boxLayerName", properties.boxLayerName); + sendDebugObserverBatch(); + } } - - - void SickLaserUnit::RemoteGui_update() + if (tab.drawBoxes.wasClicked()) { - if (tab.boxLayerName.hasValueChanged() || tab.numBoxes.hasValueChanged()) - { - std::scoped_lock lock(propertiesMutex); - properties.boxLayerName = tab.boxLayerName.getValue(); - properties.numBoxes = tab.numBoxes.getValue(); - - { - 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) { - // 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())); - } - arviz.commit(layer); + 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 8b681b1f5..5eaf5a13c 100644 --- a/source/RobotAPI/drivers/SickLaserUnit/SickLaserUnit.h +++ b/source/RobotAPI/drivers/SickLaserUnit/SickLaserUnit.h @@ -33,6 +33,8 @@ // #include <RobotAPI/libraries/RobotAPIComponentPlugins/ArVizComponentPlugin.h> +# include <vector> + namespace armarx { @@ -50,9 +52,9 @@ namespace armarx */ class SickLaserUnit : virtual public armarx::Component - // , virtual public armarx::DebugObserverComponentPluginUser - // , virtual public armarx::LightweightRemoteGuiComponentPluginUser - // , virtual public armarx::ArVizComponentPluginUser + // , virtual public armarx::DebugObserverComponentPluginUser + // , virtual public armarx::LightweightRemoteGuiComponentPluginUser + // , virtual public armarx::ArVizComponentPluginUser { public: @@ -111,8 +113,10 @@ namespace armarx /// Properties shown in the Scenario GUI. struct Properties { - std::string boxLayerName; - int numBoxes = 10; + std::string laserScannerTopicName; + int updatePeriod = 1; + float angleOffset = 0.0; + std::string devices = "Device1; Scanner2"; }; Properties properties; /* Use a mutex if you access variables from different threads -- GitLab