WanderingNode.cpp
Go to the documentation of this file.
00001 /*
00002  * Filename: WanderingNode.cpp
00003  *   Author: Igor Makhtes
00004  *     Date: Dec 10, 2013
00005  *
00006  * The MIT License (MIT)
00007  *
00008  * Copyright (c) 2013 Cogniteam Ltd.
00009  *
00010  * Permission is hereby granted, free of charge, to any person obtaining a copy
00011  * of this software and associated documentation files (the "Software"), to deal
00012  * in the Software without restriction, including without limitation the rights
00013  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00014  * copies of the Software, and to permit persons to whom the Software is
00015  * furnished to do so, subject to the following conditions:
00016  *
00017  * The above copyright notice and this permission notice shall be included in
00018  * all copies or substantial portions of the Software.
00019  *
00020  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00021  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00022  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
00023  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00024  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00025  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
00026  * THE SOFTWARE.
00027  */
00028 
00029 #include <iostream>
00030 #include <time.h>
00031 #include <numeric>
00032 #include <boost/bind.hpp>
00033 #include <boost/thread.hpp>
00034 #include <boost/foreach.hpp>
00035 #include <boost/lambda/lambda.hpp>
00036 #include <boost/date_time.hpp>
00037 #include <ros/ros.h>
00038 
00039 #include <sensor_msgs/LaserScan.h>
00040 #include <geometry_msgs/Twist.h>
00041 
00042 #include "Wandering.h"
00043 
00044 using namespace std;
00045 
00046 #define foreach BOOST_FOREACH
00047 
00048 ros::Subscriber laserSub;
00049 ros::Publisher  velocityPub;
00050 ros::NodeHandle* node;
00051 
00052 void publishVelocity(double linear, double angular) {
00053     geometry_msgs::Twist velocity;
00054     velocity.linear.x = linear;
00055     velocity.angular.z = angular;
00056 
00057     for (int i = 0; i < 10; i++)
00058         velocityPub.publish(velocity);
00059 }
00060 
00067 bool preemptiveWait(double ms, decision_making::EventQueue& queue) {
00068     for (int i = 0; i < 100 && !queue.isTerminated(); i++)
00069         boost::this_thread::sleep(boost::posix_time::milliseconds(ms / 100.0));
00070 
00071     return queue.isTerminated();
00072 }
00073 
00080 bool preemptiveWait(double minMs, double maxMs, decision_making::EventQueue& queue) {
00081     double msToWait = ((double)rand() / (double)RAND_MAX) * (maxMs - minMs) + minMs;
00082     return preemptiveWait(msToWait, queue);
00083 }
00084 
00085 double getAverage(int centerRange, int rangeSize, const sensor_msgs::LaserScan::Ptr& scan) {
00086     double sum = std::accumulate(scan->ranges.begin() + centerRange - rangeSize / 2.0,
00087                                  scan->ranges.begin() + centerRange + rangeSize / 2.0, 0.0);
00088 
00089     return sum / (double)rangeSize;
00090 }
00091 
00092 int countRanges(const sensor_msgs::LaserScan::Ptr& scan, int center, int range, double lessThan) {
00093     return std::count_if(scan->ranges.begin() + center - range / 2.0,
00094                          scan->ranges.begin() + center + range / 2.0,
00095                          bind2nd(less<double>(), lessThan));
00096 }
00097 
00098 void onLaserScan(const sensor_msgs::LaserScan::Ptr scan, EventQueue* q) {
00099     int countFrontRange = countRanges(scan, scan->ranges.size() / 2, 100, 0.5);
00100     int countRightRange = countRanges(scan, (scan->ranges.size() / 6) * 1, 50, 0.5);
00101     int countLeftRange  = countRanges(scan, (scan->ranges.size() / 6) * 5, 50, 0.5);
00102 
00103     bool front = false;
00104     bool left = false;
00105     bool right = false;
00106 
00107     if (countFrontRange > 5) {
00108         front = true;
00109         q->riseEvent("/FRONT_OBSTACLE");
00110     }
00111 
00112     if (countLeftRange > 3) {
00113         left = true;
00114         q->riseEvent("/LEFT_OBSTACLE");
00115     }
00116 
00117     if (countRightRange > 3) {
00118         right = true;
00119         q->riseEvent("/RIGHT_OBSTACLE");
00120     }
00121 
00122     if (front && right)
00123         q->riseEvent("/FRONT_AND_RIGHT_OBSTACLE");
00124 
00125     if (front && left)
00126         q->riseEvent("/FRONT_AND_LEFT_OBSTACLE");
00127 }
00128 
00129 decision_making::TaskResult stopRobot(std::string, const decision_making::FSMCallContext& c, decision_making::EventQueue& e) {
00130     publishVelocity(0, 0);
00131     return decision_making::TaskResult::SUCCESS();
00132 }
00133 
00134 decision_making::TaskResult turnRight(std::string, const decision_making::FSMCallContext& c, decision_making::EventQueue& e) {
00135     publishVelocity(0, -2);
00136 
00137     if (preemptiveWait(500, 1000, e))
00138         return decision_making::TaskResult::TERMINATED();
00139 
00140     e.raiseEvent("/TIMEOUT_TURN");
00141     return decision_making::TaskResult::SUCCESS();
00142 }
00143 
00144 decision_making::TaskResult turnLeft(std::string, const decision_making::FSMCallContext& c, decision_making::EventQueue& e) {
00145     publishVelocity(0, 2);
00146 
00147     if (preemptiveWait(500, 1000, e))
00148         return decision_making::TaskResult::TERMINATED();
00149 
00150     e.raiseEvent("/TIMEOUT_TURN");
00151     return decision_making::TaskResult::SUCCESS();
00152 }
00153 
00154 decision_making::TaskResult turnRandom(std::string, const decision_making::FSMCallContext& c, decision_making::EventQueue& e) {
00155     bool turnRight = rand() % 2;
00156     publishVelocity(0, (turnRight * -2 + 1) * 2);
00157 
00158     ROS_INFO("Turning randomly");
00159 
00160     if (preemptiveWait(500, 2500, e))
00161         return decision_making::TaskResult::TERMINATED();
00162 
00163     e.raiseEvent("/TIMEOUT_TURN");
00164     return decision_making::TaskResult::SUCCESS();
00165 }
00166 
00167 decision_making::TaskResult drive(std::string, const decision_making::FSMCallContext& c, decision_making::EventQueue& e) {
00168     publishVelocity(0.75, 0);
00169 
00170     if (preemptiveWait(9000, 20000, e))
00171         return decision_making::TaskResult::TERMINATED();
00172 
00173     e.raiseEvent("/TIMEOUT_DRIVE");
00174     return decision_making::TaskResult::SUCCESS();
00175 }
00176 
00177 decision_making::TaskResult driveBackward(std::string, const decision_making::FSMCallContext& c, decision_making::EventQueue& e) {
00178     publishVelocity(-0.75, 0);
00179 
00180     if (preemptiveWait(1000, 2000, e))
00181         return decision_making::TaskResult::TERMINATED();
00182 
00183     e.raiseEvent("/TIMEOUT_BACKWARD");
00184     return decision_making::TaskResult::SUCCESS();
00185 }
00186 
00187 int main(int argc, char **argv) {
00188     ros::init(argc, argv, "wandering_node");
00189     ros_decision_making_init(argc, argv);
00190 
00191     ROS_INFO("Preparing wandering...");
00192 
00193     boost::posix_time::ptime epoch(boost::posix_time::min_date_time);
00194     boost::posix_time::ptime now(boost::posix_time::microsec_clock::local_time());
00195     unsigned int seed = (now - epoch).total_nanoseconds();
00196     srand(seed);
00197     node = new ros::NodeHandle();
00198 
00199     RosEventQueue* q = new RosEventQueue();
00200     laserSub    = node->subscribe<void>("/scan", 10,
00201             boost::function<void(const sensor_msgs::LaserScan::Ptr)>(boost::bind(onLaserScan, _1, q)));
00202 
00203     velocityPub = node->advertise<geometry_msgs::Twist>("/cmd_vel", 10, false);
00204 
00205     LocalTasks::registrate("TurnRight", turnRight);
00206     LocalTasks::registrate("TurnLeft", turnLeft);
00207     LocalTasks::registrate("TurnRandom", turnRandom);
00208     LocalTasks::registrate("Drive", drive);
00209     LocalTasks::registrate("DriveBackward", driveBackward);
00210     LocalTasks::registrate("StopRobot", stopRobot);
00211 
00212     ros::AsyncSpinner spinner(1);
00213     spinner.start();
00214     ROS_INFO("Spinner started");
00215     FsmWandering(NULL, q, "Wandering");
00216 
00217     delete node;
00218     return 0;
00219 }


dm_lizi
Author(s): Igor Makhtes
autogenerated on Thu Aug 27 2015 12:55:02