diff --git a/add_action_server_client.sh b/add_action_server_client.sh index e0f41bb4be4b96812d1a6feb8109a971991aacbe..c98ff878bdfcb8fa3df7bd6d109b1f1fd46c0d83 100755 --- a/add_action_server_client.sh +++ b/add_action_server_client.sh @@ -47,7 +47,7 @@ do ;; ?) echo "invalid input argument ${OPTION}" - kill_exit "Usage: ./add_action_server_client.sh -o [server,client] -p ros_pkg -a action_name -m pkg/message.action" + kill_exit "Usage: add_action_server_client.sh -o [server,client] -p ros_pkg -a action_name -m message.action" exit ;; esac @@ -57,7 +57,7 @@ done if [ ! "${server_client}" ] || [ ! "${ros_pkg}" ] || [ ! "${action_name}" ] || [ ! "${action_file}" ] then echo "Missing input parameters..." - kill_exit "Usage: ./add_action_server_client.sh -o [server,client] -p ros_pkg -a action_name -m pkg/message.action" + kill_exit "Usage: add_action_server_client.sh -o [server,client] -p ros_pkg -a action_name -m message.action" fi #check server client parameter @@ -94,10 +94,7 @@ then action_file=${my_file} echo "ACTION file ${action_file} found!" else - echo "ACTION file ${action_file} does NOT exist, please check if file is in valid directories:" - echo " /ros/stacks/common_msgs/[msg-srv]" - echo " /ros/ros/std_[msgs-srvs]/[msg/srv]" - echo " /iri_stack/iri_msgs/[msg-srv]" + echo "ACTION file ${action_file} does NOT exist, please check if file is in valid directories" kill_exit "Aborting ..." fi diff --git a/add_publisher_subscriber.sh b/add_publisher_subscriber.sh index acd75f720c6cf7caaeecb7fb1a82657526b372b4..4163f3cf7607a0bc38b888e352f8966adf8aebca 100755 --- a/add_publisher_subscriber.sh +++ b/add_publisher_subscriber.sh @@ -51,7 +51,7 @@ do ;; ?) echo "invalid input argument ${OPTION}" - kill_exit "Usage: ./add_publisher_subscriber.sh -o [publisher,subscriber] -p ros_pkg -t topic_name -m pkg/message.msg -b 100" + kill_exit "Usage: add_publisher_subscriber.sh -o [publisher,subscriber] -p ros_pkg -t topic_name -m message.msg -b 100" exit ;; esac @@ -61,7 +61,7 @@ done if [ ! "${pub_subs}" ] || [ ! "${ros_pkg}" ] || [ ! "${topic_name}" ] || [ ! "${msg_file}" ] || [ ! "${buffer}" ] then echo "Missing input parameters..." - kill_exit "Usage: ./add_publisher_subscriber.sh -o [publisher,subscriber] -p ros_pkg -t topic_name -m pkg/message.msg -b 100" + kill_exit "Usage: add_publisher_subscriber.sh -o [publisher,subscriber] -p ros_pkg -t topic_name -m message.msg -b 100" fi #check publisher subscriber parameter @@ -105,10 +105,7 @@ then msg_file=${my_file} echo "MSG file ${msg_file} found!" else - echo "MSG file ${msg_file} does NOT exist, please check if file is in valid directories:" - echo " /ros/stacks/common_msgs/[msg-srv]" - echo " /ros/ros/std_[msgs-srvs]/[msg/srv]" - echo " /iri_stack/iri_msgs/[msg-srv]" + echo "MSG file ${msg_file} does NOT exist, please check if file is in valid directories" kill_exit "Aborting ..." fi @@ -146,7 +143,3 @@ else create_subscriber ${ros_pkg} ${topic_name} ${msg_file%.msg} ${file_pkg} ${buffer} ${node_h} ${node_c} ${driver_alg} fi -# WET -cd.. # to catkin work space -catkin_make --pkg ${ros_pkg} - diff --git a/add_server_client.sh b/add_server_client.sh index af339448846396d0368adeaa5893a9753bdb6dad..6d72bcf2ef90c0cb0e3db57284512a9888294b5e 100755 --- a/add_server_client.sh +++ b/add_server_client.sh @@ -47,7 +47,7 @@ do ;; ?) echo "invalid input argument ${OPTION}" - kill_exit "Usage: ./add_server_client.sh -o [server,client] -p ros_pkg -s service_name -m pkg/service.srv" + kill_exit "Usage: add_server_client.sh -o [server,client] -p ros_pkg -s service_name -m service.srv" exit ;; esac @@ -57,7 +57,7 @@ done if [ ! "${server_client}" ] || [ ! "${ros_pkg}" ] || [ ! "${service_name}" ] || [ ! "${srv_file}" ] then echo "Missing input parameters..." - kill_exit "Usage: ./add_server_client.sh -o [server,client] -p ros_pkg -s service_name -m pkg/service.srv" + kill_exit "Usage: add_server_client.sh -o [server,client] -p ros_pkg -s service_name -m service.srv" fi #check server client parameter @@ -93,10 +93,7 @@ then srv_file=${my_file} echo "SRV file ${srv_file} found!" else - echo "SRV file ${srv_file} does NOT exist, please check if file is in valid directories:" - echo " /ros/stacks/common_msgs/[msg-srv]" - echo " /ros/ros/std_[msgs-srvs]/[msg/srv]" - echo " /iri_stack/iri_msgs/[msg-srv]" + echo "SRV file ${srv_file} does NOT exist, please check if file is in valid directories" kill_exit "Aborting ..." fi @@ -122,7 +119,3 @@ then else create_client ${ros_pkg} ${service_name} ${srv_file%.srv} ${file_pkg} ${node_h} ${node_c} ${driver_alg} fi - -# WET -cd.. # to catkin work space -catkin_make --pkg ${ros_pkg} diff --git a/algorithm_templates/CMakeLists.txt b/algorithm_templates/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..1566d7f3447db22049c1a87d7d57f0f040a8cfa1 --- /dev/null +++ b/algorithm_templates/CMakeLists.txt @@ -0,0 +1,100 @@ +cmake_minimum_required(VERSION 2.8.3) +project(template_node) + +## Find catkin macros and libraries +find_package(catkin REQUIRED) +# ******************************************************************** +# Add catkin additional components here +# ******************************************************************** +find_package(catkin REQUIRED COMPONENTS iri_base_algorithm) + +## System dependencies are found with CMake's conventions +# find_package(Boost REQUIRED COMPONENTS system) + +# ******************************************************************** +# Add system and labrobotica dependencies here +# ******************************************************************** +# find_package(<dependency> REQUIRED) + +# ******************************************************************** +# Add topic, service and action definition here +# ******************************************************************** +## Generate messages in the 'msg' folder +# add_message_files( +# FILES +# Message1.msg +# Message2.msg +# ) + +## Generate services in the 'srv' folder +# add_service_files( +# FILES +# Service1.srv +# Service2.srv +# ) + +## Generate actions in the 'action' folder +# add_action_files( +# FILES +# Action1.action +# Action2.action +# ) + +## Generate added messages and services with any dependencies listed here +# generate_messages( +# DEPENDENCIES +# std_msgs # Or other packages containing msgs +# ) + +# ******************************************************************** +# Add the dynamic reconfigure file +# ******************************************************************** +generate_dynamic_reconfigure_options(cfg/Template.cfg) + +# ******************************************************************** +# Add run time dependencies here +# ******************************************************************** +catkin_package( +# INCLUDE_DIRS +# LIBRARIES +# ******************************************************************** +# Add ROS and IRI ROS run time dependencies +# ******************************************************************** + CATKIN_DEPENDS iri_base_algorithm +# ******************************************************************** +# Add system and labrobotica run time dependencies here +# ******************************************************************** +# DEPENDS +) + +########### +## Build ## +########### + +# ******************************************************************** +# Add the include directories +# ******************************************************************** +include_directories(include) +include_directories(${catkin_INCLUDE_DIRS}) +# include_directories(${<dependency>_INCLUDE_DIR}) + +## Declare a cpp library +# add_library(${PROJECT_NAME} <list of source files>) + +## Declare a cpp executable +add_executable(${PROJECT_NAME} src/template_alg.cpp src/template_alg_node.cpp) + +# ******************************************************************** +# Add the libraries +# ******************************************************************** +target_link_libraries(${PROJECT_NAME} ${catkin_LIBRARIES}) +# target_link_libraries(${PROJECT_NAME} ${<dependency>_LIBRARY}) + +# ******************************************************************** +# Add message headers dependencies +# ******************************************************************** +# add_dependencies(${PROJECT_NAME} <msg_package_name>_generate_messages_cpp) +# ******************************************************************** +# Add dynamic reconfigure dependencies +# ******************************************************************** +add_dependencies(${PROJECT_NAME} ${${PROJECT_NAME}_EXPORTED_TARGETS}) diff --git a/algorithm_templates/template_alg.cfg b/algorithm_templates/template_alg.cfg new file mode 100644 index 0000000000000000000000000000000000000000..ac1db9d0e7d4dea9520332db055f8876a7a10ceb --- /dev/null +++ b/algorithm_templates/template_alg.cfg @@ -0,0 +1,43 @@ +#! /usr/bin/env python +#* All rights reserved. +#* +#* Redistribution and use in source and binary forms, with or without +#* modification, are permitted provided that the following conditions +#* are met: +#* +#* * Redistributions of source code must retain the above copyright +#* notice, this list of conditions and the following disclaimer. +#* * Redistributions in binary form must reproduce the above +#* copyright notice, this list of conditions and the following +#* disclaimer in the documentation and/or other materials provided +#* with the distribution. +#* * Neither the name of the Willow Garage nor the names of its +#* contributors may be used to endorse or promote products derived +#* from this software without specific prior written permission. +#* +#* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +#* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +#* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +#* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +#* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +#* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +#* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +#* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +#* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +#* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +#* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +#* POSSIBILITY OF SUCH DAMAGE. +#*********************************************************** + +# Author: + +PACKAGE='template' + +from dynamic_reconfigure.parameter_generator_catkin import * + +gen = ParameterGenerator() + +# Name Type Reconfiguration level Description Default Min Max +#gen.add("velocity_scale_factor", double_t, 0, "Maximum velocity scale factor", 0.5, 0.0, 1.0) + +exit(gen.generate(PACKAGE, "TemplateAlg", "Template")) diff --git a/algorithm_templates/template_alg.cpp b/algorithm_templates/template_alg.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8ea2443da4b6537b2612fb313ffd5255ccb25dc4 --- /dev/null +++ b/algorithm_templates/template_alg.cpp @@ -0,0 +1,23 @@ +#include "template_alg.h" + +TemplateAlg::TemplateAlg(void) +{ + pthread_mutex_init(&this->access_,NULL); +} + +TemplateAlg::~TemplateAlg(void) +{ + pthread_mutex_destroy(&this->access_); +} + +void TemplateAlg::config_update(Config& config, uint32_t level) +{ + this->lock(); + + // save the current configuration + this->config_=config; + + this->unlock(); +} + +// TemplateAlg Public API diff --git a/algorithm_templates/template_alg.h b/algorithm_templates/template_alg.h new file mode 100644 index 0000000000000000000000000000000000000000..e111915480c58be633b01d0e7611485d2a145e97 --- /dev/null +++ b/algorithm_templates/template_alg.h @@ -0,0 +1,131 @@ +// Copyright (C) 2010-2011 Institut de Robotica i Informatica Industrial, CSIC-UPC. +// Author +// All rights reserved. +// +// This file is part of iri-ros-pkg +// iri-ros-pkg is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// +// IMPORTANT NOTE: This code has been generated through a script from the +// iri_ros_scripts. Please do NOT delete any comments to guarantee the correctness +// of the scripts. ROS topics can be easly add by using those scripts. Please +// refer to the IRI wiki page for more information: +// http://wikiri.upc.es/index.php/Robotics_Lab + +#ifndef _template_alg_h_ +#define _template_alg_h_ + +#include <template_namespace/TemplateConfig.h> + +//include template_alg main library + +/** + * \brief IRI ROS Specific Driver Class + * + * + */ +class TemplateAlg +{ + protected: + /** + * \brief define config type + * + * Define a Config type with the TemplateConfig. All driver implementations + * will then use the same variable type Config. + */ + pthread_mutex_t access_; + + // private attributes and methods + + public: + /** + * \brief define config type + * + * Define a Config type with the TemplateConfig. All driver implementations + * will then use the same variable type Config. + */ + typedef template_namespace::TemplateConfig Config; + + /** + * \brief config variable + * + * This variable has all the driver parameters defined in the cfg config file. + * Is updated everytime function config_update() is called. + */ + Config config_; + + /** + * \brief constructor + * + * In this constructor parameters related to the specific driver can be + * initalized. Those parameters can be also set in the openDriver() function. + * Attributes from the main node driver class IriBaseDriver such as loop_rate, + * may be also overload here. + */ + TemplateAlg(void); + + /** + * \brief Lock Algorithm + * + * Locks access to the Algorithm class + */ + void lock(void) { pthread_mutex_lock(&this->access_); }; + + /** + * \brief Unlock Algorithm + * + * Unlocks access to the Algorithm class + */ + void unlock(void) { pthread_mutex_unlock(&this->access_); }; + + /** + * \brief Tries Access to Algorithm + * + * Tries access to Algorithm + * + * \return true if the lock was adquired, false otherwise + */ + bool try_enter(void) + { + if(pthread_mutex_trylock(&this->access_)==0) + return true; + else + return false; + }; + + /** + * \brief config update + * + * In this function the driver parameters must be updated with the input + * config variable. Then the new configuration state will be stored in the + * Config attribute. + * + * \param new_cfg the new driver configuration state + * + * \param level level in which the update is taken place + */ + void config_update(Config& config, uint32_t level=0); + + // here define all template_alg interface methods to retrieve and set + // the driver parameters + + /** + * \brief Destructor + * + * This destructor is called when the object is about to be destroyed. + * + */ + ~TemplateAlg(void); +}; + +#endif diff --git a/algorithm_templates/template_alg_node.cpp b/algorithm_templates/template_alg_node.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9039a65396705644749a01ee9f3f4d6578a88a57 --- /dev/null +++ b/algorithm_templates/template_alg_node.cpp @@ -0,0 +1,61 @@ +#include "template_node.h" + +TemplateNode::TemplateNode(void) : + algorithm_base::IriBaseAlgorithm<TemplateAlg>() +{ + //init class attributes if necessary + //this->loop_rate_ = 2;//in [Hz] + + // [init publishers] + + // [init subscribers] + + // [init services] + + // [init clients] + + // [init action servers] + + // [init action clients] +} + +TemplateNode::~TemplateNode(void) +{ + // [free dynamic memory] +} + +void TemplateNode::mainNodeThread(void) +{ + // [fill msg structures] + + // [fill srv structure and make request to the server] + + // [fill action structure and make request to the action server] + + // [publish messages] +} + +/* [subscriber callbacks] */ + +/* [service callbacks] */ + +/* [action callbacks] */ + +/* [action requests] */ + +void TemplateNode::node_config_update(Config &config, uint32_t level) +{ + this->alg_.lock(); + this->config_=config; + this->alg_.unlock(); +} + +void TemplateNode::addNodeDiagnostics(void) +{ +} + +/* main function */ +int main(int argc,char *argv[]) +{ + return algorithm_base::main<TemplateNode>(argc, argv, "template_node"); +} diff --git a/algorithm_templates/template_alg_node.h b/algorithm_templates/template_alg_node.h new file mode 100644 index 0000000000000000000000000000000000000000..bfe0d9dc493c07d1ed64bb1756c290b359a1ef39 --- /dev/null +++ b/algorithm_templates/template_alg_node.h @@ -0,0 +1,122 @@ +// Copyright (C) 2010-2011 Institut de Robotica i Informatica Industrial, CSIC-UPC. +// Author +// All rights reserved. +// +// This file is part of iri-ros-pkg +// iri-ros-pkg is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// +// IMPORTANT NOTE: This code has been generated through a script from the +// iri_ros_scripts. Please do NOT delete any comments to guarantee the correctness +// of the scripts. ROS topics can be easly add by using those scripts. Please +// refer to the IRI wiki page for more information: +// http://wikiri.upc.es/index.php/Robotics_Lab + +#ifndef _template_node_h_ +#define _template_node_h_ + +#include <iri_base_algorithm/iri_base_algorithm.h> +#include "template_alg.h" + +// [publisher subscriber headers] + +// [service client headers] + +// [action server client headers] + +/** + * \brief IRI ROS Specific Algorithm Class + * + */ +class TemplateNode : public algorithm_base::IriBaseAlgorithm<TemplateAlg> +{ + private: + // [publisher attributes] + + // [subscriber attributes] + + // [service attributes] + + // [client attributes] + + // [action server attributes] + + // [action client attributes] + + /** + * \brief config variable + * + * This variable has all the driver parameters defined in the cfg config file. + * Is updated everytime function config_update() is called. + */ + Config config_; + public: + /** + * \brief Constructor + * + * This constructor initializes specific class attributes and all ROS + * communications variables to enable message exchange. + */ + TemplateNode(void); + + /** + * \brief Destructor + * + * This destructor frees all necessary dynamic memory allocated within this + * this class. + */ + ~TemplateNode(void); + + protected: + /** + * \brief main node thread + * + * This is the main thread node function. Code written here will be executed + * in every node loop while the algorithm is on running state. Loop frequency + * can be tuned by modifying loop_rate attribute. + * + * Here data related to the process loop or to ROS topics (mainly data structs + * related to the MSG and SRV files) must be updated. ROS publisher objects + * must publish their data in this process. ROS client servers may also + * request data to the corresponding server topics. + */ + void mainNodeThread(void); + + /** + * \brief dynamic reconfigure server callback + * + * This method is called whenever a new configuration is received through + * the dynamic reconfigure. The derivated generic algorithm class must + * implement it. + * + * \param config an object with new configuration from all algorithm + * parameters defined in the config file. + * \param level integer referring the level in which the configuration + * has been changed. + */ + void node_config_update(Config &config, uint32_t level); + + /** + * \brief node add diagnostics + * + * In this abstract function additional ROS diagnostics applied to the + * specific algorithms may be added. + */ + void addNodeDiagnostics(void); + + // [diagnostic functions] + + // [test functions] +}; + +#endif diff --git a/create_algorithm_package.sh b/create_algorithm_package.sh new file mode 100755 index 0000000000000000000000000000000000000000..2e477ffe15a9db754d5b7925d66bc9af30a92447 --- /dev/null +++ b/create_algorithm_package.sh @@ -0,0 +1,178 @@ +#!/bin/bash + +# WET + +# check wether the scripts path environment variable has been defined +scripts_path=`echo "${IRI_ROS_SCRIPTS_PATH}"` +if [[ -z "${scripts_path}" ]] +then + echo "The scripts path environment variable has not been defined. Please see the wiki documentation for instructions on how to create it." + exit +else + echo "The scripts path environment variable has been properly defined." +fi + +source "${IRI_ROS_SCRIPTS_PATH}/libraries/scripts_library.sh" + +check_libraries +check_templates + +echo "" +echo "/**********************************************/" +echo "/* Creating New IRI_ROS Simple Algorithm Node */" +echo "/**********************************************/" + +usage="Usage: create_algorithm_package.sh -n node_name [-i]\n +Parameters:\n +\t-i: avoid adding the iri_ prefix to the provided node name. By default it is always added." +input_name= +use_prefix=true + +#check for input project name paramenter +while getopts “:n:i†OPTION +do + case $OPTION in + n) + input_name=$OPTARG + ;; + i) + use_prefix=false + ;; + ?) + echo "invalid argument $OPTION" + kill_exit "${usage}" + ;; + esac +done + +#check if project parameter is filled up +if [ ! "${input_name}" ] +then + echo "No project name provided, aborting ..." + kill_exit "${usage}" +fi + +#lowercase input name +input_name=$(echo ${input_name} | tr "[:upper:]" "[:lower:]") + +#create alg filename +if [[ ${use_prefix} == true ]] +then + project_name="iri_${input_name}" +else + project_name="${input_name}" +fi + +if [ -e "../${project_name}" ] +then + kill_exit "${project_name} package directory already exists, aborting ..." +else + echo "Generating folder structure for project ${project_name} ..." +fi + +catkin_create_pkg ${project_name} iri_base_algorithm +if [ $? -eq 0 ] +then + echo "Package created successfully" +else + exit 1; +fi +#create alg filename +alg_filename="${input_name}_alg" + +#create node filename +node_filename="${input_name}_alg_node" + +#create cfg filename +cfg_filename="${input_name}_alg_config" + +#create basename from pkg name +create_basename ${input_name} + +#create templates folder path name +temps_folder="${IRI_ROS_SCRIPTS_PATH}/algorithm_templates/" + +################################################################################ +# create template alg .h and .cpp files + +#create alg basename +alg_basename="${basename}Algorithm" + +mkdir -p ${project_name}/include/ +mkdir -p ${project_name}/src/ + +#Set the filename and namespace on the template_alg files +sed -e "s/template_alg/${alg_filename}/g" \ + -e "s/TemplateAlg/${alg_basename}/g" \ + -e "s/template_namespace/${project_name}/g" \ + -e "s/TemplateConfig/${basename}Config/g" <${temps_folder}/template_alg.h >"${project_name}/include/${alg_filename}.h" +sed -e "s/template_alg/${alg_filename}/g" \ + -e "s/TemplateAlg/${alg_basename}/g" <${temps_folder}/template_alg.cpp >"${project_name}/src/${alg_filename}.cpp" +echo "Creating ${alg_filename} files..." +echo "" +################################################################################ + + + +################################################################################ +# create template node .h and .cpp files + +#create node basename +node_basename="${basename}AlgNode" +#echo "node_basename $node_basename" + +#Set the filename and namespace on the template_node files +sed -e "s/template_alg/${alg_filename}/g" \ + -e "s/TemplateAlg/${alg_basename}/g" \ + -e "s/template_node/${node_filename}/g" \ + -e "s/TemplateNode/${node_basename}/g" <${temps_folder}/template_alg_node.h >"${project_name}/include/${node_filename}.h" +sed -e "s/template_node/${node_filename}/g" \ + -e "s/TemplateAlg/${alg_basename}/g" \ + -e "s/TemplateNode/${node_basename}/g" <${temps_folder}/template_alg_node.cpp >"${project_name}/src/${node_filename}.cpp" +echo "Creating ${node_filename} files..." +echo "" +################################################################################ + + +################################################################################ +#Set the filename and namespace on the CMakeLists.txt file +sed -e "s/template_alg/${alg_filename}/g" \ + -e "s/Template/${basename}/g" \ + -e "s/template_node/${project_name}/g" <${temps_folder}/CMakeLists.txt >"${project_name}/CMakeLists.txt" +echo "Creating ${project_name} CMakeLists.txt file..." +echo "" +################################################################################ + + +################################################################################ +#create cfg directory +cfg_dir="${project_name}/cfg" +if [ -e "$cfg_dir" ] +then + echo "${cfg_dir} directory already exists, skipping ..." +else + echo "Creating ${cfg_dir} directory" + mkdir ${cfg_dir} +fi + +#Set the filename and namespace on the template.cfg file +sed -e "s/template/${project_name}/g" \ + -e "s/TemplateAlg/${alg_basename}/g" \ + -e "s/template_node/${node_filename}/g" \ + -e "s/Template/${basename}/g" <${temps_folder}/template_alg.cfg >"${project_name}/cfg/${basename}.cfg" +eval "chmod 775 ${project_name}/cfg/${basename}.cfg" +echo "Creating ${cfg_filename}.cfg file..." +################################################################################ + +echo "" +echo "" +echo "Project ${project_name} has been successfully created!!" + +pushd "${project_name}" +change_license_to_LGPL +popd + +# WET +goto_catkin_workspace +catkin_make --only-pkg-with-deps ${project_name} + diff --git a/create_driver_package.sh b/create_driver_package.sh index 87556afc31cb4737c8fc11595e9b8f66ce974f67..823902e5301ed16f340d1030f33fb6deeb6beca5 100755 --- a/create_driver_package.sh +++ b/create_driver_package.sh @@ -23,7 +23,9 @@ echo "/*********************************************/" echo "/* Creating New IRI_ROS Driver Node */" echo "/*********************************************/" -usage="Usage: ./create_driver_package.sh -n node_name [-i]" +usage="Usage: create_driver_package.sh -n node_name [-i] +Parameters:\n +\t-i: avoid adding the iri_ prefix to the provided node name. By default it is always added." input_name= use_prefix=true @@ -69,7 +71,13 @@ else echo "Generating folder structure for project ${project_name} ..." fi -catkin_create_pkg ${project_name} roscpp iri_base_driver +catkin_create_pkg ${project_name} iri_base_driver +if [ $? -eq 0 ] +then + echo "Package created successfully" +else + exit 1; +fi #create driver filename driver_filename="${input_name}_driver" @@ -93,6 +101,9 @@ create_basename ${input_name} driver_basename="${basename}Driver" #echo "driver_basename $driver_basename" +mkdir -p ${project_name}/include/ +mkdir -p ${project_name}/src/ + #Set the filename and namespace on the template_driver files sed -e "s/template_driver/${driver_filename}/g" \ -e "s/TemplateDriver/${driver_basename}/g" \ @@ -131,7 +142,8 @@ echo "" ################################################################################ #Set the filename and namespace on the CMakeLists.txt file sed -e "s/template_driver/${driver_filename}/g" \ - -e "s/template_node/${node_filename}/g" <${IRI_ROS_SCRIPTS_PATH}/driver_templates/CMakeLists.txt >"${project_name}/CMakeLists.txt" + -e "s/template_node/${project_name}/g" \ + -e "s/Template/${basename}/g" <${IRI_ROS_SCRIPTS_PATH}/driver_templates/CMakeLists.txt >"${project_name}/CMakeLists.txt" echo "Creating ${project_name} CMakeLists.txt file..." echo "" ################################################################################ @@ -153,9 +165,9 @@ sed -e "s/template_driver/${driver_filename}/g" \ -e "s/template/${project_name}/g" \ -e "s/TemplateDriver/${driver_basename}/g" \ -e "s/template_node/${node_filename}/g" \ - -e "s/Template/${basename}/g" <${IRI_ROS_SCRIPTS_PATH}/driver_templates/template_driver.cfg >"${project_name}/cfg/${cfg_filename}.cfg" -eval "chmod 775 ${project_name}/cfg/${cfg_filename}.cfg" -echo "Creating ${cfg_filename}.cfg file..." + -e "s/Template/${basename}/g" <${IRI_ROS_SCRIPTS_PATH}/driver_templates/template_driver.cfg >"${project_name}/cfg/${basename}.cfg" +eval "chmod 775 ${project_name}/cfg/${basename}.cfg" +echo "Creating ${basename}.cfg file..." ################################################################################ echo "" @@ -166,6 +178,5 @@ pushd "${project_name}" change_license_to_LGPL popd -cd .. # to catkin work space -catkin_make --pkg ${project_name} - +goto_catkin_workspace +catkin_make --only-pkg-with-deps ${project_name} diff --git a/driver_templates/CMakeLists.txt b/driver_templates/CMakeLists.txt index 36cb02a5f9159aeded08a73cc86693d8f87ce492..a5982ede66b7201ae7b8aa55856f1c7a89e50dc6 100644 --- a/driver_templates/CMakeLists.txt +++ b/driver_templates/CMakeLists.txt @@ -1,43 +1,100 @@ -cmake_minimum_required(VERSION 2.4.6) -include($ENV{ROS_ROOT}/core/rosbuild/rosbuild.cmake) +cmake_minimum_required(VERSION 2.8.3) +project(template_node) -set(PROJECT_NAME template_node) +## Find catkin macros and libraries +find_package(catkin REQUIRED) +# ******************************************************************** +# Add catkin additional components here +# ******************************************************************** +find_package(catkin REQUIRED COMPONENTS iri_base_driver) -# Set the build type. Options are: -# Coverage : w/ debug symbols, w/o optimization, w/ code-coverage -# Debug : w/ debug symbols, w/o optimization -# Release : w/o debug symbols, w/ optimization -# RelWithDebInfo : w/ debug symbols, w/ optimization -# MinSizeRel : w/o debug symbols, w/ optimization, stripped binaries -#set(ROS_BUILD_TYPE RelWithDebInfo) +## System dependencies are found with CMake's conventions +# find_package(Boost REQUIRED COMPONENTS system) -rosbuild_init() +# ******************************************************************** +# Add system and labrobotica dependencies here +# ******************************************************************** +# find_package(<dependency> REQUIRED) -#set the default path for built executables to the "bin" directory -set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin) -#set the default path for built libraries to the "lib" directory -set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib) +# ******************************************************************** +# Add topic, service and action definition here +# ******************************************************************** +## Generate messages in the 'msg' folder +# add_message_files( +# FILES +# Message1.msg +# Message2.msg +# ) -#uncomment if you have defined messages -#rosbuild_genmsg() -#uncomment if you have defined services -#rosbuild_gensrv() +## Generate services in the 'srv' folder +# add_service_files( +# FILES +# Service1.srv +# Service2.srv +# ) -# added to include support for dynamic reconfiguration -rosbuild_find_ros_package(dynamic_reconfigure) -include(${dynamic_reconfigure_PACKAGE_PATH}/cmake/cfgbuild.cmake) -gencfg() -# end dynamic reconfiguration +## Generate actions in the 'action' folder +# add_action_files( +# FILES +# Action1.action +# Action2.action +# ) -FIND_PACKAGE(iriutils REQUIRED) +## Generate added messages, services and actions with any dependencies listed here +# generate_messages( +# DEPENDENCIES +# std_msgs # Or other packages containing msgs +# ) -INCLUDE_DIRECTORIES(${iriutils_INCLUDE_DIR} ./include) +# ******************************************************************** +# Add the dynamic reconfigure file +# ******************************************************************** +generate_dynamic_reconfigure_options(cfg/Template.cfg) -#common commands for building c++ executables and libraries -#rosbuild_add_library(${PROJECT_NAME} src/example.cpp) -#target_link_libraries(${PROJECT_NAME} another_library) -#rosbuild_add_boost_directories() -#rosbuild_link_boost(${PROJECT_NAME} thread) -rosbuild_add_executable(${PROJECT_NAME} src/template_driver.cpp src/template_driver_node.cpp) +# ******************************************************************** +# Add run time dependencies here +# ******************************************************************** +catkin_package( +# INCLUDE_DIRS +# LIBRARIES +# ******************************************************************** +# Add ROS and IRI ROS run time dependencies +# ******************************************************************** + CATKIN_DEPENDS iri_base_driver +# ******************************************************************** +# Add system and labrobotica run time dependencies here +# ******************************************************************** +# DEPENDS +) -target_link_libraries(${PROJECT_NAME} ${iriutils_LIBRARY}) +########### +## Build ## +########### + +# ******************************************************************** +# Add the include directories +# ******************************************************************** +include_directories(include) +include_directories(${catkin_INCLUDE_DIRS}) +# include_directories(${<dependency>_INCLUDE_DIR}) + +## Declare a cpp library +# add_library(${PROJECT_NAME} <list of source files>) + +## Declare a cpp executable +add_executable(${PROJECT_NAME} src/template_driver.cpp src/template_driver_node.cpp) + +# ******************************************************************** +# Add the libraries +# ******************************************************************** +target_link_libraries(${PROJECT_NAME} ${catkin_LIBRARIES}) +# target_link_libraries(${PROJECT_NAME} ${<dependency>_LIBRARY}) + +# ******************************************************************** +# Add message headers dependencies +# ******************************************************************** +# add_dependencies(${PROJECT_NAME} <msg_package_name>_generate_messages_cpp) +# ******************************************************************** +# Add dynamic reconfigure dependencies +# ******************************************************************** +add_dependencies(${PROJECT_NAME} ${${PROJECT_NAME}_EXPORTED_TARGETS}) diff --git a/driver_templates/template_driver.cfg b/driver_templates/template_driver.cfg index 9c8408dcd6ca79a97261ec2b90f5c0c86566b99a..a6e770487e344f24f450b6b3fb1d3056cc64809e 100644 --- a/driver_templates/template_driver.cfg +++ b/driver_templates/template_driver.cfg @@ -32,10 +32,9 @@ # Author: PACKAGE='template' -import roslib; roslib.load_manifest(PACKAGE) from driver_base.msg import SensorLevels -from dynamic_reconfigure.parameter_generator import * +from dynamic_reconfigure.parameter_generator_catkin import * gen = ParameterGenerator() diff --git a/driver_templates/template_driver_node.cpp b/driver_templates/template_driver_node.cpp index 4b0b6d4dfcda17d50c4d1db25759a53cdb4c6863..5347b09267cd24e31ad538565d471d5fd6c9aed0 100644 --- a/driver_templates/template_driver_node.cpp +++ b/driver_templates/template_driver_node.cpp @@ -25,8 +25,6 @@ void TemplateNode::mainNodeThread(void) this->driver_.lock(); // [fill msg Header if necessary] - //<publisher_name>.header.stamp = ros::Time::now(); - //<publisher_name>.header.frame_id = "<publisher_topic_name>"; // [fill msg structures] diff --git a/libraries/create_action_client.sh b/libraries/create_action_client.sh index 823222be2b86290ff2b78e40e275dfc617b1e986..df3cf2f2298af09e6aedecb9428bc491613a017e 100644 --- a/libraries/create_action_client.sh +++ b/libraries/create_action_client.sh @@ -1,12 +1,10 @@ #!/bin/bash -# WET - # check wether the scripts path environment variable has been defined scripts_path=`echo "${IRI_ROS_SCRIPTS_PATH}"` if [[ -z "${scripts_path}" ]] then - echo "The scripts path environment varibale has not been defined. Please see the wiki documentation for instructions on how to create it." + echo "The scripts path environment variable has not been defined. Please see the wiki documentation for instructions on how to create it." exit else echo "The scripts path environment variable has been properly defined." @@ -14,133 +12,247 @@ fi source "${IRI_ROS_SCRIPTS_PATH}/libraries/scripts_library.sh" +function check_action_client_file_integrity +{ + local node_h=$1 + local node_c=$2 + local comment="" + + # check node.h file + comment="\[action server client headers\]" + find_comment_in_file "${comment}" "${node_h}" + if [[ "${comment_found}" = "false" ]] + then + kill_exit "Missing \[action server client headers\] from the header file ${node_h}" + fi + comment="\[action client attributes\]" + find_comment_in_file "${comment}" "${node_h}" + if [[ "${comment_found}" = "false" ]] + then + kill_exit "Missing \[action client attributes\] from the header file ${node_h}" + fi + + # check node.cpp file + comment="\[fill action structure and make request to the action server\]" + find_comment_in_file "${comment}" "${node_c}" + if [[ "${comment_found}" = "false" ]] + then + kill_exit "Missing \[fill action structure and make request to the action server\] from the source file ${node_c}" + fi + + comment="\[action callbacks\]" + find_comment_in_file "${comment}" "${node_c}" + if [[ "${comment_found}" = "false" ]] + then + kill_exit "Missing \[action callbacks\] from the source file ${node_c}" + fi + + comment="\[action requests\]" + find_comment_in_file "${comment}" "${node_c}" + if [[ "${comment_found}" = "false" ]] + then + kill_exit "Missing \[action requests\] from the source file ${node_c}" + fi +} + +function check_action_client_attributes_functions +{ + local action_file=$1 + local act_pkg=$2 + local node_h=$3 + local node_c=$4 + local client_name=$5 + local act_goal=$6 + local topic_name=$7 + local class_name=$8 + local aux_line="" + + # check the node.h file + aux_line="actionlib::SimpleActionClient<${act_pkg}::${action_file}Action> ${client_name};" + find_comment_in_file "${aux_line}" "${node_h}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "An ActionClient variable already exists with the same name in file ${node_h} line ${line_number}" + fi + + aux_line="${act_pkg}::${action_file}Goal ${act_goal};" + find_comment_in_file "${aux_line}" "${node_h}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "An ActionClient goal message variable already exists with the same name in file ${node_h} line ${line_number}" + fi + + aux_line="bool ${topic_name}MakeActionRequest();" + find_comment_in_file "${aux_line}" "${node_h}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "A MakeActionRequest function already exists with the same name in file ${node_h} line ${line_number}" + fi + + aux_line="void ${topic_name}Done(const actionlib::SimpleClientGoalState& state, const ${act_pkg}::${action_file}ResultConstPtr& result);" + find_comment_in_file "${aux_line}" "${node_h}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "A Done callback function already exists with the same name in file ${node_h} line ${line_number}" + fi + + aux_line="void ${topic_name}Active();" + find_comment_in_file "${aux_line}" "${node_h}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "An Active callback function already exists with the same name in file ${node_h} line ${line_number}" + fi + + aux_line="void ${topic_name}Feedback(const ${act_pkg}::${action_file}FeedbackConstPtr& feedback);" + find_comment_in_file "${aux_line}" "${node_h}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "A Feedback callback function already exists with the same name in file ${node_h} line ${line_number}" + fi + + # check the node.c file + aux_line="${client_name}(\"${topic_name}\", true)" + find_comment_in_file "${aux_line}" "${node_c}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "The constructor for the Action client is already called in file ${node_c} line ${line_number}" + fi + + aux_line="void ${class_name}::${topic_name}Done(const actionlib::SimpleClientGoalState& state, const ${act_pkg}::${action_file}ResultConstPtr& result)" + find_comment_in_file "${aux_line}" "${node_c}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "An implementation for the Done callback function is already present in file ${node_c} line ${line_number}" + fi + + aux_line="void ${class_name}::${topic_name}Active()" + find_comment_in_file "${aux_line}" "${node_c}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "An implementation for the Active callback function is already present in file ${node_c} line ${line_number}" + fi + + aux_line="void ${class_name}::${topic_name}Feedback(const ${act_pkg}::${action_file}FeedbackConstPtr& feedback)" + find_comment_in_file "${aux_line}" "${node_c}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "An implementation for the Feedback callback function is already present in file ${node_c} line ${line_number}" + fi + + aux_line="bool ${class_name}::${topic_name}MakeActionRequest()" + find_comment_in_file "${aux_line}" "${node_c}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "An implementation for the MakeActionRequest function is already present in file ${node_c} line ${line_number}" + fi +} + function create_action_client { -#read input params -local ros_pkg=$1 -local topic_name=$2 -local action_file=$3 -local act_pkg=$4 -local node_h=$5 -local node_c=$6 -local driver_alg=$7 -local client_name="${topic_name}_client_" -local act_goal="${topic_name}_goal_" - -#get class basename -get_class_basename "${node_c}" -if [[ -z ${class_name} ]] -then - kill_exit "impossible to retrieve class basename" -fi -# echo "class_name=${class_name}" + #read input params + local ros_pkg=$1 + local topic_name=$2 + local action_file=$3 + local act_pkg=$4 + local node_h=$5 + local node_c=$6 + local driver_alg=$7 + local client_name="${topic_name}_client_" + local act_goal="${topic_name}_goal_" + local line="" + local old_line="" + local comment="" + local old_string="" + local new_string="" + local add_char="" + + #get class basename + get_class_basename "${node_c}" + if [[ -z ${class_name} ]] + then + kill_exit "impossible to retrieve class basename" + fi + # echo "class_name=${class_name}" + + #check files integrity before making any changes + check_package_file_integrity "${driver_alg}" + check_cmakelists_file_integrity "${driver_alg}" + check_action_client_file_integrity "${node_h}" "${node_c}" + check_action_client_attributes_functions "${action_file}" "${act_pkg}" "${node_h}" "${node_c}" "${client_name}" "${act_goal}" "${topic_name}" "${class_name}" ################################################################################ -#modify manifest.xml +#modify package.xml -local actionlib_pkg="actionlib" -#look for actionlib dependency -find_comment_in_file "depend package=\"${actionlib_pkg}\"" "manifest.xml" + local actionlib_pkg="actionlib" -#add it if necessary -if [[ "${comment_found}" = "false" ]] -then - # add actionlib as dependency - add_pkg_to_manifest "${ros_pkg}" "${actionlib_pkg}" -fi + add_build_run_dependencies "${driver_alg}" "${ros_pkg}" "${actionlib_pkg}" + add_build_run_dependencies "${driver_alg}" "${ros_pkg}" "${act_pkg}" -################################################################################ -#modify Node.h +############################################################################### +#modify CMakeLists.txt -#look for include files and add them if are not already there -local line="#include <${act_pkg}/${action_file}Action.h>" -local comment="\[action server client headers\]" -add_line_to_file "${line}" "${comment}" "${node_h}" - -#look for include files and add them if are not already there -line="#include <actionlib/client/terminal_state.h>" -comment="\[action server client headers\]" -add_line_to_file "${line}" "${comment}" "${node_h}" - -#look for include files and add them if are not already there -line="#include <actionlib/client/simple_action_client.h>" -comment="\[action server client headers\]" -add_line_to_file "${line}" "${comment}" "${node_h}" - -#look if attribute is already defined in file -local aux_line="actionlib::SimpleActionClient<${act_pkg}::${action_file}Action> ${client_name};" -find_comment_in_file "${aux_line}" "${node_h}" -line="\ \ \ \ ${aux_line}\n" - -#look if attribute is already defined in file -aux_line="${act_pkg}::${action_file}Goal ${act_goal};" -find_comment_in_file "${aux_line}" "${node_h}" -line="${line}\ \ \ \ ${aux_line}\n" - -#look if attribute is already defined in file -aux_line="void ${topic_name}MakeActionRequest();" -find_comment_in_file "${aux_line}" "${node_h}" -line="${line}\ \ \ \ ${aux_line}\n" - -#look if attribute is already defined in file -aux_line="void ${topic_name}Done(const actionlib::SimpleClientGoalState& state, const ${act_pkg}::${action_file}ResultConstPtr& result);" -find_comment_in_file "${aux_line}" "${node_h}" -line="${line}\ \ \ \ ${aux_line}\n" - -#look if attribute is already defined in file -aux_line="void ${topic_name}Active();" -find_comment_in_file "${aux_line}" "${node_h}" -line="${line}\ \ \ \ ${aux_line}\n" - -#look if attribute is already defined in file -aux_line="void ${topic_name}Feedback(const ${act_pkg}::${action_file}FeedbackConstPtr& feedback);" -find_comment_in_file "${aux_line}" "${node_h}" -line="${line}\ \ \ \ ${aux_line}\n" - -#if no attribute was already there, add them all -if [[ "${comment_found}" = "false" ]] -then - comment="\[action client attributes\]" - add_line_to_file "${line}" "${comment}" "${node_h}" -else - kill_exit "Some attributes are already defined, please check your script input variables" -fi + old_line=$(grep "find_package(catkin REQUIRED COMPONENTS" "CMakeLists.txt") + if [[ $old_line == *${actionlib_pkg}* ]] + then + echo "Dependency already included in CMakeLists.txt file."; + else + if [[ "${driver_alg}" = "driver" ]] + then + old_string="iri_base_driver" + else + old_string="iri_base_algorithm" + fi + new_string="${old_string}\ ${actionlib_pkg}" + sed -i "s/${old_string}/${new_string}/g" "CMakeLists.txt" + fi + + add_cmake_dependencies "${driver_alg}" "${ros_pkg}" "${act_pkg}" ################################################################################ -#modify Node.cpp +#modify Node.h -#look if constructor is already defined in file -aux_line="${client_name}(\"${topic_name}\", true);" -find_comment_in_file "${aux_line}" "${node_c}" + #look for include files and add them if are not already there + line="#include <${act_pkg}/${action_file}Action.h>" + comment="\[action server client headers\]" + add_line_to_file "${line}" "${comment}" "${node_h}" -#look if callback is already defined in file -aux_line="void ${class_name}::${topic_name}Done(const actionlib::SimpleClientGoalState& state, const ${act_pkg}::${topic_name}ResultConstPtr& result)" -find_comment_in_file "${aux_line}" "${node_c}" + #look for include files and add them if are not already there + line="#include <actionlib/client/terminal_state.h>" + comment="\[action server client headers\]" + add_line_to_file "${line}" "${comment}" "${node_h}" -#look if callback is already defined in file -aux_line="void ${class_name}::${topic_name}Active()" -find_comment_in_file "${aux_line}" "${node_c}" + #look for include files and add them if are not already there + line="#include <actionlib/client/simple_action_client.h>" + comment="\[action server client headers\]" + add_line_to_file "${line}" "${comment}" "${node_h}" -#look if callback is already defined in file -aux_line="void ${class_name}::${topic_name}Feedback(const ${act_pkg}::${topic_name}FeedbackConstPtr& feedback)" -find_comment_in_file "${aux_line}" "${node_c}" + aux_line="actionlib::SimpleActionClient<${act_pkg}::${action_file}Action> ${client_name};" + line="\ \ \ \ ${aux_line}\n" + aux_line="${act_pkg}::${action_file}Goal ${act_goal};" + line="${line}\ \ \ \ ${aux_line}\n" + aux_line="bool ${topic_name}MakeActionRequest();" + line="${line}\ \ \ \ ${aux_line}\n" + aux_line="void ${topic_name}Done(const actionlib::SimpleClientGoalState& state, const ${act_pkg}::${action_file}ResultConstPtr& result);" + line="${line}\ \ \ \ ${aux_line}\n" + aux_line="void ${topic_name}Active();" + line="${line}\ \ \ \ ${aux_line}\n" + aux_line="void ${topic_name}Feedback(const ${act_pkg}::${action_file}FeedbackConstPtr& feedback);" + line="${line}\ \ \ \ ${aux_line}\n" + comment="\[action client attributes\]" + add_line_to_file "${line}" "${comment}" "${node_h}" -#look if callback is already defined in file -aux_line="void ${class_name}::${topic_name}MakeActionRequest()" -find_comment_in_file "${aux_line}" "${node_c}" +################################################################################ +#modify Node.cpp -#if no attribute was already there, add them all -if [[ "${comment_found}" = "false" ]] -then line="${client_name}(\"${topic_name}\", true)" -# comment="${class_name}::${class_name}(" -# sed -i "/${comment}/s|$|,|" "${node_c}" -# add_line_to_file "\ \ ${line}" "${comment}" "${node_c}" + # comment="${class_name}::${class_name}(" + # sed -i "/${comment}/s|$|,|" "${node_c}" + # add_line_to_file "\ \ ${line}" "${comment}" "${node_c}" #check if ':' are needed comment="${class_name}::${class_name}(" - local add_char=`grep "${comment}" "${node_c}" | grep " :"` + add_char=`grep "${comment}" "${node_c}" | grep " :"` if [[ -z ${add_char} ]] then sed -i "/${comment}/s|$| :|" "${node_c}" @@ -165,68 +277,176 @@ then fi fi - line="\ \ ${topic_name}MakeActionRequest();" + aux_line="\ \ // IMPORTANT: Please note that all mutex used in the client callback functions" + line="${aux_line}" + find_comment_in_file "${line}" "${node_c}" + if [[ "${comment_found}" = "false" ]] + then + aux_line="\ \ // must be unlocked before calling any of the client class functions from an" + line="${line}\n${aux_line}\n" + aux_line="\ \ // other thread (MainNodeThread)." + line="${line}${aux_line}\n" + comment="\[fill action structure and make request to the action server\]" + add_line_to_file "${line}" "${comment}" "${node_c}" + fi + + aux_line="\ \ // variable to hold the state of the current goal on the server" + line="${aux_line}\n" + aux_line="\ \ //actionlib::SimpleClientGoalState ${topic_name}_state(actionlib::SimpleClientGoalState::PENDING);" + line="${line}${aux_line}\n" + aux_line="\ \ // to get the state of the current goal" + line="${line}${aux_line}\n" + aux_line="\ \ //${driver_alg}_.unlock();" + line="${line}${aux_line}\n" + aux_line="\ \ //${topic_name}_state=${topic_name}_client_.getState();" + line="${line}${aux_line}\n" + aux_line="\ \ // Possible state values are: PENDING,ACTIVE,RECALLED,REJECTED,PREEMPTED,ABORTED,SUCCEEDED and LOST" + line="${line}${aux_line}\n" + aux_line="\ \ //${driver_alg}_.lock();" + line="${line}${aux_line}\n" + aux_line="\ \ //if(${topic_name}_state==actionlib::SimpleClientGoalState::ABORTED)" + line="${line}${aux_line}\n" + aux_line="\ \ //{" + line="${line}${aux_line}\n" + aux_line="\ \ // do something" + line="${line}${aux_line}\n" + aux_line="\ \ //}" + line="${line}${aux_line}\n" + aux_line="\ \ //else if(${topic_name}_state==actionlib::SimpleClientGoalState::SUCCEEDED)" + line="${line}${aux_line}\n" + aux_line="\ \ //{" + line="${line}${aux_line}\n" + aux_line="\ \ // do something else" + line="${line}${aux_line}\n" + aux_line="\ \ //}" + line="${line}${aux_line}\n" + aux_line="\ \ //${topic_name}MakeActionRequest();" + line="${line}${aux_line}\n" comment="\[fill action structure and make request to the action server\]" add_line_to_file "${line}" "${comment}" "${node_c}" - line="void ${class_name}::${topic_name}Done(const actionlib::SimpleClientGoalState& state, const ${act_pkg}::${action_file}ResultConstPtr& result) \\ -{ \\ -\ \ if( state.toString().compare(\"SUCCEEDED\") == 0 ) \\ -\ \ \ \ ROS_INFO(\"${class_name}::${topic_name}Done: Goal Achieved!\"); \\ -\ \ else \\ -\ \ \ \ ROS_INFO(\"${class_name}::${topic_name}Done: %s\", state.toString().c_str()); \\ -\\ -\ \ //copy & work with requested result \\ -} \\ -\\ -void ${class_name}::${topic_name}Active() \\ -{ \\ -\ \ //ROS_INFO(\"${class_name}::${topic_name}Active: Goal just went active!\"); \\ -} \\ -\\ -void ${class_name}::${topic_name}Feedback(const ${act_pkg}::${action_file}FeedbackConstPtr& feedback) \\ -{ \\ -\ \ //ROS_INFO(\"${class_name}::${topic_name}Feedback: Got Feedback!\"); \\ -\\ -\ \ bool feedback_is_ok = true; \\ -\\ -\ \ //analyze feedback \\ -\ \ //my_var = feedback->var; \\ -\\ -\ \ //if feedback is not what expected, cancel requested goal \\ -\ \ if( !feedback_is_ok ) \\ -\ \ { \\ -\ \ \ \ ${client_name}.cancelGoal(); \\ -\ \ \ \ //ROS_INFO(\"${class_name}::${topic_name}Feedback: Cancelling Action!\"); \\ -\ \ } \\ -}" + aux_line="void ${class_name}::${topic_name}Done(const actionlib::SimpleClientGoalState& state, const ${act_pkg}::${action_file}ResultConstPtr& result)" + line="${aux_line}\n" + aux_line="{" + line="${line}${aux_line}\n" + aux_line="\ \ ${driver_alg}_.lock();" + line="${line}${aux_line}\n" + aux_line="\ \ if( state == actionlib::SimpleClientGoalState::SUCCEEDED )" + line="${line}${aux_line}\n" + aux_line="\ \ \ \ ROS_INFO(\"${class_name}::${topic_name}Done: Goal Achieved!\");" + line="${line}${aux_line}\n" + aux_line="\ \ else" + line="${line}${aux_line}\n" + aux_line="\ \ \ \ ROS_INFO(\"${class_name}::${topic_name}Done: %s\", state.toString().c_str());" + line="${line}${aux_line}\n\n" + aux_line="\ \ //copy & work with requested result" + line="${line}${aux_line}\n" + aux_line="\ \ ${driver_alg}_.unlock();" + line="${line}${aux_line}\n" + aux_line="}" + line="${line}${aux_line}\n\n" + aux_line="void ${class_name}::${topic_name}Active()" + line="${line}${aux_line}\n" + aux_line="{" + line="${line}${aux_line}\n" + aux_line="\ \ ${driver_alg}_.lock();" + line="${line}${aux_line}\n" + aux_line="\ \ //ROS_INFO(\"${class_name}::${topic_name}Active: Goal just went active!\");" + line="${line}${aux_line}\n" + aux_line="\ \ ${driver_alg}_.unlock();" + line="${line}${aux_line}\n" + aux_line="}" + line="${line}${aux_line}\n\n" + aux_line="void ${class_name}::${topic_name}Feedback(const ${act_pkg}::${action_file}FeedbackConstPtr& feedback)" + line="${line}${aux_line}\n" + aux_line="{" + line="${line}${aux_line}\n" + aux_line="\ \ ${driver_alg}_.lock();" + line="${line}${aux_line}\n" + aux_line="\ \ //ROS_INFO(\"${class_name}::${topic_name}Feedback: Got Feedback!\");" + line="${line}${aux_line}\n\n" + aux_line="\ \ bool feedback_is_ok = true;" + line="${line}${aux_line}\n\n" + aux_line="\ \ //analyze feedback" + line="${line}${aux_line}\n" + aux_line="\ \ //my_var = feedback->var;" + line="${line}${aux_line}\n\n" + aux_line="\ \ //if feedback is not what expected, cancel requested goal" + line="${line}${aux_line}\n" + aux_line="\ \ if( !feedback_is_ok )" + line="${line}${aux_line}\n" + aux_line="\ \ {" + line="${line}${aux_line}\n" + aux_line="\ \ \ \ ${client_name}.cancelGoal();" + line="${line}${aux_line}\n" + aux_line="\ \ \ \ //ROS_INFO(\"${class_name}::${topic_name}Feedback: Cancelling Action!\");" + line="${line}${aux_line}\n" + aux_line="\ \ }" + line="${line}${aux_line}\n" + aux_line="\ \ ${driver_alg}_.unlock();" + line="${line}${aux_line}\n" + aux_line="}" + line="${line}${aux_line}\n" comment="\[action callbacks\]" add_line_to_file "${line}" "${comment}" "${node_c}" - line="void ${class_name}::${topic_name}MakeActionRequest() \\ -{ \\ -\ \ ROS_INFO(\"${class_name}::${topic_name}MakeActionRequest: Starting New Request!\"); \\ -\\ -\ \ //wait for the action server to start \\ -\ \ //will wait for infinite time \\ -\ \ ${client_name}.waitForServer(); \\ -\ \ ROS_INFO(\"${class_name}::${topic_name}MakeActionRequest: Server is Available!\"); \\ -\\ -\ \ //send a goal to the action \\ -\ \ //${act_goal}.data = my_desired_goal; \\ -\ \ ${client_name}.sendGoal(${act_goal}, \\ -\ \ \ \ \ \ \ \ \ \ \ \ \ \ boost::bind(&${class_name}::${topic_name}Done, this, _1, _2), \\ -\ \ \ \ \ \ \ \ \ \ \ \ \ \ boost::bind(&${class_name}::${topic_name}Active, this), \\ -\ \ \ \ \ \ \ \ \ \ \ \ \ \ boost::bind(&${class_name}::${topic_name}Feedback, this, _1)); \\ -\ \ ROS_INFO(\"${class_name}::${topic_name}MakeActionRequest: Goal Sent. Wait for Result!\"); \\ -}" + aux_line="bool ${class_name}::${topic_name}MakeActionRequest()" + line="${aux_line}\n" + aux_line="{" + line="${line}${aux_line}\n" + aux_line="\ \ // IMPORTANT: Please note that all mutex used in the client callback functions" + line="${line}${aux_line}\n" + aux_line="\ \ // must be unlocked before calling any of the client class functions from an" + line="${line}${aux_line}\n" + aux_line="\ \ // other thread (MainNodeThread)." + line="${line}${aux_line}\n" + aux_line="\ \ // this->${driver_alg}_.unlock();" + line="${line}${aux_line}\n" + aux_line="\ \ if(${client_name}.isServerConnected())" + line="${line}${aux_line}\n" + aux_line="\ \ {" + line="${line}${aux_line}\n" + aux_line="\ \ \ \ //ROS_DEBUG(\"${class_name}::${topic_name}MakeActionRequest: Server is Available!\");" + line="${line}${aux_line}\n" + aux_line="\ \ \ \ //send a goal to the action server" + line="${line}${aux_line}\n" + aux_line="\ \ \ \ //${act_goal}.data = my_desired_goal;" + line="${line}${aux_line}\n" + aux_line="\ \ \ \ ${client_name}.sendGoal(${act_goal}," + line="${line}${aux_line}\n" + aux_line="\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ boost::bind(&${class_name}::${topic_name}Done, this, _1, _2)," + line="${line}${aux_line}\n" + aux_line="\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ boost::bind(&${class_name}::${topic_name}Active, this)," + line="${line}${aux_line}\n" + aux_line="\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ boost::bind(&${class_name}::${topic_name}Feedback, this, _1));" + line="${line}${aux_line}\n" + aux_line="\ \ \ \ // this->${driver_alg}_.lock();" + line="${line}${aux_line}\n" + aux_line="\ \ \ \ // ROS_DEBUG(\"${class_name}::${topipc_name}MakeActionRequest: Goal Sent.\");" + line="${line}${aux_line}\n" + aux_line="\ \ \ \ return true;" + line="${line}${aux_line}\n" + aux_line="\ \ }" + line="${line}${aux_line}\n" + aux_line="\ \ else" + line="${line}${aux_line}\n" + aux_line="\ \ {" + line="${line}${aux_line}\n" + aux_line="\ \ \ \ // this->${driver_alg}_.lock();" + line="${line}${aux_line}\n" + aux_line="\ \ \ \ // ROS_DEBUG(\"${class_name}::${topic_name}MakeActionRequest: HRI server is not connected\");" + line="${line}${aux_line}\n" + aux_line="\ \ \ \ return false;" + line="${line}${aux_line}\n" + aux_line="\ \ }" + line="${line}${aux_line}\n" + aux_line="}" + line="${line}${aux_line}\n" comment="\[action requests\]" add_line_to_file "${line}" "${comment}" "${node_c}" -else - kill_exit "Some attributes are already defined, please check your script input variables" -fi - # ################################################################################ - +#compile + goto_catkin_workspace + catkin_make --only-pkg-with-deps ${ros_pkg} } diff --git a/libraries/create_action_server.sh b/libraries/create_action_server.sh index 7cbaccc78967d1d4d31d55920efcade35ca9c880..7005269cbf77fcbe94b43b481521d531ff955b11 100644 --- a/libraries/create_action_server.sh +++ b/libraries/create_action_server.sh @@ -1,7 +1,5 @@ #!/bin/bash -# WET - # check wether the scripts path environment variable has been defined scripts_path=`echo "${IRI_ROS_SCRIPTS_PATH}"` if [[ -z "${scripts_path}" ]] @@ -14,165 +12,340 @@ fi source "${IRI_ROS_SCRIPTS_PATH}/libraries/scripts_library.sh" -function create_action_server +function check_action_server_files_integrity { -#read input params -local ros_pkg=$1 -local topic_name=$2 -local action_file=$3 -local act_pkg=$4 -local node_h=$5 -local node_c=$6 -local driver_alg=$7 -local server_name="${topic_name}_aserver_" -local act_start="${topic_name}StartCallback" -local act_stop="${topic_name}StopCallback" -local act_finish="${topic_name}IsFinishedCallback" -local act_succeed="${topic_name}HasSucceedCallback" -local act_result="${topic_name}GetResultCallback" -local act_feedback="${topic_name}GetFeedbackCallback" - -#get class basename -get_class_basename "${node_c}" -if [[ -z ${class_name} ]] -then - kill_exit "impossible to retrieve class basename" -fi -# echo "class_name=${class_name}" + local node_h=$1 + local node_c=$2 + local comment="" + + # check the node.h file + comment="\[action server client headers\]" + find_comment_in_file "${comment}" "${node_h}" + if [[ "${comment_found}" = "false" ]] + then + kill_exit "Missing \[action server client headers\] from the header file ${node_h}" + fi + comment="\[action server attributes\]" + find_comment_in_file "${comment}" "${node_h}" + if [[ "${comment_found}" = "false" ]] + then + kill_exit "Missing \[action server attributes\] from the header file ${node_h}" + fi -################################################################################ -#modify manifest.xml + # check the node.cpp file + comment="\[init action servers\]" + find_comment_in_file "${comment}" "${node_c}" + if [[ "${comment_found}" = "false" ]] + then + kill_exit "Missing \[init action servers\] from the source file ${node_c}" + fi + comment="\[action callbacks\]" + find_comment_in_file "${comment}" "${node_c}" + if [[ "${comment_found}" = "false" ]] + then + kill_exit "Missing \[action callbacks\] from the source file ${node_c}" + fi + comment="\[fill action structure and make request to the action server\]" + find_comment_in_file "${comment}" "${node_c}" + if [[ "${comment_found}" = "false" ]] + then + kill_exit "Missing \[fill action structure and make request to the action server\] from the source file ${node_c}" + fi +} -local actionlib_pkg="iri_action_server" -#look for actionlib dependency -find_comment_in_file "depend package=\"${actionlib_pkg}\"" "manifest.xml" +function check_action_server_attributes_functions +{ + local action_file=$1 + local act_pkg=$2 + local node_h=$3 + local node_c=$4 + local server_name=$5 + local act_goal=$6 + local topic_name=$7 + local class_name=$8 + local act_start=$9 + local act_stop=${10} + local act_finish=${11} + local act_succeed=${12} + local act_result=${13} + local act_feedback=${14} + + local aux_line="" + + # check the node.h file + aux_line="IriActionServer<${act_pkg}::${action_file}Action> ${server_name};" + find_comment_in_file "${aux_line}" "${node_h}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "An ActionServer variable already exists with the same name in file ${node_h} line ${line_number}" + fi -#add it if necessary -if [[ "${comment_found}" = "false" ]] -then - # add actionlib as dependency - add_pkg_to_manifest "${ros_pkg}" "${actionlib_pkg}" -fi + aux_line="void ${act_start}(const ${act_pkg}::${action_file}GoalConstPtr& goal);" + find_comment_in_file "${aux_line}" "${node_h}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "A start callback function already exists with the same name in file ${node_h} line ${line_number}" + fi + aux_line="void ${act_stop}(void);" + find_comment_in_file "${aux_line}" "${node_h}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "A stop callback function already exists with the same name in file ${node_h} line ${line_number}" + fi -################################################################################ -#modify Node.h + aux_line="bool ${act_finish}(void);" + find_comment_in_file "${aux_line}" "${node_h}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "An is finished callback function already exists with the same name in file ${node_h} line ${line_number}" + fi -#look for include files and add them if are not already there -local line="#include <${act_pkg}/${action_file}Action.h>" -local comment="\[action server client headers\]" -add_line_to_file "${line}" "${comment}" "${node_h}" - -#look for include files and add them if are not already there -line="#include <iri_action_server/iri_action_server.h>" -comment="\[action server client headers\]" -add_line_to_file "${line}" "${comment}" "${node_h}" - -#look if attribute is already defined in file -local aux_line="IriActionServer<${act_pkg}::${action_file}Action> ${server_name};" -find_comment_in_file "${aux_line}" "${node_h}" -line="\ \ \ \ ${aux_line}\n" - -#look if attribute is already defined in file -aux_line="void ${act_start}(const ${act_pkg}::${action_file}GoalConstPtr& goal);" -find_comment_in_file "${aux_line}" "${node_h}" -line="${line}\ \ \ \ ${aux_line}\n" - -#look if attribute is already defined in file -aux_line="void ${act_stop}(void);" -find_comment_in_file "${aux_line}" "${node_h}" -line="${line}\ \ \ \ ${aux_line}\n" - -#look if attribute is already defined in file -aux_line="bool ${act_finish}(void);" -find_comment_in_file "${aux_line}" "${node_h}" -line="${line}\ \ \ \ ${aux_line}\n" - -#look if attribute is already defined in file -aux_line="bool ${act_succeed}(void);" -find_comment_in_file "${aux_line}" "${node_h}" -line="${line}\ \ \ \ ${aux_line}\n" - -#look if attribute is already defined in file -aux_line="void ${act_result}(${act_pkg}::${action_file}ResultPtr& result);" -find_comment_in_file "${aux_line}" "${node_h}" -line="${line}\ \ \ \ ${aux_line}\n" - -#look if attribute is already defined in file -aux_line="void ${act_feedback}(${act_pkg}::${action_file}FeedbackPtr& feedback);" -find_comment_in_file "${aux_line}" "${node_h}" -line="${line}\ \ \ \ ${aux_line}" - -#if no attribute was already there, add them all -if [[ "${comment_found}" = "false" ]] -then - comment="\[action server attributes\]" - add_line_to_file "${line}" "${comment}" "${node_h}" -else - kill_exit "Some attributes are already defined, please check your script input variables" -fi + aux_line="bool ${act_succeed}(void);" + find_comment_in_file "${aux_line}" "${node_h}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "A has succeeded callback function already exists with the same name in file ${node_h} line ${line_number}" + fi -################################################################################ -#modify Node.cpp + aux_line="void ${act_result}(${act_pkg}::${action_file}ResultPtr& result);" + find_comment_in_file "${aux_line}" "${node_h}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "A get result callback function already exists with the same name in file ${node_h} line ${line_number}" + fi + + aux_line="void ${act_feedback}(${act_pkg}::${action_file}FeedbackPtr& feedback);" + find_comment_in_file "${aux_line}" "${node_h}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "A get feedback callback function already exists with the same name in file ${node_h} line ${line_number}" + fi + aux_line="bool ${topic_name}_active;" + find_comment_in_file "${aux_line}" "${node_h}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "An active boolean already exists with the same name in file ${node_h} line ${line_number}" + fi + aux_line="bool ${topic_name}_succeeded;" + find_comment_in_file "${aux_line}" "${node_h}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "A success boolean already exists with the same name in file ${node_h} line ${line_number}" + fi + aux_line="bool ${topic_name}_finished;" + find_comment_in_file "${aux_line}" "${node_h}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "A finished boolean already exists with the same name in file ${node_h} line ${line_number}" + fi + + # check the node.cpp file + aux_line="${server_name}(public_node_handle_, \"${topic_name}\")" + find_comment_in_file "${aux_line}" "${node_c}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "The constructor for the Action server is already called in file ${node_c} line ${line_number}" + fi + + aux_line="${server_name}.registerStartCallback" + find_comment_in_file "${aux_line}" "${node_c}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "The registration of the start callback function is already present in file ${node_c} line ${line_number}" + fi + + aux_line="${server_name}.registerStopCallback" + find_comment_in_file "${aux_line}" "${node_c}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "The registration of the stop callback function is already present in file ${node_c} line ${line_number}" + fi + + aux_line="${server_name}.registerIsFinishedCallback" + find_comment_in_file "${aux_line}" "${node_c}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "The registration of the is finished callback function is already present in file ${node_c} line ${line_number}" + fi -#look if constructor is already defined in file -line="${server_name}(this->public_node_handle_, \"${topic_name}\")" -find_comment_in_file "${line}" "${node_c}" + aux_line="${server_name}.registerHasSucceedCallback" + find_comment_in_file "${aux_line}" "${node_c}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "The registration of the has succeeded callback function is already present in file ${node_c} line ${line_number}" + fi -#look if callback is already defined in file -line="${server_name}.registerStartCallback;" -find_comment_in_file "${line}" "${node_c}" + aux_line="${server_name}.registerGetResultCallback" + find_comment_in_file "${aux_line}" "${node_c}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "The registration of the get result callback function is already present in file ${node_c} line ${line_number}" + fi -#look if callback is already defined in file -line="${server_name}.registerStopCallback;" -find_comment_in_file "${line}" "${node_c}" + aux_line="${server_name}.registerGetFeedbackCallback" + find_comment_in_file "${aux_line}" "${node_c}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "The registration of the get feedback callback function is already present in file ${node_c} line ${line_number}" + fi -#look if callback is already defined in file -line="${server_name}.registerIsFinishedCallback;" -find_comment_in_file "${line}" "${node_c}" + aux_line="${server_name}.start();" + find_comment_in_file "${aux_line}" "${node_c}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "The activation of the action server is already done in file ${node_c} line ${line_number}" + fi -#look if callback is already defined in file -line="${server_name}.registerHasSucceedCallback;" -find_comment_in_file "${line}" "${node_c}" + line="void ${class_name}::${act_start}(const ${act_pkg}::${action_file}GoalConstPtr& goal)" + find_comment_in_file "${line}" "${node_c}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "The implementation of the start callback function is already present in file ${node_c} line ${line_number}" + fi -#look if callback is already defined in file -line="${server_name}.registerGetResultCallback;" -find_comment_in_file "${line}" "${node_c}" + line="void ${class_name}::${act_stop}(void)" + find_comment_in_file "${line}" "${node_c}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "The implementation of the stop callback function is already present in file ${node_c} line ${line_number}" + fi -#look if callback is already defined in file -line="${server_name}.registerGetFeedbackCallback;" -find_comment_in_file "${line}" "${node_c}" + line="bool ${class_name}::${act_finish}(void)" + find_comment_in_file "${line}" "${node_c}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "The implementation of the is finished callback function is already present in file ${node_c} line ${line_number}" + fi -line="${server_name}.start();" -find_comment_in_file "${line}" "${node_c}" + line="bool ${class_name}::${act_succeed}(void)" + find_comment_in_file "${line}" "${node_c}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "The implementation of the has succeeded callback function is already present in file ${node_c} line ${line_number}" + fi -aux_line="void ${act_start}(const ${act_pkg}::${action_file}GoalConstPtr& goal)" -find_comment_in_file "${line}" "${node_c}" + line="void ${class_name}::${act_result}(${act_pkg}::${action_file}ResultPtr& result)" + find_comment_in_file "${line}" "${node_c}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "The implementation of the get result callback function is already present in file ${node_c} line ${line_number}" + fi -aux_line="void ${act_stop}(void)" -find_comment_in_file "${line}" "${node_c}" + line="void ${class_name}::${act_feedback}(${act_pkg}::${action_file}FeedbackPtr& feedback)" + find_comment_in_file "${line}" "${node_c}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "The implementation of the get feedback callback function is already present in file ${node_c} line ${line_number}" + fi -aux_line="bool ${act_finish}(void)" -find_comment_in_file "${line}" "${node_c}" + aux_line="this->${topic_name}_active=false;" + find_comment_in_file "${aux_line}" "${node_c}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "The active variable of the action server is already initialized in file ${node_c} line ${line_number}" + fi -aux_line="bool ${act_succeed}(void)" -find_comment_in_file "${line}" "${node_c}" + aux_line="this->${topic_name}_succeeded=false;" + find_comment_in_file "${aux_line}" "${node_c}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "The success variable of the action server is already initialized in file ${node_c} line ${line_number}" + fi -aux_line="void ${act_result}(${act_pkg}::${action_file}ResultPtr& result)" -find_comment_in_file "${line}" "${node_c}" + aux_line="this->${topic_name}_finished=false;" + find_comment_in_file "${aux_line}" "${node_c}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "The finished variable of the action server is already initialized in file ${node_c} line ${line_number}" + fi -aux_line="void ${act_feedback}(${act_pkg}::${action_file}FeedbackPtr& feedback)" -find_comment_in_file "${line}" "${node_c}" +} +function create_action_server +{ + #read input params + local ros_pkg=$1 + local topic_name=$2 + local action_file=$3 + local act_pkg=$4 + local node_h=$5 + local node_c=$6 + local driver_alg=$7 + local server_name="${topic_name}_aserver_" + local act_start="${topic_name}StartCallback" + local act_stop="${topic_name}StopCallback" + local act_finish="${topic_name}IsFinishedCallback" + local act_succeed="${topic_name}HasSucceededCallback" + local act_result="${topic_name}GetResultCallback" + local act_feedback="${topic_name}GetFeedbackCallback" + local line="" + local old_line="" + local comment="" + local aux_line="" + local add_char="" + local new_string="" + local old_string="" + + #get class basename + get_class_basename "${node_c}" + if [[ -z ${class_name} ]] + then + kill_exit "impossible to retrieve class basename" + fi + # echo "class_name=${class_name}" + + #check files integrity before making any changes + check_package_file_integrity "${driver_alg}" + check_cmakelists_file_integrity "${driver_alg}" + check_action_server_files_integrity "${node_h}" "${node_c}" + check_action_server_attributes_functions "${action_file}" "${act_pkg}" "${node_h}" "${node_c}" "${server_name}" "${act_goal}" "${topic_name}" "${class_name}" "${act_start}" "${act_stop}" "${act_finish}" "${act_succeed}" "${act_result}" "${act_feedback}" + +################################################################################ +#modify Node.h + + #look for include files and add them if are not already there + line="#include <${act_pkg}/${action_file}Action.h>" + comment="\[action server client headers\]" + add_line_to_file "${line}" "${comment}" "${node_h}" + + #look for include files and add them if are not already there + line="#include <iri_action_server/iri_action_server.h>" + comment="\[action server client headers\]" + add_line_to_file "${line}" "${comment}" "${node_h}" + + aux_line="IriActionServer<${act_pkg}::${action_file}Action> ${server_name};" + line="\ \ \ \ ${aux_line}\n" + aux_line="void ${act_start}(const ${act_pkg}::${action_file}GoalConstPtr& goal);" + line="${line}\ \ \ \ ${aux_line}\n" + aux_line="void ${act_stop}(void);" + line="${line}\ \ \ \ ${aux_line}\n" + aux_line="bool ${act_finish}(void);" + line="${line}\ \ \ \ ${aux_line}\n" + aux_line="bool ${act_succeed}(void);" + line="${line}\ \ \ \ ${aux_line}\n" + aux_line="void ${act_result}(${act_pkg}::${action_file}ResultPtr& result);" + line="${line}\ \ \ \ ${aux_line}\n" + aux_line="void ${act_feedback}(${act_pkg}::${action_file}FeedbackPtr& feedback);" + line="${line}\ \ \ \ ${aux_line}\n" + aux_line="bool ${topic_name}_active;" + line="${line}\ \ \ \ ${aux_line}\n" + aux_line="bool ${topic_name}_succeeded;" + line="${line}\ \ \ \ ${aux_line}\n" + aux_line="bool ${topic_name}_finished;" + line="${line}\ \ \ \ ${aux_line}\n" + + comment="\[action server attributes\]" + add_line_to_file "${line}" "${comment}" "${node_h}" + +################################################################################ +#modify Node.cpp -#if no attribute was already there, add them all -if [[ "${comment_found}" = "false" ]] -then line="${server_name}(public_node_handle_, \"${topic_name}\")" #check if ':' are needed comment="${class_name}::${class_name}(" - local add_char=`grep "${comment}" "${node_c}" | grep " :"` + add_char=`grep "${comment}" "${node_c}" | grep " :"` if [[ -z ${add_char} ]] then sed -i "/${comment}/s|$| :|" "${node_c}" @@ -197,79 +370,190 @@ then fi fi - line="${server_name}.registerStartCallback(boost::bind(&${class_name}::${act_start}, this, _1)); \\ -\ \ ${server_name}.registerStopCallback(boost::bind(&${class_name}::${act_stop}, this)); \\ -\ \ ${server_name}.registerIsFinishedCallback(boost::bind(&${class_name}::${act_finish}, this)); \\ -\ \ ${server_name}.registerHasSucceedCallback(boost::bind(&${class_name}::${act_succeed}, this)); \\ -\ \ ${server_name}.registerGetResultCallback(boost::bind(&${class_name}::${act_result}, this, _1)); \\ -\ \ ${server_name}.registerGetFeedbackCallback(boost::bind(&${class_name}::${act_feedback}, this, _1)); \\ -\ \ ${server_name}.start();" + aux_line="\ \ // IMPORTANT: it is better to use the boolean variables to control the" + line="${aux_line}\n" + find_comment_in_file "${line}" "${node_c}" + if [[ "${comment_found}" = "false" ]] + then + aux_line="\ \ // behavior of the action server instead of direclty calling the action server" + line="${line}${aux_line}\n" + aux_line="\ \ // class functions." + line="${line}${aux_line}\n" + comment="\[fill action structure and make request to the action server\]" + add_line_to_file "${line}" "${comment}" "${node_c}" + fi + + aux_line="\ \ // To finish the action server with success" + line="${aux_line}\n" + aux_line="\ \ //this->${topic_name}_succeeded=true;" + line="${line}${aux_line}\n" + aux_line="\ \ //this->${topic_name}_finished=true;" + line="${line}${aux_line}\n" + aux_line="\ \ // To finish the action server with failure" + line="${line}${aux_line}\n" + aux_line="\ \ //this->${topic_name}_succeeded=false;" + line="${line}${aux_line}\n" + aux_line="\ \ //this->${topic_name}_finished=true;" + line="${line}${aux_line}\n" + comment="\[fill action structure and make request to the action server\]" + add_line_to_file "${line}" "${comment}" "${node_c}" + + aux_line="${server_name}.registerStartCallback(boost::bind(&${class_name}::${act_start}, this, _1));" + line="${aux_line}\n" + aux_line="\ \ ${server_name}.registerStopCallback(boost::bind(&${class_name}::${act_stop}, this));" + line="${line}${aux_line}\n" + aux_line="\ \ ${server_name}.registerIsFinishedCallback(boost::bind(&${class_name}::${act_finish}, this));" + line="${line}${aux_line}\n" + aux_line="\ \ ${server_name}.registerHasSucceedCallback(boost::bind(&${class_name}::${act_succeed}, this));" + line="${line}${aux_line}\n" + aux_line="\ \ ${server_name}.registerGetResultCallback(boost::bind(&${class_name}::${act_result}, this, _1));" + line="${line}${aux_line}\n" + aux_line="\ \ ${server_name}.registerGetFeedbackCallback(boost::bind(&${class_name}::${act_feedback}, this, _1));" + line="${line}${aux_line}\n" + aux_line="\ \ ${server_name}.start();" + line="${line}${aux_line}\n" + aux_line="\ \ this->${topic_name}_active=false;" + line="${line}${aux_line}\n" + aux_line="\ \ this->${topic_name}_succeeded=false;" + line="${line}${aux_line}\n" + aux_line="\ \ this->${topic_name}_finished=false;" + line="${line}${aux_line}\n" comment="\[init action servers\]" add_line_to_file "\ \ ${line}" "${comment}" "${node_c}" - line="void ${class_name}::${act_start}(const ${act_pkg}::${action_file}GoalConstPtr& goal)\\ -{ \\ -\ \ ${driver_alg}_.lock(); \\ -\ \ \ \ //check goal \\ -\ \ \ \ //execute goal \\ -\ \ ${driver_alg}_.unlock(); \\ -} \\ -\\ -void ${class_name}::${act_stop}(void) \\ -{ \\ -\ \ ${driver_alg}_.lock(); \\ -\ \ \ \ //stop action \\ -\ \ ${driver_alg}_.unlock(); \\ -} \\ -\\ -bool ${class_name}::${act_finish}(void) \\ -{ \\ -\ \ bool ret = false; \\ -\\ -\ \ ${driver_alg}_.lock(); \\ -\ \ \ \ //if action has finish for any reason \\ -\ \ \ \ //ret = true; \\ -\ \ ${driver_alg}_.unlock(); \\ -\\ -\ \ return ret; \\ -} \\ -\\ -bool ${class_name}::${act_succeed}(void) \\ -{ \\ -\ \ bool ret = false; \\ -\\ -\ \ ${driver_alg}_.lock(); \\ -\ \ \ \ //if goal was accomplished \\ -\ \ \ \ //ret = true; \\ -\ \ ${driver_alg}_.unlock(); \\ -\\ -\ \ return ret; \\ -} \\ -\\ -void ${class_name}::${act_result}(${act_pkg}::${action_file}ResultPtr& result) \\ -{ \\ -\ \ ${driver_alg}_.lock(); \\ -\ \ \ \ //update result data to be sent to client \\ -\ \ \ \ //result->data = data; \\ -\ \ ${driver_alg}_.unlock(); \\ -} \\ -\\ -void ${class_name}::${act_feedback}(${act_pkg}::${action_file}FeedbackPtr& feedback) \\ -{ \\ -\ \ ${driver_alg}_.lock(); \\ -\ \ \ \ //keep track of feedback \\ -\ \ \ \ //ROS_INFO(\"feedback: %s\", feedback->data.c_str()); \\ -\ \ ${driver_alg}_.unlock(); \\ -}" + aux_line="void ${class_name}::${act_start}(const ${act_pkg}::${action_file}GoalConstPtr& goal)" + line="${aux_line}\n" + aux_line="{" + line="${line}${aux_line}\n" + aux_line="\ \ this->${driver_alg}_.lock();" + line="${line}${aux_line}\n" + aux_line="\ \ //check goal" + line="${line}${aux_line}\n" + aux_line="\ \ this->${topic_name}_active=true;" + line="${line}${aux_line}\n" + aux_line="\ \ this->${topic_name}_succeeded=false;" + line="${line}${aux_line}\n" + aux_line="\ \ this->${topic_name}_finished=false;" + line="${line}${aux_line}\n" + aux_line="\ \ //execute goal" + line="${line}${aux_line}\n" + aux_line="\ \ this->${driver_alg}_.unlock();" + line="${line}${aux_line}\n" + aux_line="}" + line="${line}${aux_line}\n\n" + aux_line="void ${class_name}::${act_stop}(void)" + line="${line}${aux_line}\n" + aux_line="{" + line="${line}${aux_line}\n" + aux_line="\ \ this->${driver_alg}_.lock();" + line="${line}${aux_line}\n" + aux_line="\ \ //stop action" + line="${line}${aux_line}\n" + aux_line="\ \ this->${topic_name}_active=false;" + line="${line}${aux_line}\n" + aux_line="\ \ this->${driver_alg}_.unlock();" + line="${line}${aux_line}\n" + aux_line="}" + line="${line}${aux_line}\n\n" + aux_line="bool ${class_name}::${act_finish}(void)" + line="${line}${aux_line}\n" + aux_line="{" + line="${line}${aux_line}\n" + aux_line="\ \ bool ret = false;" + line="${line}${aux_line}\n\n" + aux_line="\ \ this->${driver_alg}_.lock();" + line="${line}${aux_line}\n" + aux_line="\ \ //if action has finish for any reason" + line="${line}${aux_line}\n" + aux_line="\ \ ret = this->${topic_name}_finished;" + line="${line}${aux_line}\n" + aux_line="\ \ this->${driver_alg}_.unlock();" + line="${line}${aux_line}\n\n" + aux_line="\ \ return ret;" + line="${line}${aux_line}\n" + aux_line="}" + line="${line}${aux_line}\n\n" + aux_line="bool ${class_name}::${act_succeed}(void)" + line="${line}${aux_line}\n" + aux_line="{" + line="${line}${aux_line}\n" + aux_line="\ \ bool ret = false;" + line="${line}${aux_line}\n\n" + aux_line="\ \ this->${driver_alg}_.lock();" + line="${line}${aux_line}\n" + aux_line="\ \ //if goal was accomplished" + line="${line}${aux_line}\n" + aux_line="\ \ ret = this->${topic_name}_succeeded;" + line="${line}${aux_line}\n" + aux_line="\ \ this->${topic_name}_active=false;" + line="${line}${aux_line}\n" + aux_line="\ \ this->${driver_alg}_.unlock();" + line="${line}${aux_line}\n\n" + aux_line="\ \ return ret;" + line="${line}${aux_line}\n" + aux_line="}" + line="${line}${aux_line}\n\n" + aux_line="void ${class_name}::${act_result}(${act_pkg}::${action_file}ResultPtr& result)" + line="${line}${aux_line}\n" + aux_line="{" + line="${line}${aux_line}\n" + aux_line="\ \ this->${driver_alg}_.lock();" + line="${line}${aux_line}\n" + aux_line="\ \ //update result data to be sent to client" + line="${line}${aux_line}\n" + aux_line="\ \ //result->data = data;" + line="${line}${aux_line}\n" + aux_line="\ \ this->${driver_alg}_.unlock();" + line="${line}${aux_line}\n" + aux_line="}" + line="${line}${aux_line}\n\n" + aux_line="void ${class_name}::${act_feedback}(${act_pkg}::${action_file}FeedbackPtr& feedback)" + line="${line}${aux_line}\n" + aux_line="{" + line="${line}${aux_line}\n" + aux_line="\ \ this->${driver_alg}_.lock();" + line="${line}${aux_line}\n" + aux_line="\ \ //update feedback data to be sent to client" + line="${line}${aux_line}\n" + aux_line="\ \ //ROS_INFO(\"feedback: %s\", feedback->data.c_str());" + line="${line}${aux_line}\n" + aux_line="\ \ this->${driver_alg}_.unlock();" + line="${line}${aux_line}\n" + aux_line="}" + line="${line}${aux_line}\n" comment="\[action callbacks\]" add_line_to_file "${line}" "${comment}" "${node_c}" -else - kill_exit "Some attributes are already defined, please check your script input variables" -fi +################################################################################ +# Modify package.xml +# check if the message package is the current ros package + add_build_run_dependencies "${driver_alg}" "${ros_pkg}" "${act_pkg}" + add_build_run_dependencies "${driver_alg}" "${ros_pkg}" "iri_action_server" ################################################################################ +# modify the CMakeLists.txt file +# check if the message package is the current ros package + add_cmake_dependencies "${driver_alg}" "${ros_pkg}" "${act_pkg}" + # check if the base iri_action server dependency is included + if [[ $old_line == *iri_action_server* ]] + then + echo "iri_action_sever dependency already included in CMakeLists.txt file."; + else + if [[ "${driver_alg}" = "driver" ]] + then + old_string="iri_base_driver" + else + old_string="iri_base_algorithm" + fi + new_string="${old_string}\ iri_action_server" + sed -i "s/${old_string}/${new_string}/g" "CMakeLists.txt" + fi + +################################################################################ +#compile + goto_catkin_workspace + catkin_make --only-pkg-with-deps ${ros_pkg} } diff --git a/libraries/create_client.sh b/libraries/create_client.sh index cbe85012f96ccc93c40959ec865867abed576a90..1ebb01723883d4db9c713a96bb013d9ac4125861 100755 --- a/libraries/create_client.sh +++ b/libraries/create_client.sh @@ -1,7 +1,5 @@ #!/bin/bash -# WET - # check wether the scripts path environment variable has been defined scripts_path=`echo "${IRI_ROS_SCRIPTS_PATH}"` if [[ -z "${scripts_path}" ]] @@ -14,90 +12,168 @@ fi source "${IRI_ROS_SCRIPTS_PATH}/libraries/scripts_library.sh" +function check_client_file_integrity +{ + local node_h=$1 + local node_c=$2 + local comment="" + + # check the node.h file + comment="\[service client headers\]" + find_comment_in_file "${comment}" "${node_h}" + if [[ "${comment_found}" = "false" ]] + then + kill_exit "Missing \[service client headers\] from the header file ${node_h}" + fi + comment="\[client attributes\]" + find_comment_in_file "${comment}" "${node_h}" + if [[ "${comment_found}" = "false" ]] + then + kill_exit "Missing \[client attributes\] from the header file ${node_h}" + fi + # chekc the node.cpp file + comment="\[init clients\]" + find_comment_in_file "${comment}" "${node_c}" + if [[ "${comment_found}" = "false" ]] + then + kill_exit "Missing \[init clients\] from the header file ${node_c}" + fi + comment="\[fill srv structure and make request to the server\]" + find_comment_in_file "${comment}" "${node_c}" + if [[ "${comment_found}" = "false" ]] + then + kill_exit "Missing \[fill srv structure and make request to the server\] from the header file ${node_c}" + fi +} + +function check_client_attributes_functions +{ + local node_h=$1 + local node_c=$2 + local client_name=$3 + local srv_pkg=$4 + local srv_file=$5 + local topic_name=$6 + local line="" + + # check the node.h file + line="ros::ServiceClient ${client_name};" + find_comment_in_file "${line}" "${node_h}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "A service client with the same name is already declared in file ${node_h} line ${line_number}" + fi + line="${srv_pkg}::${srv_file} ${topic_name}_srv_;" + find_comment_in_file "${line}" "${node_h}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "A service message with the same name is already declared in file ${node_h} line ${line_number}" + fi + + # check the node.cpp file + line="${client_name} = this->public_node_handle_.serviceClient<${srv_pkg}::${srv_file}>(\"${topic_name}\");" + echo "${line}" + find_comment_in_file "${line}" "${node_c}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "A service client with the same name is already initialized in file ${node_c} line ${line_number}" + fi + line="if (${client_name}.call(${topic_name}_srv_))" + find_comment_in_file "${line}" "${node_c}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "A service with the same name is already called in file ${node_c} line ${line_number}" + fi +} + function create_client { -#read input params -local ros_pkg=$1 -local topic_name=$2 -local srv_file=$3 -local srv_pkg=$4 -local node_h=$5 -local node_c=$6 -local driver_alg=$7 -local client_name="${topic_name}_client_" - -#get class basename -get_class_basename "${node_c}" -if [[ -z ${class_name} ]] -then - kill_exit "impossible to retrieve class basename" -fi + #read input params + local ros_pkg=$1 + local topic_name=$2 + local srv_file=$3 + local srv_pkg=$4 + local node_h=$5 + local node_c=$6 + local driver_alg=$7 + local client_name="${topic_name}_client_" + local line="" + local aux_line="" + local comment="" + + #get class basename + get_class_basename "${node_c}" + if [[ -z ${class_name} ]] + then + kill_exit "impossible to retrieve class basename" + fi # echo "class_name=${class_name}" + #check files integrity before making any changes + check_package_file_integrity "${driver_alg}" + check_cmakelists_file_integrity "${driver_alg}" + check_client_file_integrity "${node_h}" "${node_c}" + check_client_attributes_functions "${node_h}" "${node_c}" "${client_name}" "${srv_pkg}" "${srv_file}" "${topic_name}" + ################################################################################ #modify Node.h -#look for include files and add them if are not already there -local line="#include <${srv_pkg}/${srv_file}.h>" -local comment="\[service client headers\]" -add_line_to_file "${line}" "${comment}" "${node_h}" - -#look if attribute is already defined in file -local aux_line="ros::ServiceClient ${client_name};" -find_comment_in_file "${aux_line}" "${node_h}" -line="\ \ \ \ ${aux_line}\n" + #look for include files and add them if are not already there + line="#include <${srv_pkg}/${srv_file}.h>" + comment="\[service client headers\]" + add_line_to_file "${line}" "${comment}" "${node_h}" -#look if attribute is already defined in file -aux_line="${srv_pkg}::${srv_file} ${topic_name}_srv_;" -find_comment_in_file "${aux_line}" "${node_h}" -line="${line}\ \ \ \ ${aux_line}" + aux_line="ros::ServiceClient ${client_name};" + line="\ \ \ \ ${aux_line}\n" + aux_line="${srv_pkg}::${srv_file} ${topic_name}_srv_;" + line="${line}\ \ \ \ ${aux_line}\n" -#if no attribute was already there, add them all -if [[ "${comment_found}" = "false" ]] -then comment="\[client attributes\]" add_line_to_file "${line}" "${comment}" "${node_h}" -else - kill_exit "Some attributes are already defined, please check your script input variables: ${line}" -fi - ################################################################################ #modify Node.cpp -#look if constructor is already defined in file -line="this->node_handle_.serviceClient<${srv_pkg}::${srv_file}>(port_name);" -find_comment_in_file "${line}" "${node_c}" - -#look if request is already defined in file -line="if (${client_name}.call(${topic_name}_srv))" -find_comment_in_file "${line}" "${node_c}" - -#if no attribute was already there, add them all -if [[ "${comment_found}" = "false" ]] -then line="${client_name} = this->public_node_handle_.serviceClient<${srv_pkg}::${srv_file}>(\"${topic_name}\");" comment="\[init clients\]" - add_line_to_file "\ \ ${line}" "${comment}" "${node_c}" - - line="//${topic_name}_srv_.request.data = my_var; \\ -\ \ //ROS_INFO(\"${class_name}:: Sending New Request!\"); \\ -\ \ //if (${client_name}.call(${topic_name}_srv_)) \\ -\ \ //{ \\ -\ \ \ \ //ROS_INFO(\"${class_name}:: Response: %s\", ${topic_name}_srv_.response.result); \\ -\ \ //} \\ -\ \ //else \\ -\ \ //{ \\ -\ \ \ \ //ROS_INFO(\"${class_name}:: Failed to Call Server on topic ${topic_name} \"); \\ -\ \ //}" + add_line_to_file "\ \ ${line}\n" "${comment}" "${node_c}" + + aux_line="//${topic_name}_srv_.request.data = my_var;" + line="\ \ ${aux_line}\n" + aux_line="\ \ //ROS_INFO(\"${class_name}:: Sending New Request!\");" + line="${line}${aux_line}\n" + aux_line="\ \ //if (${client_name}.call(${topic_name}_srv_))" + line="${line}${aux_line}\n" + aux_line="\ \ //{" + line="${line}${aux_line}\n" + aux_line="\ \ \ \ //ROS_INFO(\"${class_name}:: Response: %s\", ${topic_name}_srv_.response.result);" + line="${line}${aux_line}\n" + aux_line="\ \ //}" + line="${line}${aux_line}\n" + aux_line="\ \ //else" + line="${line}${aux_line}\n" + aux_line="\ \ //{" + line="${line}${aux_line}\n" + aux_line="\ \ \ \ //ROS_INFO(\"${class_name}:: Failed to Call Server on topic ${topic_name} \");" + line="${line}${aux_line}\n" + aux_line="\ \ //}" + line="${line}${aux_line}\n" comment="\[fill srv structure and make request to the server\]" - add_line_to_file "\ \ ${line}" "${comment}" "${node_c}" + add_line_to_file "${line}\n" "${comment}" "${node_c}" -else - kill_exit "Some attributes are already defined, please check your script input variables: ${line}" -fi +################################################################################ +# Modify package.xml +# check if the message package is the current ros package + add_build_run_dependencies "${driver_alg}" "${ros_pkg}" "${srv_pkg}" ################################################################################ +# modify the CMakeLists.txt file +# check if the message package is the current ros package + add_cmake_dependencies "${driver_alg}" "${ros_pkg}" "${srv_pkg}" +################################################################################ +#compile + goto_catkin_workspace + catkin_make --only-pkg-with-deps ${ros_pkg} } diff --git a/libraries/create_publisher.sh b/libraries/create_publisher.sh index 6a71bf25257a413f1db5bd64b31e167cc86a07a2..0592145343190c902b539439cd15932593698d97 100755 --- a/libraries/create_publisher.sh +++ b/libraries/create_publisher.sh @@ -1,7 +1,5 @@ #!/bin/bash -# WET - # check wether the scripts path environment variable has been defined scripts_path=`echo "${IRI_ROS_SCRIPTS_PATH}"` if [[ -z "${scripts_path}" ]] @@ -14,88 +12,396 @@ fi source "${IRI_ROS_SCRIPTS_PATH}/libraries/scripts_library.sh" +function check_publisher_file_integrity +{ + local node_h=$1 + local node_c=$2 + local comment="" + + # check the node.h file + comment="\[publisher subscriber headers\]" + find_comment_in_file "${comment}" "${node_h}" + if [[ "${comment_found}" = "false" ]] + then + kill_exit "Missing \[publisher subscriber headers\] from the header file ${node_h}" + fi + comment="\[publisher attributes\]" + find_comment_in_file "${comment}" "${node_h}" + if [[ "${comment_found}" = "false" ]] + then + kill_exit "Missing \[publisher attributes\] from the header file ${node_h}" + fi + + # check the node.cpp file + comment="\[init publishers\]" + find_comment_in_file "${comment}" "${node_c}" + if [[ "${comment_found}" = "false" ]] + then + kill_exit "Missing \[init publishers\] from the header file ${node_c}" + fi + comment="\[fill msg structures\]" + find_comment_in_file "${comment}" "${node_c}" + if [[ "${comment_found}" = "false" ]] + then + kill_exit "Missing \[fill msg structures\] from the header file ${node_c}" + fi + + comment="\[publish messages\]" + find_comment_in_file "${comment}" "${node_c}" + if [[ "${comment_found}" = "false" ]] + then + kill_exit "Missing \[publish messages\] from the header file ${node_c}" + fi +} + +function check_publisher_attributes_functions +{ + local node_h=$1 + local node_c=$2 + local msg_pkg=$3 + local msg_file=$4 + local topic_name=$5 + local publisher_name=$6 + local buffer=$7 + local line="" + + # check the node.h file + if [[ "${msg_file}" = "Image" ]] + then + line="image_transport::CameraPublisher ${publisher_name};" + find_comment_in_file "${line}" "${node_h}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "A publisher with the same name is already declared in file ${node_h} line ${line_number}" + fi + line="camera_info_manager::CameraInfoManager ${topic_name}_camera_manager;" + find_comment_in_file "${line}" "${node_h}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "A camera manager with the same name is already declared in file ${node_h} line ${line_number}" + fi + else + line="ros::Publisher ${publisher_name};" + find_comment_in_file "${line}" "${node_h}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "A publisher with the same name is already declared in file ${node_h} line ${line_number}" + fi + fi + + line="${msg_pkg}::${msg_file} ${topic_name}_${msg_file}_msg_;" + find_comment_in_file "${line}" "${node_h}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "A message variable with the same name is already declared in file ${node_h} line ${line_number}" + fi + + # check the node.cpp file + if [[ "${msg_file}" = "Image" ]] + then + line="${topic_name}_camera_manager(ros::NodeHandle(\"~${topic_name}\"))" + find_comment_in_file "${line}" "${node_c}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "A camera manager with the same name is already initialized in file ${node_c} line ${line_number}" + fi + line="this->${publisher_name} = this->it.advertiseCamera(\"${topic_name}/image_raw\", ${buffer});" + find_comment_in_file "${line}" "${node_c}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "A topic with the same name is already advertised in file ${node_c} line ${line_number}" + fi + line="this->${topic_name}_camera_manager.validateURL(${topic_name}_cal_file)" + find_comment_in_file "${line}" "${node_c}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "The calibration file URL for a camera manager with the same name is already validated in file ${node_c} line ${line_number}" + fi + line="this->${topic_name}_camera_manager.loadCameraInfo(${topic_name}_cal_file)" + find_comment_in_file "${line}" "${node_c}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "The camera information for a camera manager with the same name is already loaded in file ${node_c} line ${line_number}" + fi + line="sensor_msgs::CameraInfo ${topic_name}_camera_info=this->${topic_name}_camera_manager.getCameraInfo();" + find_comment_in_file "${line}" "${node_c}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "The camera info structure for a topic with the same name is already initialized in file ${node_c} line ${line_number}" + fi + line="//this->${publisher_name}.publish(this->${topic_name}_${msg_file}_msg_,${topic_name}_camera_info);" + find_comment_in_file "${line}" "${node_c}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "A message with the same name is already published in file ${node_c} line ${line_number}" + fi + else + line="this->${publisher_name} = this->public_node_handle_.advertise<${msg_pkg}::${msg_file}>(\"${topic_name}\", ${buffer});" + find_comment_in_file "${line}" "${node_c}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "A publisher with the same name is already advertised in file ${node_c} line ${line_number}" + fi + line="this->${publisher_name}.publish(this->${topic_name}_${msg_file}_msg_);" + find_comment_in_file "${line}" "${node_c}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "A message with the same name is already published in file ${node_c} line ${line_number}" + fi + fi +} + function create_publisher { -#read input params -local ros_pkg=$1 -local topic_name=$2 -local msg_file=$3 -local msg_pkg=$4 -local buffer=$5 -local node_h=$6 -local node_c=$7 -local driver_alg=$8 -local publisher_name="${topic_name}_publisher_" - -#check if node_h is empty, then it would be a library -if [[ ${node_h} == ${node_c} ]] -then - local advertise="template advertise" -else - local advertise="advertise" -fi + #read input params + local ros_pkg=$1 + local topic_name=$2 + local msg_file=$3 + local msg_pkg=$4 + local buffer=$5 + local node_h=$6 + local node_c=$7 + local driver_alg=$8 + local publisher_name="${topic_name}_publisher_" + local line="" + local old_line="" + local aux_line="" + local comment="" + local old_string="" + local new_string="" -################################################################################ -# modify Node.h # + #get class basename + get_class_basename "${node_c}" + if [[ -z ${class_name} ]] + then + kill_exit "impossible to retrieve class basename" + fi -#look for include files and add them if are not already there -local line="#include <${msg_pkg}/${msg_file}.h>" -local comment="\[publisher subscriber headers\]" -add_line_to_file "${line}" "${comment}" "${node_h}" + #check files integrity before making any changes + check_package_file_integrity "${driver_alg}" + check_cmakelists_file_integrity "${driver_alg}" + check_publisher_file_integrity "${node_h}" "${node_c}" + check_publisher_attributes_functions "${node_h}" "${node_c}" "${msg_pkg}" "${msg_file}" "${topic_name}" "${publisher_name}" "${buffer}" -#look if attribute is already defined in file -local aux_line="ros::Publisher ${publisher_name};" -find_comment_in_file "${aux_line}" "${node_h}" -line="\ \ \ \ ${aux_line}\n" +################################################################################ +# modify Node.h # -#look if attribute is already defined in file -aux_line="${msg_pkg}::${msg_file} ${msg_file}_msg_;" -find_comment_in_file "${aux_line}" "${node_h}" -line="${line}\ \ \ \ ${aux_line}" + #look for include files and add them if are not already there + line="#include <${msg_pkg}/${msg_file}.h>" + comment="\[publisher subscriber headers\]" + add_line_to_file "${line}" "${comment}" "${node_h}" + if [[ "${msg_file}" = "Image" ]] + then + line="//#include <cv_bridge/cv_bridge.h>" + comment="\[publisher subscriber headers\]" + add_line_to_file "${line}" "${comment}" "${node_h}" + line="// Uncomment to use the openCV <-> ROS bridge" + comment="\[publisher subscriber headers\]" + add_line_to_file "${line}" "${comment}" "${node_h}" + line="#include <image_transport/image_transport.h>" + comment="\[publisher subscriber headers\]" + add_line_to_file "${line}" "${comment}" "${node_h}" + line="#include <camera_info_manager/camera_info_manager.h>" + comment="\[publisher subscriber headers\]" + add_line_to_file "${line}" "${comment}" "${node_h}" + fi -#if no attribute was already there, add them all -if [[ "${comment_found}" = "false" ]] -then + # add the message type variable + aux_line="${msg_pkg}::${msg_file} ${topic_name}_${msg_file}_msg_;" + line="\ \ \ \ ${aux_line}\n" comment="\[publisher attributes\]" add_line_to_file "${line}" "${comment}" "${node_h}" -else - kill_exit "Some attributes are already defined, please check your script input variables: ${line}" -fi + + # special actions for images + if [[ "${msg_file}" = "Image" ]] + then + aux_line="image_transport::CameraPublisher ${publisher_name};" + line="\ \ \ \ ${aux_line}" + comment="\[publisher attributes\]" + add_line_to_file "${line}" "${comment}" "${node_h}" + aux_line="camera_info_manager::CameraInfoManager ${topic_name}_camera_manager;" + line="\ \ \ \ ${aux_line}" + comment="\[publisher attributes\]" + add_line_to_file "${line}" "${comment}" "${node_h}" + aux_line="image_transport::ImageTransport it;" + find_comment_in_file "${aux_line}" "${node_h}" + if [[ "${comment_found}" = "false" ]] + then + line="\ \ \ \ ${aux_line}" + comment="\[publisher attributes\]" + add_line_to_file "${line}\n" "${comment}" "${node_h}" + fi + aux_line="cv_bridge::CvImagePtr cv_image_;" + find_comment_in_file "${aux_line}" "${node_h}" + if [[ "${comment_found}" = "false" ]] + then + line="// Uncomment to use the openCV <-> ROS bridge" + line="\ \ \ \ ${line}\n\ \ \ \ //${aux_line}" + comment="\[publisher attributes\]" + add_line_to_file "${line}" "${comment}" "${node_h}" + fi + else + aux_line="ros::Publisher ${publisher_name};" + line="\ \ \ \ ${aux_line}" + comment="\[publisher attributes\]" + add_line_to_file "${line}" "${comment}" "${node_h}" + fi ################################################################################ # modify Node.cpp # + if [[ "${msg_file}" = "Image" ]] + then + line="it(this->public_node_handle_)" + find_comment_in_file "${line}" "${node_c}" + if [[ "${comment_found}" = "false" ]] + then + #check if ':' are needed + comment="${class_name}::${class_name}(" + add_char=`grep "${comment}" "${node_c}" | grep " :"` + if [[ -z ${add_char} ]] + then + sed -i "/${comment}/s|$| :|" "${node_c}" + add_line_to_file "\ \ ${line}" "${comment}" "${node_c}" + else + #check if it is an algorithm or a driver + if [[ ${driver_alg} == "alg" ]] + then + comment="::IriBaseAlgorithm<" + else + comment="::IriBaseNodeDriver<" + fi + #check if ',' is needed + add_char=`grep "${comment}" "${node_c}" | grep ","` + if [[ -z ${add_char} ]] + then + #add ',' to comment + sed -i "/${comment}/s|$|,|" "${node_c}" + add_line_to_file "\ \ ${line}" "${comment}" "${node_c}" + else + add_line_to_file "\ \ ${line}," "${comment}" "${node_c}" + fi + fi + fi + line="${topic_name}_camera_manager(ros::NodeHandle(\"~${topic_name}\"))" -#look if constructor is already defined in file -line="this->${publisher_name} = this->node_handle_.${advertise}<${msg_pkg}::${msg_file}>(port_name, ${buffer});" -find_comment_in_file "${line}" "${node_c}" - -#look if msg update is already defined in file -line="//this->${msg_file}_msg_.data = my_var;" -find_comment_in_file "${line}" "${node_c}" - -#look if publish is already defined in file -line="this->${publisher_name}.publish(this->${msg_file}_msg_);" -find_comment_in_file "${line}" "${node_c}" + #check if ':' are needed + comment="${class_name}::${class_name}(" + add_char=`grep "${comment}" "${node_c}" | grep " :"` + if [[ -z ${add_char} ]] + then + sed -i "/${comment}/s|$| :|" "${node_c}" + add_line_to_file "\ \ ${line}" "${comment}" "${node_c}" + else + #check if it is an algorithm or a driver + if [[ ${driver_alg} == "alg" ]] + then + comment="::IriBaseAlgorithm<" + else + comment="::IriBaseNodeDriver<" + fi + #check if ',' is needed + add_char=`grep "${comment}" "${node_c}" | grep ","` + if [[ -z ${add_char} ]] + then + #add ',' to comment + sed -i "/${comment}/s|$|,|" "${node_c}" + add_line_to_file "\ \ ${line}" "${comment}" "${node_c}" + else + add_line_to_file "\ \ ${line}," "${comment}" "${node_c}" + fi + fi + # try load the calibration file + aux_line="// uncomment the following lines to load the calibration file for the camera" + line="${aux_line}\n" + aux_line="\ \ // Change <cal_file_param> for the correct parameter name holding the configuration filename" + line="${line}${aux_line}\n" + aux_line="\ \ //std::string ${topic_name}_cal_file;" + line="${line}${aux_line}\n" + aux_line="\ \ //public_node_handle_.param<std::string>(\"<cal_file_param>\",${topic_name}_cal_file,\"\");" + line="${line}${aux_line}\n" + aux_line="\ \ //if(this->${topic_name}_camera_manager.validateURL(${topic_name}_cal_file))" + line="${line}${aux_line}\n" + aux_line="\ \ //{" + line="${line}${aux_line}\n" + aux_line="\ \ //\ \ if(!this->${topic_name}_camera_manager.loadCameraInfo(${topic_name}_cal_file))" + line="${line}${aux_line}\n" + aux_line="\ \ //\ \ \ \ ROS_INFO(\"Invalid calibration file\");" + line="${line}${aux_line}\n" + aux_line="\ \ //}" + line="${line}${aux_line}\n" + aux_line="\ \ //else" + line="${line}${aux_line}\n" + aux_line="\ \ //\ \ ROS_INFO(\"Invalid calibration file\");" + line="${line}${aux_line}\n" + comment="\[init publishers\]" + add_line_to_file " ${line}" "${comment}" "${node_c}" + line="this->${publisher_name} = this->it.advertiseCamera(\"${topic_name}/image_raw\", ${buffer});" + comment="\[init publishers\]" + add_line_to_file " ${line}" "${comment}" "${node_c}" + aux_line="// Uncomment the following lines two initialize the camera info structure" + line="${aux_line}\n" + aux_line="\ \ //sensor_msgs::CameraInfo ${topic_name}_camera_info=this->${topic_name}_camera_manager.getCameraInfo();" + line="${line}${aux_line}\n" + aux_line="\ \ //${topic_name}_camera_info.header.stamp = <time_stamp>;" + line="${line}${aux_line}\n" + aux_line="\ \ //${topic_name}_camera_info.header.frame_id = <frame_id>;" + line="${line}${aux_line}\n" + comment="\[fill msg structures\]" + add_line_to_file "\ \ ${line}" "${comment}" "${node_c}" + aux_line="// Uncomment the following line to convert an OpenCV image to a ROS image message" + line="${aux_line}\n" + aux_line="\ \ //this->${topic_name}_${msg_file}_msg_=*this->cv_image_->toImageMsg();" + line="${line}${aux_line}\n" + aux_line="\ \ // Uncomment the following line to publish the image together with the camera information" + line="${line}${aux_line}\n" + aux_line="\ \ //this->${publisher_name}.publish(this->${topic_name}_${msg_file}_msg_,${topic_name}_camera_info);" + line="${line}${aux_line}\n" + comment="\[publish messages\]" + add_line_to_file "\ \ ${line}" "${comment}" "${node_c}" + else + line="this->${publisher_name} = this->public_node_handle_.advertise<${msg_pkg}::${msg_file}>(\"${topic_name}\", ${buffer});" + comment="\[init publishers\]" + add_line_to_file " ${line}" "${comment}" "${node_c}" + aux_line="// Uncomment the following line to publish the topic message" + line="${aux_line}\n" + aux_line="\ \ //this->${publisher_name}.publish(this->${topic_name}_${msg_file}_msg_);" + line="${line}${aux_line}\n" + comment="\[publish messages\]" + add_line_to_file "\ \ ${line}" "${comment}" "${node_c}" + fi -#if no attribute was already there, add them all -if [[ "${comment_found}" = "false" ]] -then - line="this->${publisher_name} = this->public_node_handle_.${advertise}<${msg_pkg}::${msg_file}>(\"${topic_name}\", ${buffer});" - comment="\[init publishers\]" - add_line_to_file " ${line}" "${comment}" "${node_c}" - - line="//this->${msg_file}_msg_.data = my_var;" + aux_line="// Initialize the topic message structure" + line="${aux_line}\n" + aux_line="\ \ //this->${topic_name}_${msg_file}_msg_.data = my_var;" + line="${line}${aux_line}\n" comment="\[fill msg structures\]" add_line_to_file "\ \ ${line}" "${comment}" "${node_c}" - line="this->${publisher_name}.publish(this->${msg_file}_msg_);" - comment="\[publish messages\]" - add_line_to_file "\ \ ${line}" "${comment}" "${node_c}" +################################################################################ +# Modify package.xml +# check if the message package is the current ros package -else - kill_exit "Some attributes are already defined, please check your script input variables: ${line}" -fi + add_build_run_dependencies "${driver_alg}" "${ros_pkg}" "${msg_pkg}" + if [[ "${msg_file}" = "Image" ]] + then + add_build_run_dependencies "${driver_alg}" "${ros_pkg}" "camera_info_manager" + add_build_run_dependencies "${driver_alg}" "${ros_pkg}" "image_transport" + add_build_run_dependencies "${driver_alg}" "${ros_pkg}" "cv_bridge" + fi ################################################################################ +# modify the CMakeLists.txt file + add_cmake_dependencies "${driver_alg}" "${ros_pkg}" "${msg_pkg}" + if [[ "${msg_file}" = "Image" ]] + then + add_cmake_dependencies "${driver_alg}" "${ros_pkg}" "camera_info_manager" + add_cmake_dependencies "${driver_alg}" "${ros_pkg}" "image_transport" + add_cmake_dependencies "${driver_alg}" "${ros_pkg}" "cv_bridge" + fi + +################################################################################ +#compile + goto_catkin_workspace + catkin_make --only-pkg-with-deps ${ros_pkg} } diff --git a/libraries/create_server.sh b/libraries/create_server.sh index da72292e60d055b2fc7f39ec336465fa20ea45b4..2bd88752eba7e3b64f4ac7871fe0ebea927e936c 100755 --- a/libraries/create_server.sh +++ b/libraries/create_server.sh @@ -1,12 +1,10 @@ #!/bin/bash -# WET - # check wether the scripts path environment variable has been defined scripts_path=`echo "${IRI_ROS_SCRIPTS_PATH}"` if [[ -z "${scripts_path}" ]] then - echo "The scripts path environment varibale has not been defined. Please see the wiki documentation for instructions on how to create it." + echo "The scripts path environment variable has not been defined. Please see the wiki documentation for instructions on how to create it." exit else echo "The scripts path environment variable has been properly defined." @@ -14,123 +12,258 @@ fi source "${IRI_ROS_SCRIPTS_PATH}/libraries/scripts_library.sh" +function check_server_file_integrity +{ + local node_h=$1 + local node_c=$2 + local comment="" + + # check the node.h file + comment="\[service client headers\]" + find_comment_in_file "${comment}" "${node_h}" + if [[ "${comment_found}" = "false" ]] + then + kill_exit "Missing \[service client headers\] from the header file ${node_h}" + fi + comment="\[service attributes\]" + find_comment_in_file "${comment}" "${node_h}" + if [[ "${comment_found}" = "false" ]] + then + kill_exit "Missing \[service attributes\] from the header file ${node_h}" + fi + + # check the node.cpp file + comment="\[init services\]" + find_comment_in_file "${comment}" "${node_c}" + if [[ "${comment_found}" = "false" ]] + then + kill_exit "Missing \[init services\] from the header file ${node_c}" + fi + comment="\[service callbacks\]" + find_comment_in_file "${comment}" "${node_c}" + if [[ "${comment_found}" = "false" ]] + then + kill_exit "Missing \[service callbacks\] from the header file ${node_c}" + fi + comment="\[free dynamic memory\]" + find_comment_in_file "${comment}" "${node_c}" + if [[ "${comment_found}" = "false" ]] + then + kill_exit "Missing \[free dynamic memory\] from the header file ${node_c}" + fi +} + +function check_server_attributes_functions +{ + local node_h=$1 + local node_c=$2 + local server_name=$3 + local srv_pkg=$4 + local srv_file=$5 + local topic_name=$6 + local callback=$7 + local mutex_name=$8 + local class_name=$9 + local line="" + + # check the node.h file + line="ros::ServiceServer ${server_name};" + find_comment_in_file "${line}" "${node_h}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "A service server with the same name is already declared in file ${node_h} line ${line_number}" + fi + line="bool ${callback}(${srv_pkg}::${srv_file}::Request &req, ${srv_pkg}::${srv_file}::Response &res);" + find_comment_in_file "${line}" "${node_h}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "A service callback function with the same name is already declared in file ${node_h} line ${line_number}" + fi + line="pthread_mutex_t ${mutex_name};" + find_comment_in_file "${line}" "${node_h}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "A mutex with the same name is already declared in file ${node_h} line ${line_number}" + fi + line="void ${mutex_name}enter(void);" + find_comment_in_file "${line}" "${node_h}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "A mutex enter function with the same name is already declared in file ${node_h} line ${line_number}" + fi + line="void ${mutex_name}exit(void);" + find_comment_in_file "${line}" "${node_h}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "A mutex exit function with the same name is already declared in file ${node_h} line ${line_number}" + fi + + # check the node.cpp file + line="this->${server_name} = this->public_node_handle_.advertiseService(\"${topic_name}\", &${class_name}::${callback}, this);" + find_comment_in_file "${line}" "${node_c}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "A service server with the same name is already initialized in file ${node_c} line ${line_number}" + fi + line="pthread_mutex_init(&this->${mutex_name},NULL);" + find_comment_in_file "${line}" "${node_c}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "A mutex with the same name is already initialized in file ${node_c} line ${line_number}" + fi + line="pthread_mutex_destroy(&this->${mutex_name});" + find_comment_in_file "${line}" "${node_c}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "A mutex with the same name is already destroyed in file ${node_c} line ${line_number}" + fi + aux_line="bool ${class_name}::${callback}(${srv_pkg}::${srv_file}::Request &req, ${srv_pkg}::${srv_file}::Response &res)" + find_comment_in_file "${aux_line}" "${node_c}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "A service callback function with the same name is already implemented in file ${node_c} line ${line_number}" + fi + line="void ${class_name}::${mutex_name}enter(void)" + find_comment_in_file "${line}" "${node_c}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "A mutex enter function with the same name is already implemented in file ${node_c} line ${line_number}" + fi + line="void ${class_name}::${mutex_name}exit(void)" + find_comment_in_file "${line}" "${node_c}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "A mutex exit function with the same name is already implemented in file ${node_c} line ${line_number}" + fi +} + function create_server { -#read input params -local ros_pkg=$1 -local topic_name=$2 -local srv_file=$3 -local srv_pkg=$4 -local node_h=$5 -local node_c=$6 -local driver_alg=$7 -local server_name="${topic_name}_server_" -local mutex_name="${topic_name}_mutex_" - - -#get class basename -get_class_basename "${node_c}" -if [[ -z ${class_name} ]] -then - kill_exit "impossible to retrieve class basename" -fi + #read input params + local ros_pkg=$1 + local topic_name=$2 + local srv_file=$3 + local srv_pkg=$4 + local node_h=$5 + local node_c=$6 + local driver_alg=$7 + local server_name="${topic_name}_server_" + local mutex_name="${topic_name}_mutex_" + local callback="${topic_name}Callback" + local line="" + local aux_line="" + local comment="" + + #get class basename + get_class_basename "${node_c}" + if [[ -z ${class_name} ]] + then + kill_exit "impossible to retrieve class basename" + fi # echo "class_name=${class_name}" -local callback="${topic_name}Callback" + #check files integrity before making any changes + check_package_file_integrity "${driver_alg}" + check_cmakelists_file_integrity "${driver_alg}" + check_server_file_integrity "${node_h}" "${node_c}" + check_server_attributes_functions "${node_h}" "${node_c}" "${server_name}" "${srv_pkg}" "${srv_file}" "${topic_name}" "${callback}" "${mutex_name}" "${class_name}" ################################################################################ #modify Node.h -#look for include files and add them if are not already there -local line="#include <${srv_pkg}/${srv_file}.h>" -local comment="\[service client headers\]" -add_line_to_file "${line}" "${comment}" "${node_h}" - -#look if attribute is already defined in file -local aux_line="ros::ServiceServer ${server_name};" -find_comment_in_file "${aux_line}" "${node_h}" -line="\ \ \ \ ${aux_line}\n" - -#look if attribute is already defined in file -aux_line="bool ${callback}(${srv_pkg}::${srv_file}::Request &req, ${srv_pkg}::${srv_file}::Response &res);" -find_comment_in_file "${aux_line}" "${node_h}" -line="${line}\ \ \ \ ${aux_line}\n" - -#look if attribute is already defined in file -aux_line="CMutex ${mutex_name};" -find_comment_in_file "${aux_line}" "${node_h}" -line="${line}\ \ \ \ ${aux_line}" + #look for include files and add them if are not already there + line="#include <${srv_pkg}/${srv_file}.h>" + comment="\[service client headers\]" + add_line_to_file "${line}" "${comment}" "${node_h}" -#if no attribute was already there, add them all -if [[ "${comment_found}" = "false" ]] -then + aux_line="ros::ServiceServer ${server_name};" + line="\ \ \ \ ${aux_line}\n" + aux_line="bool ${callback}(${srv_pkg}::${srv_file}::Request &req, ${srv_pkg}::${srv_file}::Response &res);" + line="${line}\ \ \ \ ${aux_line}\n" + aux_line="pthread_mutex_t ${mutex_name};" + line="${line}\ \ \ \ ${aux_line}\n" + aux_line="void ${mutex_name}enter(void);" + line="${line}\ \ \ \ ${aux_line}\n" + aux_line="void ${mutex_name}exit(void);" + line="${line}\ \ \ \ ${aux_line}\n" comment="\[service attributes\]" add_line_to_file "${line}" "${comment}" "${node_h}" -else - kill_exit "Some attributes are already defined, please check your script input variables: ${line}" -fi - ################################################################################ #modify Node.cpp -#look if constructor is already defined in file -line="this->${server_name} = this->node_handle_.advertiseService(\"${topic_name}\", &${class_name}::${callback}, this);" -find_comment_in_file "${line}" "${node_c}" + aux_line="this->${server_name} = this->public_node_handle_.advertiseService(\"${topic_name}\", &${class_name}::${callback}, this);" + line="\ \ ${aux_line}\n" + aux_line="pthread_mutex_init(&this->${mutex_name},NULL);\n" + line="${line}\ \ ${aux_line}" + comment="\[init services\]" + add_line_to_file "${line}" "${comment}" "${node_c}" -#look if callback is already defined in file -aux_line="bool ${class_name}::${callback}(${srv_pkg}::${srv_file}::Request &req, ${srv_pkg}::${srv_file}::Response &res)" -find_comment_in_file "${aux_line}" "${node_c}" + aux_line="bool ${class_name}::${callback}(${srv_pkg}::${srv_file}::Request &req, ${srv_pkg}::${srv_file}::Response &res)" + line="${aux_line}\n" + aux_line="{" + line="${line}${aux_line}\n" + aux_line="\ \ ROS_INFO(\"${class_name}::${callback}: New Request Received!\");" + line="${line}${aux_line}\n\n" + aux_line="\ \ //use appropiate mutex to shared variables if necessary" + line="${line}${aux_line}\n" + aux_line="\ \ //this->${driver_alg}_.lock();" + line="${line}${aux_line}\n" + aux_line="\ \ //this->${mutex_name}enter();" + line="${line}${aux_line}\n\n" + aux_line="\ \ //ROS_INFO(\"${class_name}::${callback}: Processing New Request!\");" + line="${line}${aux_line}\n" + aux_line="\ \ //do operations with req and output on res" + line="${line}${aux_line}\n" + aux_line="\ \ //res.data2 = req.data1 + my_var;" + line="${line}${aux_line}\n\n" + aux_line="\ \ //unlock previously blocked shared variables" + line="${line}${aux_line}\n" + aux_line="\ \ //this->${mutex_name}exit();" + line="${line}${aux_line}\n" + aux_line="\ \ //this->${driver_alg}_.unlock();" + line="${line}${aux_line}\n\n" + aux_line="\ \ return true;" + line="${line}${aux_line}\n" + aux_line="}" + line="${line}${aux_line}\n\n" + aux_line="${template_class}void ${class_name}::${mutex_name}enter(void)" + line="${line}${aux_line}\n" + aux_line="{" + line="${line}${aux_line}\n" + aux_line="\ \ pthread_mutex_lock(&this->${mutex_name});" + line="${line}${aux_line}\n" + aux_line="}" + line="${line}${aux_line}\n\n" + aux_line="${template_class}void ${class_name}::${mutex_name}exit(void)" + line="${line}${aux_line}\n" + aux_line="{" + line="${line}${aux_line}\n" + aux_line="\ \ pthread_mutex_unlock(&this->${mutex_name});" + line="${line}${aux_line}\n" + aux_line="}" + line="${line}${aux_line}\n" + comment="\[service callbacks\]" + add_line_to_file "${line}" "${comment}" "${node_c}" -if [[ "${comment_found}" = "false" ]] -then - line="this->${server_name} = this->public_node_handle_.advertiseService(\"${topic_name}\", &${class_name}::${callback}, this);" - comment="\[init services\]" + line="pthread_mutex_destroy(&this->${mutex_name});" + comment="\[free dynamic memory\]" add_line_to_file "\ \ ${line}" "${comment}" "${node_c}" - local template_class=(`echo ${class_name} | grep "<*>"`) +################################################################################ +# Modify package.xml +# check if the message package is the current ros package - if [[ -n ${template_class} ]] - then - local first_char_pos=`expr index "${class_name}" "<"` - local last_char_pos=`expr index "${class_name}" ">"` - let last_char_pos=${last_char_pos}-${first_char_pos}-1 - template_class=${class_name:first_char_pos:last_char_pos} - template_class="template <class ${template_class}> \n" - fi + add_build_run_dependencies "${driver_alg}" "${ros_pkg}" "${srv_pkg}" - line="${template_class}bool ${class_name}::${callback}(${srv_pkg}::${srv_file}::Request &req, ${srv_pkg}::${srv_file}::Response &res) \\ -{ \\ -\ \ ROS_INFO(\"${class_name}::${callback}: New Request Received!\"); \\ -\\ -\ \ //use appropiate mutex to shared variables if necessary \\ -\ \ //this->${driver_alg}_.lock(); \\ -\ \ //this->${mutex_name}.enter(); \\ -\\ -\ \ //if(this->${driver_alg}_.isRunning()) \\ -\ \ //{ \\ -\ \ \ \ //ROS_INFO(\"${class_name}::${callback}: Processin New Request!\"); \\ -\ \ \ \ //do operations with req and output on res \\ -\ \ \ \ //res.data2 = req.data1 + my_var; \\ -\ \ //} \\ -\ \ //else \\ -\ \ //{ \\ -\ \ \ \ //ROS_INFO(\"${class_name}::${callback}: ERROR: ${driver_alg} is not on run mode yet.\"); \\ -\ \ //} \\ -\\ -\ \ //unlock previously blocked shared variables \\ -\ \ //this->${driver_alg}_.unlock(); \\ -\ \ //this->${mutex_name}.exit(); \\ -\\ -\ \ return true; \\ -}" - comment="\[service callbacks\]" - add_line_to_file "${line}" "${comment}" "${node_c}" -else - kill_exit "Callback is already defined, please check your script input variables: ${aux_line}" -fi +################################################################################ +# modify the CMakeLists.txt file +# check if the message package is the current ros package + add_cmake_dependencies "${driver_alg}" "${ros_pkg}" "${srv_pkg}" ################################################################################ - +#compile + goto_catkin_workspace + catkin_make --only-pkg-with-deps ${ros_pkg} } diff --git a/libraries/create_subscriber.sh b/libraries/create_subscriber.sh index ef826491db2001b874b9fd28ddf2694f9f06b8b9..325f418ed2402f4d96e2079d22e6860b91600c77 100755 --- a/libraries/create_subscriber.sh +++ b/libraries/create_subscriber.sh @@ -1,7 +1,5 @@ #!/bin/bash -# WET - # check wether the scripts path environment variable has been defined scripts_path=`echo "${IRI_ROS_SCRIPTS_PATH}"` if [[ -z "${scripts_path}" ]] @@ -14,112 +12,402 @@ fi source "${IRI_ROS_SCRIPTS_PATH}/libraries/scripts_library.sh" +function check_subscriber_file_integrity +{ + local node_h=$1 + local node_c=$2 + local comment="" + + # check node.h file + comment="\[publisher subscriber headers\]" + find_comment_in_file "${comment}" "${node_h}" + if [[ "${comment_found}" = "false" ]] + then + kill_exit "Missing \[publisher subscriber headers\] from the header file ${node_h}" + fi + comment="\[subscriber attributes\]" + find_comment_in_file "${comment}" "${node_h}" + if [[ "${comment_found}" = "false" ]] + then + kill_exit "Missing \[subscriber attributes\] from the header file ${node_h}" + fi + + # check node.cpp file + comment="\[init subscribers\]" + find_comment_in_file "${comment}" "${node_c}" + if [[ "${comment_found}" = "false" ]] + then + kill_exit "Missing \[init subscribers\] from the header file ${node_c}" + fi + comment="\[subscriber callbacks\]" + find_comment_in_file "${comment}" "${node_c}" + if [[ "${comment_found}" = "false" ]] + then + kill_exit "Missing \[subscriber callbacks\] from the header file ${node_c}" + fi + comment="\[free dynamic memory\]" + find_comment_in_file "${comment}" "${node_c}" + if [[ "${comment_found}" = "false" ]] + then + kill_exit "Missing \[free dynamic memory\] from the header file ${node_c}" + fi +} + +function check_subscriber_attributes_functions +{ + local node_h=$1 + local node_c=$2 + local subscriber_name=$3 + local callback=$4 + local msg_pkg=$5 + local msg_file=$6 + local mutex_name=$7 + local topic_name=$8 + local class_name=$9 + local buffer=${10} + local line="" + + # check node.h file + if [[ "${msg_file}" = "Image" ]] + then + line="image_transport::CameraSubscriber ${subscriber_name};" + find_comment_in_file "${line}" "${node_h}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "A subscriber with the same name is already declared in file ${node_h} line ${line_number}" + fi + line="void ${callback}(const ${msg_pkg}::${msg_file}::ConstPtr& msg,const sensor_msgs::CameraInfoConstPtr& info);" + find_comment_in_file "${line}" "${node_h}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "A subscriber callback function with the same name is already declared in file ${node_h} line ${line_number}" + fi + else + line="ros::Subscriber ${subscriber_name};" + find_comment_in_file "${line}" "${node_h}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "A subscriber with the same name is already declared in file ${node_h} line ${line_number}" + fi + + line="void ${callback}(const ${msg_pkg}::${msg_file}::ConstPtr& msg);" + find_comment_in_file "${line}" "${node_h}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "A subscriber callback function with the same name is already declared in file ${node_h} line ${line_number}" + fi + fi + + line="pthread_mutex_t ${mutex_name};" + find_comment_in_file "${line}" "${node_h}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "A mutex with the same name is already declared in file ${node_h} line ${line_number}" + fi + + line="void ${mutex_name}enter(void);" + find_comment_in_file "${line}" "${node_h}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "A mutex enter function with the same name is already declared in file ${node_h} line ${line_number}" + fi + + line="void ${mutex_name}exit(void);" + find_comment_in_file "${line}" "${node_h}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "A mutex exit function with the same name is already declared in file ${node_h} line ${line_number}" + fi + + # check node.cpp file + if [[ "${msg_file}" = "Image" ]] + then + line="this->${subscriber_name} = this->it.subscribeCamera(\"${topic_name}/image_raw\", ${buffer}, &${class_name}::${callback}, this);" + find_comment_in_file "${line}" "${node_c}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "A subscriber with the same name is already subscribed in file ${node_c} line ${line_number}" + fi + else + line="this->${subscriber_name} = this->public_node_handle_.subscribe(\"${topic_name}\", ${buffer}, &${class_name}::${callback}, this);" + find_comment_in_file "${line}" "${node_c}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "A subscriber with the same name is already subscribed in file ${node_c} line ${line_number}" + fi + fi + + line="pthread_mutex_init(&this->${mutex_name},NULL);" + find_comment_in_file "${line}" "${node_c}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "A mutex with the same name is already initialized in file ${node_c} line ${line_number}" + fi + + line="pthread_mutex_destroy(&this->${mutex_name});" + find_comment_in_file "${line}" "${node_c}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "A mutex with the same name is already destroyed in file ${node_c} line ${line_number}" + fi + + #look if callback is already defined in file + if [[ "${msg_file}" = "Image" ]] + then + aux_line="void ${class_name}::${callback}(const ${msg_pkg}::${msg_file}::ConstPtr& msg, const sensor_msgs::CameraInfoConstPtr& info)" + find_comment_in_file "${aux_line}" "${node_c}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "A subscriber callback function with the same name is already implemented in file ${node_c} line ${line_number}" + fi + else + aux_line="void ${class_name}::${callback}(const ${msg_pkg}::${msg_file}::ConstPtr& msg)" + find_comment_in_file "${aux_line}" "${node_c}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "A subscriber callback function with the same name is already implemented in file ${node_c} line ${line_number}" + fi + fi + line="void ${class_name}::${mutex_name}enter(void)" + find_comment_in_file "${line}" "${node_c}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "A mutex enter function with the same name is already implemented in file ${node_c} line ${line_number}" + fi + line="void ${class_name}::${mutex_name}exit(void)" + find_comment_in_file "${line}" "${node_c}" + if [[ "${comment_found}" = "true" ]] + then + kill_exit "A mutex exit function with the same name is already implemented in file ${node_c} line ${line_number}" + fi +} + function create_subscriber { -#read input params -local ros_pkg=$1 -local topic_name=$2 -local msg_file=$3 -local msg_pkg=$4 -local buffer=$5 -local node_h=$6 -local node_c=$7 -local driver_alg=$8 -local subscriber_name="${topic_name}_subscriber_" -local mutex_name="${topic_name}_mutex_" -local callback="${topic_name}_callback" - - -#get class basename -get_class_basename "${node_c}" -if [[ -z ${class_name} ]] -then - kill_exit "impossible to retrieve class basename" -fi + #read input params + local ros_pkg=$1 + local topic_name=$2 + local msg_file=$3 + local msg_pkg=$4 + local buffer=$5 + local node_h=$6 + local node_c=$7 + local driver_alg=$8 + local subscriber_name="${topic_name}_subscriber_" + local mutex_name="${topic_name}_mutex_" + local callback="${topic_name}_callback" + local line="" + local old_line="" + local aux_line="" + local comment="" + local old_string="" + local new_string="" + + #get class basename + get_class_basename "${node_c}" + if [[ -z ${class_name} ]] + then + kill_exit "impossible to retrieve class basename" + fi # echo "class_name=${class_name}" - -################################################################################ -# modify Node.h # -#look for include files and add them if are not already there -local line="#include <${msg_pkg}/${msg_file}.h>" -local comment="\[publisher subscriber headers\]" -add_line_to_file "${line}" "${comment}" "${node_h}" + #check files integrity before making any changes + check_package_file_integrity "${driver_alg}" + check_cmakelists_file_integrity "${driver_alg}" + check_subscriber_file_integrity "${node_h}" "${node_c}" + check_subscriber_attributes_functions "${node_h}" "${node_c}" "${subscriber_name}" "${callback}" "${msg_pkg}" "${msg_file}" "${mutex_name}" "${topic_name}" "${class_name}" "${buffer}" -#look if attribute is already defined in file -local aux_line="ros::Subscriber ${subscriber_name};" -find_comment_in_file "${aux_line}" "${node_h}" -line="\ \ \ \ ${aux_line}\n" +################################################################################ +# modify Node.h # -#look if attribute is already defined in file -aux_line="void ${callback}(const ${msg_pkg}::${msg_file}::ConstPtr& msg);" -find_comment_in_file "${aux_line}" "${node_h}" -line="${line}\ \ \ \ ${aux_line}\n" + line="#include <${msg_pkg}/${msg_file}.h>" + comment="\[publisher subscriber headers\]" + add_line_to_file "${line}" "${comment}" "${node_h}" + if [[ "${msg_file}" = "Image" ]] + then + line="//#include <cv_bridge/cv_bridge.h>" + comment="\[publisher subscriber headers\]" + add_line_to_file "${line}" "${comment}" "${node_h}" + line="// Uncomment to use the openCV <-> ROS bridge" + comment="\[publisher subscriber headers\]" + add_line_to_file "${line}" "${comment}" "${node_h}" + line="#include <image_transport/image_transport.h>" + comment="\[publisher subscriber headers\]" + add_line_to_file "${line}" "${comment}" "${node_h}" + line="#include <camera_info_manager/camera_info_manager.h>" + comment="\[publisher subscriber headers\]" + add_line_to_file "${line}" "${comment}" "${node_h}" + fi -#look if attribute is already defined in file -aux_line="CMutex ${mutex_name};" -find_comment_in_file "${aux_line}" "${node_h}" -line="${line}\ \ \ \ ${aux_line}" + if [[ "${msg_file}" = "Image" ]] + then + aux_line="image_transport::ImageTransport it;" + find_comment_in_file "${aux_line}" "${node_h}" + if [[ "${comment_found}" = "false" ]] + then + line="\ \ \ \ ${aux_line}" + comment="\[subscriber attributes\]" + add_line_to_file "${line}\n" "${comment}" "${node_h}" + fi + aux_line="cv_bridge::CvImagePtr cv_image_;" + find_comment_in_file "${aux_line}" "${node_h}" + if [[ "${comment_found}" = "false" ]] + then + line="// Uncomment to use the openCV <-> ROS bridge" + line="\ \ \ \ ${line}\n\ \ \ \ //${aux_line}" + comment="\[subscriber attributes\]" + add_line_to_file "${line}" "${comment}" "${node_h}" + fi + aux_line="image_transport::CameraSubscriber ${subscriber_name};" + line="\ \ \ \ ${aux_line}\n" + aux_line="void ${callback}(const ${msg_pkg}::${msg_file}::ConstPtr& msg,const sensor_msgs::CameraInfoConstPtr& info);" + line="${line}\ \ \ \ ${aux_line}\n" + else + aux_line="ros::Subscriber ${subscriber_name};" + line="\ \ \ \ ${aux_line}\n" + aux_line="void ${callback}(const ${msg_pkg}::${msg_file}::ConstPtr& msg);" + line="${line}\ \ \ \ ${aux_line}\n" + fi + aux_line="pthread_mutex_t ${mutex_name};" + line="${line}\ \ \ \ ${aux_line}\n" + aux_line="void ${mutex_name}enter(void);" + line="${line}\ \ \ \ ${aux_line}\n" + aux_line="void ${mutex_name}exit(void);" + line="${line}\ \ \ \ ${aux_line}\n" -#if no attribute was already there, add them all -if [[ "${comment_found}" = "false" ]] -then comment="\[subscriber attributes\]" add_line_to_file "${line}" "${comment}" "${node_h}" -else - kill_exit "Some attributes are already defined, please check your script input variables: ${line}" -fi - ################################################################################ # modify Node.cpp # - -#look if constructor is already defined in file -line="this->${subscriber_name} = this->public_node_handle_.subscribe(\"${topic_name}\", ${buffer}, &${class_name}::${callback}, this);" -find_comment_in_file "${line}" "${node_c}" - -#look if callback is already defined in file -aux_line="void ${class_name}::${callback}(const ${msg_pkg}::${msg_file}::ConstPtr& msg)" -find_comment_in_file "${aux_line}" "${node_c}" - -if [[ "${comment_found}" = "false" ]] -then - line="this->${subscriber_name} = this->public_node_handle_.subscribe(\"${topic_name}\", ${buffer}, &${class_name}::${callback}, this);" + if [[ "${msg_file}" = "Image" ]] + then + line="it(this->public_node_handle_)" + find_comment_in_file "${line}" "${node_c}" + if [[ "${comment_found}" = "false" ]] + then + #check if ':' are needed + comment="${class_name}::${class_name}(" + add_char=`grep "${comment}" "${node_c}" | grep " :"` + if [[ -z ${add_char} ]] + then + sed -i "/${comment}/s|$| :|" "${node_c}" + add_line_to_file "\ \ ${line}" "${comment}" "${node_c}" + else + #check if it is an algorithm or a driver + if [[ ${driver_alg} == "alg" ]] + then + comment="::IriBaseAlgorithm<" + else + comment="::IriBaseNodeDriver<" + fi + #check if ',' is needed + add_char=`grep "${comment}" "${node_c}" | grep ","` + if [[ -z ${add_char} ]] + then + #add ',' to comment + sed -i "/${comment}/s|$|,|" "${node_c}" + add_line_to_file "\ \ ${line}" "${comment}" "${node_c}" + else + add_line_to_file "\ \ ${line}," "${comment}" "${node_c}" + fi + fi + fi + aux_line="this->${subscriber_name} = this->it.subscribeCamera(\"${topic_name}/image_raw\", ${buffer}, &${class_name}::${callback}, this);" + line="${aux_line}\n" + else + aux_line="this->${subscriber_name} = this->public_node_handle_.subscribe(\"${topic_name}\", ${buffer}, &${class_name}::${callback}, this);" + line="${aux_line}\n" + fi + aux_line="\ \ pthread_mutex_init(&this->${mutex_name},NULL);" + line="${line}${aux_line}\n" comment="\[init subscribers\]" add_line_to_file "\ \ ${line}" "${comment}" "${node_c}" - local template_class=(`echo ${class_name} | grep "<*>"`) - - if [[ -n ${template_class} ]] - then - local first_char_pos=`expr index "${class_name}" "<"` - local last_char_pos=`expr index "${class_name}" ">"` - let last_char_pos=${last_char_pos}-${first_char_pos}-1 - template_class=${class_name:first_char_pos:last_char_pos} - template_class="template <class ${template_class}> \n" - fi - - line="${template_class}void ${class_name}::${callback}(const ${msg_pkg}::${msg_file}::ConstPtr& msg) \\ -{ \\ -\ \ ROS_INFO(\"${class_name}::${callback}: New Message Received\"); \\ -\\ -\ \ //use appropiate mutex to shared variables if necessary \\ -\ \ //this->${driver_alg}_.lock(); \\ -\ \ //this->${mutex_name}.enter(); \\ -\\ -\ \ //std::cout << msg->data << std::endl; \\ -\\ -\ \ //unlock previously blocked shared variables \\ -\ \ //this->${driver_alg}_.unlock(); \\ -\ \ //this->${mutex_name}.exit(); \\ -}" + if [[ "${msg_file}" = "Image" ]] + then + aux_line="void ${class_name}::${callback}(const ${msg_pkg}::${msg_file}::ConstPtr& msg, const sensor_msgs::CameraInfoConstPtr& info)" + line="${aux_line}\n" + else + aux_line="void ${class_name}::${callback}(const ${msg_pkg}::${msg_file}::ConstPtr& msg)" + line="${aux_line}\n" + fi + aux_line="{" + line="${line}${aux_line}\n" + aux_line="\ \ ROS_INFO(\"${class_name}::${callback}: New Message Received\");" + line="${line}${aux_line}\n\n" + aux_line="\ \ //use appropiate mutex to shared variables if necessary" + line="${line}${aux_line}\n" + aux_line="\ \ //this->${driver_alg}_.lock();" + line="${line}${aux_line}\n" + aux_line="\ \ //this->${mutex_name}enter();" + line="${line}${aux_line}\n\n" + aux_line="\ \ //std::cout << msg->data << std::endl;" + line="${line}${aux_line}\n" + if [[ "${msg_file}" = "Image" ]] + then + aux_line="\ \ // Uncomment the following line to convert the input image to OpenCV format" + line="${line}${aux_line}\n" + aux_line="\ \ //this->cv_image_ = cv_bridge::toCvCopy(msg, \"mono8\");" + line="${line}${aux_line}\n\n" + fi + aux_line="\ \ //unlock previously blocked shared variables" + line="${line}${aux_line}\n" + aux_line="\ \ //this->${driver_alg}_.unlock();" + line="${line}${aux_line}\n" + aux_line="\ \ //this->${mutex_name}exit();" + line="${line}${aux_line}\n" + aux_line="}" + line="${line}${aux_line}\n\n" + aux_line="void ${class_name}::${mutex_name}enter(void)" + line="${line}${aux_line}\n" + aux_line="{" + line="${line}${aux_line}\n" + aux_line="\ \ pthread_mutex_lock(&this->${mutex_name});" + line="${line}${aux_line}\n" + aux_line="}" + line="${line}${aux_line}\n\n" + aux_line="void ${class_name}::${mutex_name}exit(void)" + line="${line}${aux_line}\n" + aux_line="{" + line="${line}${aux_line}\n" + aux_line="\ \ pthread_mutex_unlock(&this->${mutex_name});" + line="${line}${aux_line}\n" + aux_line="}" + line="${line}${aux_line}\n" comment="\[subscriber callbacks\]" add_line_to_file "${line}" "${comment}" "${node_c}" -else - kill_exit "Callback is already defined, please check your script input variables: ${aux_line}" -fi + line="pthread_mutex_destroy(&this->${mutex_name});" + comment="\[free dynamic memory\]" + add_line_to_file "\ \ ${line}" "${comment}" "${node_c}" ################################################################################ +# Modify package.xml +# check if the message package is the current ros package + + add_build_run_dependencies "${driver_alg}" "${ros_pkg}" "${msg_pkg}" + if [[ "${msg_file}" = "Image" ]] + then + add_build_run_dependencies "${driver_alg}" "${ros_pkg}" "camera_info_manager" + add_build_run_dependencies "${driver_alg}" "${ros_pkg}" "image_transport" + add_build_run_dependencies "${driver_alg}" "${ros_pkg}" "cv_bridge" + fi +################################################################################ +# modify the CMakeLists.txt file +# check if the message package is the current ros package + + add_cmake_dependencies "${driver_alg}" "${ros_pkg}" "${msg_pkg}" + if [[ "${msg_file}" = "Image" ]] + then + add_cmake_dependencies "${driver_alg}" "${ros_pkg}" "camera_info_manager" + add_cmake_dependencies "${driver_alg}" "${ros_pkg}" "image_transport" + add_cmake_dependencies "${driver_alg}" "${ros_pkg}" "cv_bridge" + fi + +################################################################################ +#compile + goto_catkin_workspace + catkin_make --only-pkg-with-deps ${ros_pkg} } diff --git a/libraries/scripts_library.sh b/libraries/scripts_library.sh index dceade8cf9c48287397042fa19bd14850b990ed7..24cd2c3f67726a6b90ef82b3e842a32467b1916f 100644 --- a/libraries/scripts_library.sh +++ b/libraries/scripts_library.sh @@ -1,19 +1,13 @@ #!/bin/bash -# WET +source "${ROS_ROOT}/../rosbash/rosbash" || kill_exit "ROS_ROOT Not found, try to install ROS again" -case ${ROS_ROOT} in - *electric* ) source "${ROS_ROOT}/tools/rosbash/rosbash" || kill_exit "ROS_ROOT Not found, try to install ROS again";; - *fuerte* ) source "${ROS_ROOT}/../rosbash/rosbash" || kill_exit "ROS_ROOT Not found, try to install ROS again";; - *hydro* ) source "${ROS_ROOT}/../rosbash/rosbash" || kill_exit "ROS_ROOT Not found, try to install ROS again";; - -esac # kill_exit # prints string in $1 and exits script # - $1: string to print function kill_exit { - echo $1 + echo -e $1 echo "" exit } @@ -50,7 +44,7 @@ function check_templates if [[ -d "${IRI_ROS_SCRIPTS_PATH}/driver_templates" ]] then pushd "${IRI_ROS_SCRIPTS_PATH}/driver_templates" - if [[ -e "CMakeLists.txt" ]] || [[ -e "template.cfg" ]] || [[ -e "template_driver.h" ]] || [[ -e "template_driver.cpp" ]] || [[ -e "template_node.h" ]] || [[ -e "template_node.cpp" ]] + if [[ -e "CMakeLists.txt" ]] && [[ -e "template_driver.cfg" ]] && [[ -e "template_driver.h" ]] && [[ -e "template_driver.cpp" ]] && [[ -e "template_driver_node.h" ]] && [[ -e "template_driver_node.cpp" ]] then echo "Driver template files available" popd @@ -63,11 +57,11 @@ function check_templates kill_exit "Missing driver templates folder, please download IRI_ROS scripts again, aborting ..." fi - echo "checking generic algorithm templates ..." - if [[ -d "${IRI_ROS_SCRIPTS_PATH}/generic_algorithm_templates" ]] + echo "checking algorithm templates ..." + if [[ -d "${IRI_ROS_SCRIPTS_PATH}/algorithm_templates" ]] then - pushd "${IRI_ROS_SCRIPTS_PATH}/generic_algorithm_templates" - if [[ -e "CMakeLists.txt" ]] || [[ -e "generic_algorithm_templates.h" ]] + pushd "${IRI_ROS_SCRIPTS_PATH}/algorithm_templates" + if [[ -e "CMakeLists.txt" ]] && [[ -e "template_alg.cfg" ]] && [[ -e "template_alg.cpp" ]] && [[ -e "template_alg.h" ]] && [[ -e "template_alg_node.cpp" ]] && [[ -e "template_alg_node.h" ]] then echo "Generic algorithm template files available" popd @@ -79,23 +73,6 @@ function check_templates popd kill_exit "Missing generic algorithm templates folder, please download IRI_ROS scripts again, aborting ..." fi - - echo "checking algorithm implementation templates ..." - if [[ -d "${IRI_ROS_SCRIPTS_PATH}/driver_templates" ]] - then - pushd "${IRI_ROS_SCRIPTS_PATH}/driver_templates" - if [[ -e "CMakeLists.txt" ]] || [[ -e "template_algorithm_implementation.cfg" ]] || [[ -e "template_algorithm_implementation.h" ]] || [[ -e "template_algorithm_implementation.cpp" ]] - then - echo "Algorithm implementation template files available" - popd - else - popd - kill_exit "Missing some algorithm implementation template files, please download IRI_ROS scripts again, aborting ..." - fi - else - popd - kill_exit "Missing algorithm implementation templates folder, please download IRI_ROS scripts again, aborting ..." - fi } # check_package @@ -214,11 +191,14 @@ function find_ros_message local ext=$2 local ros_pkg=$3 local ros_out= + local my_file_tmp= found_it=true if [[ ${ext} = "msg" ]] || [[ ${ext} = "srv" ]] then - ros_out=`eval "ros${ext} show ${my_file}"` + my_file_tmp="${my_file%.*}" + ros_out=`eval "ros${ext} list | grep ${my_file_tmp}"` + #ros_out=`eval "ros${ext} show ${my_file}"` else #action file ros_out=`eval "rosmsg show ${my_file}Action"` @@ -226,7 +206,8 @@ function find_ros_message local act_msgs="${my_file}Action ${my_file}ActionFeedback ${my_file}ActionGoal ${my_file}ActionResult ${my_file}Feedback ${my_file}Goal ${my_file}Result" for am in ${act_msgs} do - ros_out=`eval "rosmsg show ${am}"` + ros_out=`eval "rosmsg list | grep ${am}"` + #ros_out=`eval "rosmsg show ${am}"` if [[ -z "${ros_out}" ]] then found_it=false @@ -268,9 +249,7 @@ function find_ros_message fi } - -# # DRY add_pkg_to_manifest -# # WET add_pkg_to_packagexml +# add_pkg_to_packagexml # Adds $2 as dependency to $1 package.xml file. # - $1: current ros package # - $2: message ros package @@ -289,13 +268,13 @@ function add_pkg_to_packagexml roscd "${ros_pkg}" #look for package in package.xml and add dependency if necessary - local pub="<build_depend package=\"${file_pkg}\"/>" + local pub="<build_depend>${file_pkg}<build_depend/>" local pub1=$(grep "${pub}" "package.xml") if [[ -z "${pub1}" ]] then echo "Adding package \"${file_pkg}\" as dependency..." - local comment="build_depend package=\"iri_base_" - pub="<build_depend package=\"${file_pkg}\"\/>" + local comment="\"iri_base_" + pub="<build_depend>${file_pkg}<build_depend/>" sed -i -e "/${comment}/a\\ ${pub}" "package.xml" else echo "Package \"${file_pkg}\" already added as dependency, skipping" @@ -318,10 +297,12 @@ function find_comment_in_file comment_found="true" #look for key comment - local comm_found=$(grep "${comment_to_find}" "${file}") + local comm_found=$(grep -n "${comment_to_find}" "${file}") if [[ -z "${comm_found}" ]] then comment_found="false" + else + line_number=${comm_found%%:*} fi } @@ -356,8 +337,8 @@ function add_line_to_file if [[ -z "${line_found}" ]] then #add line to file - echo "Modifying file ${file} with:" - echo " ${line_to_add}" +# echo "Modifying file ${file} with:" +# echo " ${line_to_add}" sed -i -e "/${comment}/a\\${line_to_add}" "${file}" else #skip line @@ -427,12 +408,172 @@ function is_driver_or_alg_node fi } -# WET function change_license_to_LGPL { find . -name package.xml -exec sed -i -e 's:<license>.*</license>:<license>LGPL</license>:g' {} \; } +function goto_catkin_workspace +{ + roscd + if [[ -f .catkin ]] + then + cd .. # to catkin work space + else + setup_line=$(grep "setup-file" ".rosinstall") + ros_path=$(sed -n 's/.*- setup-file: {local-name: \(.*\)devel.*/\1/p' <<< ${setup_line}) + cd ${ros_path} + fi +} + +function check_package_file_integrity +{ + local driver_alg=$1 + local comment="" + + # check the package.xml file + if [[ "${driver_alg}" = "driver" ]] + then + comment="<build_depend>iri_base_driver<\/build_depend>" + find_comment_in_file "${comment}" "package.xml" + if [[ "${comment_found}" = "false" ]] + then + kill_exit "<build_depend>iri_base_driver<\/build_depend> missing in package.xml file" + fi + else + comment="<build_depend>iri_base_algorithm<\/build_depend>" + find_comment_in_file "${comment}" "package.xml" + if [[ "${comment_found}" = "false" ]] + then + kill_exit "<build_depend>iri_base_algorithm<\/build_depend> missing in package.xml file" + fi + fi + if [[ "${driver_alg}" = "driver" ]] + then + comment="<run_depend>iri_base_driver<\/run_depend>" + find_comment_in_file "${comment}" "package.xml" + if [[ "${comment_found}" = "false" ]] + then + kill_exit "<run_depend>iri_base_driver<\/run_depend> missing in package.xml file" + fi + else + comment="<run_depend>iri_base_algorithm<\/run_depend>" + find_comment_in_file "${comment}" "package.xml" + if [[ "${comment_found}" = "false" ]] + then + kill_exit "<run_depend>iri_base_algorithm<\/run_depend> missing in package.xml file" + fi + fi +} + +function check_cmakelists_file_integrity +{ + local driver_alg=$1 + local comment="" + local old_line="" + + old_line=$(grep "find_package(catkin REQUIRED COMPONENTS" "CMakeLists.txt") + if [[ "${driver_alg}" = "driver" ]] + then + if [[ $old_line != *iri_base_driver* ]] + then + kill_exit "Missing iri_base_driver in the catkin REQUIRED COMPONENTS list in file CMakeLists.txt. (multiline not supported)" + fi + else + if [[ $old_line != *iri_base_algorithm* ]] + then + kill_exit "Missing iri_base_algorithm in the catkin REQUIRED COMPONENTS list in file CMakeLists.txt. (multiline not supported)" + fi + fi + comment="add_dependencies(\${PROJECT_NAME} <msg_package_name>_generate_messages_cpp)" + find_comment_in_file "${comment}" "CMakeLists.txt" + if [[ "${comment_found}" = "false" ]] + then + kill_exit "Missing add_dependencies(\${PROJECT_NAME} <msg_package_name>_generate_messages_cpp) from the CMakeLists.txt file" + fi +} + +function add_build_run_dependencies +{ + local driver_alg=$1 + local ros_pkg=$2 + local new_pkg=$3 + local line="" + local comment="" + + if [[ "${new_pkg}" != "${ros_pkg}" ]] + then + line="<build_depend>${new_pkg}<\/build_depend>" + find_comment_in_file "${line}" "package.xml" + if [[ "${comment_found}" = "false" ]] + then + if [[ "${driver_alg}" = "driver" ]] + then + line="<build_depend>${new_pkg}<\/build_depend>" + comment="<build_depend>iri_base_driver<\/build_depend>" + add_line_to_file "\ \ ${line}" "${comment}" "package.xml" + else + line="<build_depend>${new_pkg}<\/build_depend>" + comment="<build_depend>iri_base_algorithm<\/build_depend>" + add_line_to_file "\ \ ${line}" "${comment}" "package.xml" + fi + else + echo "Build dependencies already included." + fi + + line="<run_depend>${new_pkg}<\/run_depend>" + find_comment_in_file "${line}" "package.xml" + if [[ "${comment_found}" = "false" ]] + then + if [[ "${driver_alg}" = "driver" ]] + then + line="<run_depend>${new_pkg}<\/run_depend>" + comment="<run_depend>iri_base_driver<\/run_depend>" + add_line_to_file "\ \ ${line}" "${comment}" "package.xml" + else + line="<run_depend>${new_pkg}<\/run_depend>" + comment="<run_depend>iri_base_algorithm<\/run_depend>" + add_line_to_file "\ \ ${line}" "${comment}" "package.xml" + fi + else + echo "Run dependencies already included." + fi + fi +} + +function add_cmake_dependencies +{ + local driver_alg=$1 + local ros_pkg=$2 + local new_pkg=$3 + local line="" + local old_line="" + local comment="" + local old_string="" + local new_string="" + + if [[ "${new_pkg}" != "${ros_pkg}" ]] + then + old_line=$(grep "find_package(catkin REQUIRED COMPONENTS" "CMakeLists.txt") + if [[ $old_line == *${new_pkg}* ]] + then + echo "Dependency already included in CMakeLists.txt file."; + else + if [[ "${driver_alg}" = "driver" ]] + then + old_string="iri_base_driver" + else + old_string="iri_base_algorithm" + fi + new_string="${old_string}\ ${new_pkg}" + sed -i "s/${old_string}/${new_string}/g" "CMakeLists.txt" + fi + + line="add_dependencies(\${PROJECT_NAME} ${new_pkg}_generate_messages_cpp)" + comment="add_dependencies(\${PROJECT_NAME} <msg_package_name>_generate_messages_cpp)" + add_line_to_file "${line}" "${comment}" "CMakeLists.txt" + fi +} # 11. Bash File Testing # -b filename Block special file diff --git a/setup.bash b/setup.bash index cf99cbe4d1c1bc92086e416758581cdc5dd5eeec..083246feb8c661bb7bc3b80ad16e4044312aa41d 100755 --- a/setup.bash +++ b/setup.bash @@ -1,7 +1,5 @@ #!/bin/bash -# WET - SCRIPT_PATH=`realpath "${BASH_SOURCE[0]}"` export IRI_ROS_SCRIPTS_PATH=${SCRIPT_PATH%/*}