2020#include < geometry_msgs/Twist.h>
2121#include < nav_msgs/Odometry.h>
2222#include < apriltags_ros/AprilTagDetectionArray.h>
23+ #include < std_msgs/Float32MultiArray.h>
2324
2425// Include Controllers
2526#include " LogicController.h"
3334#include < ros/ros.h>
3435#include < signal.h>
3536
37+ #include < exception> // For exception handling
3638
3739using namespace std ;
3840
41+ // Define Exceptions
42+ // Define an exception to be thrown if the user tries to create
43+ // a RangeShape using invalid dimensions
44+ class ROSAdapterRangeShapeInvalidTypeException : public std ::exception {
45+ public:
46+ ROSAdapterRangeShapeInvalidTypeException (std::string msg) {
47+ this ->msg = msg;
48+ }
49+
50+ virtual const char * what () const throw()
51+ {
52+ std::string message = " Invalid RangeShape type provided: " + msg;
53+ return message.c_str ();
54+ }
55+
56+ private:
57+ std::string msg;
58+ };
59+
60+
3961// Random number generator
4062random_numbers::RandomNumberGenerator* rng;
4163
@@ -106,6 +128,7 @@ ros::Subscriber modeSubscriber;
106128ros::Subscriber targetSubscriber;
107129ros::Subscriber odometrySubscriber;
108130ros::Subscriber mapSubscriber;
131+ ros::Subscriber virtualFenceSubscriber;
109132
110133
111134// Timers
@@ -133,6 +156,7 @@ void modeHandler(const std_msgs::UInt8::ConstPtr& message);
133156void targetHandler (const apriltags_ros::AprilTagDetectionArray::ConstPtr& tagInfo);
134157void odometryHandler (const nav_msgs::Odometry::ConstPtr& message);
135158void mapHandler (const nav_msgs::Odometry::ConstPtr& message);
159+ void virtualFenceHandler (const std_msgs::Float32MultiArray& message);
136160void behaviourStateMachine (const ros::TimerEvent&);
137161void publishStatusTimerEventHandler (const ros::TimerEvent& event);
138162void publishHeartBeatTimerEventHandler (const ros::TimerEvent& event);
@@ -167,7 +191,8 @@ int main(int argc, char **argv) {
167191 targetSubscriber = mNH .subscribe ((publishedName + " /targets" ), 10 , targetHandler);
168192 odometrySubscriber = mNH .subscribe ((publishedName + " /odom/filtered" ), 10 , odometryHandler);
169193 mapSubscriber = mNH .subscribe ((publishedName + " /odom/ekf" ), 10 , mapHandler);
170- message_filters::Subscriber<sensor_msgs::Range> sonarLeftSubscriber (mNH , (publishedName + " /sonarLeft" ), 10 );
194+ virtualFenceSubscriber = mNH .subscribe ((" /virtualFence" ), 10 , virtualFenceHandler);
195+ message_filters::Subscriber<sensor_msgs::Range> sonarLeftSubscriber (mNH , (publishedName + " /sonarLeft" ), 10 );
171196 message_filters::Subscriber<sensor_msgs::Range> sonarCenterSubscriber (mNH , (publishedName + " /sonarCenter" ), 10 );
172197 message_filters::Subscriber<sensor_msgs::Range> sonarRightSubscriber (mNH , (publishedName + " /sonarRight" ), 10 );
173198
@@ -294,7 +319,7 @@ void behaviourStateMachine(const ros::TimerEvent&) {
294319 }
295320
296321 // publishHandeling here
297- // logicController.getPublishData() suggested;
322+ // logicController.getPublishData(); suggested
298323
299324
300325 // adds a blank space between sets of debugging data to easly tell one tick from the next
@@ -385,6 +410,53 @@ void odometryHandler(const nav_msgs::Odometry::ConstPtr& message) {
385410 logicController.SetVelocityData (linearVelocity, angularVelocity);
386411}
387412
413+ // Allows a virtual fence to be defined and enabled or disabled through ROS
414+ void virtualFenceHandler (const std_msgs::Float32MultiArray& message)
415+ {
416+ // Read data from the message array
417+ // The first element is an integer indicating the shape type
418+ // 0 = Disable the virtual fence
419+ // 1 = circle
420+ // 2 = rectangle
421+ int shape_type = static_cast <int >(message.data [0 ]); // Shape type
422+
423+ if (shape_type == 0 )
424+ {
425+ logicController.setVirtualFenceOff ();
426+ }
427+ else
428+ {
429+ // Elements 2 and 3 are the x and y coordinates of the range center
430+ Point center;
431+ center.x = message.data [1 ]; // Range center x
432+ center.y = message.data [2 ]; // Range center y
433+
434+ // If the shape type is "circle" then element 4 is the radius, if rectangle then width
435+ switch ( shape_type )
436+ {
437+ case 1 : // Circle
438+ {
439+ if ( message.data .size () != 4 ) throw ROSAdapterRangeShapeInvalidTypeException (" Wrong number of parameters for circle shape type in ROSAdapter.cpp:virtualFenceHandler()" );
440+ float radius = message.data [3 ];
441+ logicController.setVirtualFenceOn ( new RangeCircle (center, radius) );
442+ break ;
443+ }
444+ case 2 : // Rectangle
445+ {
446+ if ( message.data .size () != 5 ) throw ROSAdapterRangeShapeInvalidTypeException (" Wrong number of parameters for rectangle shape type in ROSAdapter.cpp:virtualFenceHandler()" );
447+ float width = message.data [3 ];
448+ float height = message.data [4 ];
449+ logicController.setVirtualFenceOn ( new RangeRectangle (center, width, height) );
450+ break ;
451+ }
452+ default :
453+ { // Unknown shape type specified
454+ throw ROSAdapterRangeShapeInvalidTypeException (" Unknown Shape type in ROSAdapter.cpp:virtualFenceHandler()" );
455+ }
456+ }
457+ }
458+ }
459+
388460void mapHandler (const nav_msgs::Odometry::ConstPtr& message) {
389461 // Get (x,y) location directly from pose
390462 currentLocationMap.x = message->pose .pose .position .x ;
@@ -400,11 +472,11 @@ void mapHandler(const nav_msgs::Odometry::ConstPtr& message) {
400472 linearVelocity = message->twist .twist .linear .x ;
401473 angularVelocity = message->twist .twist .angular .z ;
402474
403- Point currentLoc ;
404- currentLoc .x = currentLocation .x ;
405- currentLoc .y = currentLocation .y ;
406- currentLoc .theta = currentLocation .theta ;
407- logicController.SetPositionData (currentLoc );
475+ Point curr_loc ;
476+ curr_loc .x = currentLocationMap .x ;
477+ curr_loc .y = currentLocationMap .y ;
478+ curr_loc .theta = currentLocationMap .theta ;
479+ logicController.SetMapPositionData (curr_loc );
408480 logicController.SetMapVelocityData (linearVelocity, angularVelocity);
409481}
410482
0 commit comments