cob_relayboard_node.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright 2017 Fraunhofer Institute for Manufacturing Engineering and Automation (IPA)
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *   http://www.apache.org/licenses/LICENSE-2.0
00009 
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016  
00017 
00018 //##################
00019 //#### includes ####
00020 
00021 // standard includes
00022 //--
00023 
00024 // ROS includes
00025 #include <ros/ros.h>
00026 #include <cob_relayboard/SerRelayBoard.h>
00027 
00028 // ROS message includes
00029 #include <std_msgs/Bool.h>
00030 #include <std_msgs/Float64.h>
00031 #include <cob_msgs/EmergencyStopState.h>
00032 
00033 // ROS service includes
00034 //--
00035 
00036 // external includes
00037 //--
00038 
00039 //####################
00040 //#### node class ####
00041 class NodeClass
00042 {
00043   //
00044 public:
00045   // create a handle for this node, initialize node
00046   ros::NodeHandle n;
00047   ros::NodeHandle n_priv;
00048 
00049   // topics to publish
00050   ros::Publisher topicPub_isEmergencyStop;
00051   ros::Publisher topicPub_Voltage;
00052   // topics to subscribe, callback is called for new messages arriving
00053   // --
00054 
00055   // Constructor
00056   NodeClass()
00057   {
00058     n = ros::NodeHandle();
00059     n_priv = ros::NodeHandle("~");
00060 
00061     topicPub_isEmergencyStop = n.advertise<cob_msgs::EmergencyStopState>("emergency_stop_state", 1);
00062     topicPub_Voltage = n.advertise<std_msgs::Float64>("voltage", 1);
00063 
00064     // Make sure member variables have a defined state at the beginning
00065     EM_stop_status_ = ST_EM_FREE;
00066     relayboard_available = false;
00067     relayboard_online = false;
00068     relayboard_timeout_ = 2.0;
00069     protocol_version_ = 1;
00070     duration_for_EM_free_ = ros::Duration(1);
00071   }
00072 
00073   // Destructor
00074   ~NodeClass()
00075   {
00076     delete m_SerRelayBoard;
00077   }
00078 
00079   void sendEmergencyStopStates();
00080   void sendBatteryVoltage();
00081   int init();
00082 
00083 private:
00084   std::string sComPort;
00085   SerRelayBoard * m_SerRelayBoard;
00086 
00087   int EM_stop_status_;
00088   ros::Duration duration_for_EM_free_;
00089   ros::Time time_of_EM_confirmed_;
00090   double relayboard_timeout_;
00091   int protocol_version_;
00092 
00093   ros::Time time_last_message_received_;
00094   bool relayboard_online; //the relayboard is sending messages at regular time
00095   bool relayboard_available; //the relayboard has sent at least one message -> publish topic
00096 
00097   // possible states of emergency stop
00098   enum
00099     {
00100       ST_EM_FREE = 0,
00101       ST_EM_ACTIVE = 1,
00102       ST_EM_CONFIRMED = 2
00103     };
00104 
00105   int requestBoardStatus();
00106 };
00107 
00108 //#######################
00109 //#### main programm ####
00110 int main(int argc, char** argv)
00111 {
00112   // initialize ROS, spezify name of node
00113   ros::init(argc, argv, "cob_relayboard_node");
00114 
00115   NodeClass node;
00116   if(node.init() != 0) return 1;
00117 
00118   ros::Rate r(20); //Cycle-Rate: Frequency of publishing EMStopStates
00119   while(node.n.ok())
00120     {
00121       node.sendEmergencyStopStates();
00122 
00123       ros::spinOnce();
00124       r.sleep();
00125     }
00126 
00127   return 0;
00128 }
00129 
00130 //##################################
00131 //#### function implementations ####
00132 
00133 int NodeClass::init()
00134 {
00135   if (n_priv.hasParam("ComPort"))
00136     {
00137       n_priv.getParam("ComPort", sComPort);
00138       ROS_INFO("Loaded ComPort parameter from parameter server: %s",sComPort.c_str());
00139     }
00140   else
00141     {
00142       sComPort ="/dev/ttyUSB0";
00143       ROS_WARN("ComPort Parameter not available, using default Port: %s",sComPort.c_str());
00144     }
00145 
00146   n_priv.param("relayboard_timeout", relayboard_timeout_, 2.0);
00147   n_priv.param("protocol_version", protocol_version_, 1);
00148 
00149   m_SerRelayBoard = new SerRelayBoard(sComPort, protocol_version_);
00150   ROS_INFO("Opened Relayboard at ComPort = %s", sComPort.c_str());
00151 
00152   m_SerRelayBoard->init();
00153 
00154   // Init member variable for EM State
00155   EM_stop_status_ = ST_EM_ACTIVE;
00156   duration_for_EM_free_ = ros::Duration(1);
00157 
00158   return 0;
00159 }
00160 
00161 int NodeClass::requestBoardStatus() {
00162   int ret;
00163 
00164   // Request Status of RelayBoard
00165   ret = m_SerRelayBoard->sendRequest();
00166   if(ret != SerRelayBoard::NO_ERROR) {
00167     ROS_ERROR("Error in sending message to Relayboard over SerialIO, lost bytes during writing");
00168   }
00169 
00170   ret = m_SerRelayBoard->evalRxBuffer();
00171   if(ret==SerRelayBoard::NOT_INITIALIZED) {
00172     ROS_ERROR("Failed to read relayboard data over Serial, the device is not initialized");
00173     relayboard_online = false;
00174   } else if(ret==SerRelayBoard::NO_MESSAGES) {
00175     ROS_ERROR("For a long time, no messages from RelayBoard have been received, check com port!");
00176     if(time_last_message_received_.toSec() - ros::Time::now().toSec() > relayboard_timeout_) {relayboard_online = false;}
00177   } else if(ret==SerRelayBoard::TOO_LESS_BYTES_IN_QUEUE) {
00178     //ROS_ERROR("Relayboard: Too less bytes in queue");
00179   } else if(ret==SerRelayBoard::CHECKSUM_ERROR) {
00180     ROS_ERROR("A checksum error occurred while reading from relayboard data");
00181   } else if(ret==SerRelayBoard::NO_ERROR) {
00182     relayboard_online = true;
00183     relayboard_available = true;
00184     time_last_message_received_ = ros::Time::now();
00185   }
00186 
00187   return 0;
00188 }
00189 
00190 void NodeClass::sendBatteryVoltage()
00191 {
00192   std_msgs::Float64 voltage;
00193   voltage.data = m_SerRelayBoard->getBatteryVoltage()/1000.0; //normalize from mV to V
00194   topicPub_Voltage.publish(voltage);
00195 }
00196 
00197 void NodeClass::sendEmergencyStopStates()
00198 {
00199   requestBoardStatus();
00200 
00201   if(!relayboard_available) return;
00202 
00203   sendBatteryVoltage();
00204 
00205 
00206   bool EM_signal;
00207   ros::Duration duration_since_EM_confirmed;
00208   cob_msgs::EmergencyStopState EM_msg;
00209 
00210   // assign input (laser, button) specific EM state TODO: Laser and Scanner stop can't be read independently (e.g. if button is stop --> no informtion about scanner, if scanner ist stop --> no informtion about button stop)
00211   EM_msg.emergency_button_stop = m_SerRelayBoard->isEMStop();
00212   EM_msg.scanner_stop = m_SerRelayBoard->isScannerStop();
00213 
00214   // determine current EMStopState
00215   EM_signal = (EM_msg.emergency_button_stop || EM_msg.scanner_stop);
00216 
00217   switch (EM_stop_status_)
00218     {
00219     case ST_EM_FREE:
00220       {
00221       if (EM_signal == true)
00222         {
00223           ROS_INFO("Emergency stop was issued");
00224           EM_stop_status_ = EM_msg.EMSTOP;
00225         }
00226       break;
00227       }
00228     case ST_EM_ACTIVE:
00229       {
00230       if (EM_signal == false)
00231         {
00232           ROS_INFO("Emergency stop was confirmed");
00233           EM_stop_status_ = EM_msg.EMCONFIRMED;
00234           time_of_EM_confirmed_ = ros::Time::now();
00235         }
00236       break;
00237       }
00238     case ST_EM_CONFIRMED:
00239       {
00240       if (EM_signal == true)
00241         {
00242           ROS_INFO("Emergency stop was issued");
00243           EM_stop_status_ = EM_msg.EMSTOP;
00244         }
00245       else
00246         {
00247           duration_since_EM_confirmed = ros::Time::now() - time_of_EM_confirmed_;
00248           if( duration_since_EM_confirmed.toSec() > duration_for_EM_free_.toSec() )
00249             {
00250             ROS_INFO("Emergency stop released");
00251             EM_stop_status_ = EM_msg.EMFREE;
00252             }
00253         }
00254       break;
00255       }
00256     };
00257 
00258 
00259   EM_msg.emergency_state = EM_stop_status_;
00260 
00261   //publish EM-Stop-Active-messages, when connection to relayboard got cut
00262   if(relayboard_online == false) {
00263     EM_msg.emergency_state = EM_msg.EMSTOP;
00264   }
00265   topicPub_isEmergencyStop.publish(EM_msg);
00266 }


cob_relayboard
Author(s): Christian Connette
autogenerated on Sat Jun 8 2019 21:02:18