Advertisement
Guest User

Untitled

a guest
Feb 18th, 2017
384
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 28.31 KB | None | 0 0
  1. #include <ros/ros.h>
  2.  
  3. // ROS libraries
  4. #include <angles/angles.h>
  5. #include <random_numbers/random_numbers.h>
  6. #include <tf/transform_datatypes.h>
  7. #include <tf/transform_listener.h>
  8.  
  9. // ROS messages
  10. #include <std_msgs/Float32.h>
  11. #include <std_msgs/Int16.h>
  12. #include <std_msgs/UInt8.h>
  13. #include <std_msgs/String.h>
  14. #include <sensor_msgs/Joy.h>
  15. #include <sensor_msgs/Range.h>
  16. #include <geometry_msgs/Pose2D.h>
  17. #include <geometry_msgs/Twist.h>
  18. #include <nav_msgs/Odometry.h>
  19. #include <apriltags_ros/AprilTagDetectionArray.h>
  20. #include <std_msgs/Float64.h>
  21.  
  22. // Include Controllers
  23. #include "PickUpController.h"
  24. #include "DropOffController.h"
  25. #include "SearchController.h"
  26.  
  27. // To handle shutdown signals so the node quits
  28. // properly in response to "rosnode kill"
  29. #include <ros/ros.h>
  30. #include <signal.h>
  31.  
  32.  
  33. using namespace std;
  34.  
  35. // Random number generator
  36. random_numbers::RandomNumberGenerator* rng;
  37.  
  38. // Create controllers
  39. PickUpController pickUpController;
  40. DropOffController dropOffController;
  41. SearchController searchController;
  42.  
  43. // Mobility Logic Functions
  44. void sendDriveCommand(double linearVel, double angularVel);
  45. void openFingers(); // Open fingers to 90 degrees
  46. void closeFingers();// Close fingers to 0 degrees
  47. void raiseWrist();  // Return wrist back to 0 degrees
  48. void lowerWrist();  // Lower wrist to 50 degrees
  49. void mapAverage();  // constantly averages last 100 positions from map
  50.  
  51. // Numeric Variables for rover positioning
  52. geometry_msgs::Pose2D currentLocation;
  53. geometry_msgs::Pose2D currentLocationMap;
  54. geometry_msgs::Pose2D currentLocationAverage;
  55. geometry_msgs::Pose2D goalLocation;
  56.  
  57. geometry_msgs::Pose2D centerLocation;
  58. geometry_msgs::Pose2D centerLocationMap;
  59. geometry_msgs::Pose2D centerLocationOdom;
  60.  
  61. int currentMode = 0;
  62. float mobilityLoopTimeStep = 0.1; // time between the mobility loop calls
  63. float status_publish_interval = 1;
  64. float killSwitchTimeout = 10;
  65. bool targetDetected = false;
  66. bool targetCollected = false;
  67.  
  68. // Set true when the target block is less than targetDist so we continue
  69. // attempting to pick it up rather than switching to another block in view.
  70. bool lockTarget = false;
  71.  
  72. // Failsafe state. No legitimate behavior state. If in this state for too long
  73. // return to searching as default behavior.
  74. bool timeOut = false;
  75.  
  76. // Set to true when the center ultrasound reads less than 0.14m. Usually means
  77. // a picked up cube is in the way.
  78. bool blockBlock = false;
  79.  
  80. // central collection point has been seen (aka the nest)
  81. bool centerSeen = false;
  82.  
  83. // Set true when we are insie the center circle and we need to drop the block,
  84. // back out, and reset the boolean cascade.
  85. bool reachedCollectionPoint = false;
  86.  
  87. // used for calling code once but not in main
  88. bool init = false;
  89.  
  90. // used to remember place in mapAverage array
  91. int mapCount = 0;
  92.  
  93. // How many points to use in calculating the map average position
  94. const unsigned int mapHistorySize = 500;
  95.  
  96. // An array in which to store map positions
  97. geometry_msgs::Pose2D mapLocation[mapHistorySize];
  98.  
  99. bool avoidingObstacle = false;
  100.  
  101. float searchVelocity = 0.2; // meters/second
  102.  
  103. std_msgs::String msg;
  104.  
  105. // state machine states
  106. #define STATE_MACHINE_TRANSFORM 0
  107. #define STATE_MACHINE_ROTATE 1
  108. #define STATE_MACHINE_SKID_STEER 2
  109. #define STATE_MACHINE_PICKUP 3
  110. #define STATE_MACHINE_DROPOFF 4
  111.  
  112.  
  113.  
  114. int stateMachineState = STATE_MACHINE_TRANSFORM;
  115.  
  116. geometry_msgs::Twist velocity;
  117. char host[128];
  118. string publishedName;
  119. char prev_state_machine[128];
  120.  
  121. // Publishers
  122. ros::Publisher stateMachinePublish;
  123. ros::Publisher status_publisher;
  124. ros::Publisher fingerAnglePublish;
  125. ros::Publisher wristAnglePublish;
  126. ros::Publisher infoLogPublisher;
  127. ros::Publisher driveControlPublish;
  128.  
  129. // My own custom publisher
  130. ros::Publisher thetaPublish;
  131.  
  132. // Subscribers
  133. ros::Subscriber joySubscriber;
  134. ros::Subscriber modeSubscriber;
  135. ros::Subscriber targetSubscriber;
  136. ros::Subscriber obstacleSubscriber;
  137. ros::Subscriber odometrySubscriber;
  138. ros::Subscriber mapSubscriber;
  139.  
  140.  
  141. // Timers
  142. ros::Timer stateMachineTimer;
  143. ros::Timer publish_status_timer;
  144. ros::Timer targetDetectedTimer;
  145.  
  146. // records time for delays in sequanced actions, 1 second resolution.
  147. time_t timerStartTime;
  148.  
  149. // An initial delay to allow the rover to gather enough position data to
  150. // average its location.
  151. unsigned int startDelayInSeconds = 1;
  152. float timerTimeElapsed = 0;
  153.  
  154. //Transforms
  155. tf::TransformListener *tfListener;
  156.  
  157. // OS Signal Handler
  158. void sigintEventHandler(int signal);
  159.  
  160. //Callback handlers
  161. void joyCmdHandler(const sensor_msgs::Joy::ConstPtr& message);
  162. void modeHandler(const std_msgs::UInt8::ConstPtr& message);
  163. void targetHandler(const apriltags_ros::AprilTagDetectionArray::ConstPtr& tagInfo);
  164. void obstacleHandler(const std_msgs::UInt8::ConstPtr& message);
  165. void odometryHandler(const nav_msgs::Odometry::ConstPtr& message);
  166. void mapHandler(const nav_msgs::Odometry::ConstPtr& message);
  167. void mobilityStateMachine(const ros::TimerEvent&);
  168. void publishStatusTimerEventHandler(const ros::TimerEvent& event);
  169. void targetDetectedReset(const ros::TimerEvent& event);
  170.  
  171.  
  172. int main(int argc, char **argv) {
  173.  
  174.     gethostname(host, sizeof (host));
  175.     string hostname(host);
  176.  
  177.     // instantiate random number generator
  178.     rng = new random_numbers::RandomNumberGenerator();
  179.  
  180.     //set initial random heading
  181.     goalLocation.theta = rng->uniformReal(0, 2 * M_PI);
  182.  
  183.     //select initial search position 50 cm from center (0,0)
  184.     goalLocation.x = 0.5 * cos(goalLocation.theta+M_PI);
  185.     goalLocation.y = 0.5 * sin(goalLocation.theta+M_PI);
  186.  
  187.     centerLocation.x = 0;
  188.     centerLocation.y = 0;
  189.     centerLocationOdom.x = 0;
  190.     centerLocationOdom.y = 0;
  191.  
  192.     for (int i = 0; i < 100; i++) {
  193.         mapLocation[i].x = 0;
  194.         mapLocation[i].y = 0;
  195.         mapLocation[i].theta = 0;
  196.     }
  197.  
  198.     if (argc >= 2) {
  199.         publishedName = argv[1];
  200.         cout << "Welcome to the world of tomorrow " << publishedName
  201.              << "!  Mobility turnDirectionule started." << endl;
  202.     } else {
  203.         publishedName = hostname;
  204.         cout << "No Name Selected. Default is: " << publishedName << endl;
  205.     }
  206.  
  207.     // NoSignalHandler so we can catch SIGINT ourselves and shutdown the node
  208.     ros::init(argc, argv, (publishedName + "_MOBILITY"), ros::init_options::NoSigintHandler);
  209.     ros::NodeHandle mNH;
  210.  
  211.     // Register the SIGINT event handler so the node can shutdown properly
  212.     signal(SIGINT, sigintEventHandler);
  213.  
  214.     joySubscriber = mNH.subscribe((publishedName + "/joystick"), 10, joyCmdHandler);
  215.     modeSubscriber = mNH.subscribe((publishedName + "/mode"), 1, modeHandler);
  216.     targetSubscriber = mNH.subscribe((publishedName + "/targets"), 10, targetHandler);
  217.     obstacleSubscriber = mNH.subscribe((publishedName + "/obstacle"), 10, obstacleHandler);
  218.     odometrySubscriber = mNH.subscribe((publishedName + "/odom/filtered"), 10, odometryHandler);
  219.     mapSubscriber = mNH.subscribe((publishedName + "/odom/ekf"), 10, mapHandler);
  220.  
  221.     status_publisher = mNH.advertise<std_msgs::String>((publishedName + "/status"), 1, true);
  222.     stateMachinePublish = mNH.advertise<std_msgs::String>((publishedName + "/state_machine"), 1, true);
  223.     fingerAnglePublish = mNH.advertise<std_msgs::Float32>((publishedName + "/fingerAngle/cmd"), 1, true);
  224.     wristAnglePublish = mNH.advertise<std_msgs::Float32>((publishedName + "/wristAngle/cmd"), 1, true);
  225.     infoLogPublisher = mNH.advertise<std_msgs::String>("/infoLog", 1, true);
  226.     driveControlPublish = mNH.advertise<geometry_msgs::Twist>((publishedName + "/driveControl"), 10);
  227.    
  228.     //Making thetaPublish brodcast strings under chatter
  229.     thetaPublish = mNH.advertise<std_msgs::Float32>( (publishedName + "/Theta"), 10);
  230.  
  231.    
  232.     publish_status_timer = mNH.createTimer(ros::Duration(status_publish_interval), publishStatusTimerEventHandler);
  233.     stateMachineTimer = mNH.createTimer(ros::Duration(mobilityLoopTimeStep), mobilityStateMachine);
  234.     targetDetectedTimer = mNH.createTimer(ros::Duration(0), targetDetectedReset, true);
  235.  
  236.     tfListener = new tf::TransformListener();
  237.     std_msgs::String msg;
  238.     msg.data = "Log Started";
  239.     infoLogPublisher.publish(msg);
  240.  
  241.     stringstream ss;
  242.     ss << "Rover start delay set to " << startDelayInSeconds << " seconds";
  243.     msg.data = ss.str();
  244.     infoLogPublisher.publish(msg);
  245.  
  246.     timerStartTime = time(0);
  247.  
  248.     ros::spin();
  249.  
  250.     return EXIT_SUCCESS;
  251. }
  252.  
  253. // This is the top-most logic control block organised as a state machine.
  254. // This function calls the dropOff, pickUp, and search controllers.
  255. // This block passes the goal location to the proportional-integral-derivative
  256. // controllers in the abridge package.
  257. void mobilityStateMachine(const ros::TimerEvent&) {
  258.  
  259.     std_msgs::String stateMachineMsg;
  260.     float rotateOnlyAngleTolerance = 0.4;
  261.     int returnToSearchDelay = 5;
  262.  
  263.     // calls the averaging function, also responsible for
  264.     // transform from Map frame to odom frame.
  265.     mapAverage();
  266.  
  267.     // Robot is in automode
  268.     if (currentMode == 2 || currentMode == 3) {
  269.  
  270.  
  271.         // time since timerStartTime was set to current time
  272.         timerTimeElapsed = time(0) - timerStartTime;
  273.  
  274.         // init code goes here. (code that runs only once at start of
  275.         // auto mode but wont work in main goes here)
  276.         if (!init) {
  277.             if (timerTimeElapsed > startDelayInSeconds) {
  278.                 // Set the location of the center circle location in the map
  279.                 // frame based upon our current average location on the map.
  280.                 centerLocationMap.x = currentLocationAverage.x;
  281.                 centerLocationMap.y = currentLocationAverage.y;
  282.                 centerLocationMap.theta = currentLocationAverage.theta;
  283.  
  284.                 // initialization has run
  285.                 init = true;
  286.             } else {
  287.                 return;
  288.             }
  289.  
  290.         }
  291.  
  292.         // If no collected or detected blocks set fingers
  293.         // to open wide and raised position.
  294.         if (!targetCollected && !targetDetected) {
  295.             // set gripper
  296.             std_msgs::Float32 angle;
  297.  
  298.             // open fingers
  299.             angle.data = M_PI_2;
  300.  
  301.             fingerAnglePublish.publish(angle);
  302.             angle.data = 0;
  303.  
  304.             // raise wrist
  305.             wristAnglePublish.publish(angle);
  306.         }
  307.  
  308.         // Select rotation or translation based on required adjustment
  309.         switch(stateMachineState) {
  310.  
  311.         // If no adjustment needed, select new goal
  312.         case STATE_MACHINE_TRANSFORM: {
  313.             stateMachineMsg.data = "TRANSFORMING";
  314.  
  315.             // If returning with a target
  316.             if (targetCollected && !avoidingObstacle) {
  317.                 // calculate the euclidean distance between
  318.                 // centerLocation and currentLocation
  319.                 dropOffController.setCenterDist(hypot(centerLocation.x - currentLocation.x, centerLocation.y - currentLocation.y));
  320.                 dropOffController.setDataLocations(centerLocation, currentLocation, timerTimeElapsed);
  321.  
  322.                 DropOffResult result = dropOffController.getState();
  323.  
  324.                 if (result.timer) {
  325.                     timerStartTime = time(0);
  326.                     reachedCollectionPoint = true;
  327.                 }
  328.  
  329.                 std_msgs::Float32 angle;
  330.  
  331.                 if (result.fingerAngle != -1) {
  332.                     angle.data = result.fingerAngle;
  333.                     fingerAnglePublish.publish(angle);
  334.                 }
  335.  
  336.                 if (result.wristAngle != -1) {
  337.                     angle.data = result.wristAngle;
  338.                     wristAnglePublish.publish(angle);
  339.                 }
  340.  
  341.                 if (result.reset) {
  342.                     timerStartTime = time(0);
  343.                     targetCollected = false;
  344.                     targetDetected = false;
  345.                     lockTarget = false;
  346.                     sendDriveCommand(0.0,0);
  347.  
  348.                     // move back to transform step
  349.                     stateMachineState = STATE_MACHINE_TRANSFORM;
  350.                     reachedCollectionPoint = false;;
  351.                     centerLocationOdom = currentLocation;
  352.  
  353.                     dropOffController.reset();
  354.                 } else if (result.goalDriving && timerTimeElapsed >= 5 ) {
  355.                     goalLocation = result.centerGoal;
  356.                     stateMachineState = STATE_MACHINE_ROTATE;
  357.                     timerStartTime = time(0);
  358.                 }
  359.                 // we are in precision/timed driving
  360.                 else {
  361.                     goalLocation = currentLocation;
  362.                     sendDriveCommand(result.cmdVel,result.angleError);
  363.                     stateMachineState = STATE_MACHINE_TRANSFORM;
  364.  
  365.                     break;
  366.                 }
  367.             }
  368.             //If angle between current and goal is significant
  369.             //if error in heading is greater than 0.4 radians
  370.             else if (fabs(angles::shortest_angular_distance(currentLocation.theta, goalLocation.theta)) > rotateOnlyAngleTolerance) {
  371.                 stateMachineState = STATE_MACHINE_ROTATE;
  372.                 thetaPublish.publish( (currentLocation.theta ) );
  373.             }
  374.             //If goal has not yet been reached drive and maintane heading
  375.             else if (fabs(angles::shortest_angular_distance(currentLocation.theta, atan2(goalLocation.y - currentLocation.y, goalLocation.x - currentLocation.x))) < M_PI_2) {
  376.                 stateMachineState = STATE_MACHINE_SKID_STEER;
  377.                 thetaPublish.publish( (currentLocation.theta));
  378.             }
  379.             //Otherwise, drop off target and select new random uniform heading
  380.             //If no targets have been detected, assign a new goal
  381.             else if (!targetDetected && timerTimeElapsed > returnToSearchDelay) {
  382.                 goalLocation = searchController.search(currentLocation);
  383.             }
  384.  
  385.             //Purposefully fall through to next case without breaking
  386.         }
  387.  
  388.         // Calculate angle between currentLocation.theta and goalLocation.theta
  389.         // Rotate left or right depending on sign of angle
  390.         // Stay in this state until angle is minimized
  391.         case STATE_MACHINE_ROTATE: {
  392.             stateMachineMsg.data = "ROTATING";
  393.             // Calculate the diffrence between current and desired
  394.             // heading in radians.
  395.             float errorYaw = angles::shortest_angular_distance(currentLocation.theta, goalLocation.theta);
  396.  
  397.             // If angle > 0.4 radians rotate but dont drive forward.
  398.             if (fabs(angles::shortest_angular_distance(currentLocation.theta, goalLocation.theta)) > rotateOnlyAngleTolerance) {
  399.                 // rotate but dont drive  0.05 is to prevent turning in reverse
  400.                 thetaPublish.publish( (currentLocation.theta));
  401.                 sendDriveCommand(0.05, errorYaw);
  402.                 break;
  403.             } else {
  404.                 // move to differential drive step
  405.                 stateMachineState = STATE_MACHINE_SKID_STEER;
  406.                 //fall through on purpose.
  407.             }
  408.         }
  409.  
  410.         // Calculate angle between currentLocation.x/y and goalLocation.x/y
  411.         // Drive forward
  412.         // Stay in this state until angle is at least PI/2
  413.         case STATE_MACHINE_SKID_STEER: {
  414.             stateMachineMsg.data = "SKID_STEER";
  415.  
  416.             // calculate the distance between current and desired heading in radians
  417.             float errorYaw = angles::shortest_angular_distance(currentLocation.theta, goalLocation.theta);
  418.             thetaPublish.publish( (currentLocation.theta));
  419.             // goal not yet reached drive while maintaining proper heading.
  420.             if (fabs(angles::shortest_angular_distance(currentLocation.theta, atan2(goalLocation.y - currentLocation.y, goalLocation.x - currentLocation.x))) < M_PI_2) {
  421.                 // drive and turn simultaniously
  422.                 sendDriveCommand(searchVelocity, errorYaw/2);
  423.                 thetaPublish.publish( (currentLocation.theta));
  424.             }
  425.             // goal is reached but desired heading is still wrong turn only
  426.             else if (fabs(angles::shortest_angular_distance(currentLocation.theta, goalLocation.theta)) > 0.1) {
  427.                  // rotate but dont drive
  428.                 sendDriveCommand(0.0, errorYaw);
  429.                 thetaPublish.publish( (currentLocation.theta));
  430.             }
  431.             else {
  432.                 // stop
  433.                 sendDriveCommand(0.0, 0.0);
  434.                 avoidingObstacle = false;
  435.  
  436.                 // move back to transform step
  437.                 stateMachineState = STATE_MACHINE_TRANSFORM;
  438.             }
  439.  
  440.             break;
  441.         }
  442.  
  443.         case STATE_MACHINE_PICKUP: {
  444.             stateMachineMsg.data = "PICKUP";
  445.  
  446.             PickUpResult result;
  447.  
  448.             // we see a block and have not picked one up yet
  449.             if (targetDetected && !targetCollected) {
  450.                 result = pickUpController.pickUpSelectedTarget(blockBlock);
  451.                 sendDriveCommand(result.cmdVel,result.angleError);
  452.                 std_msgs::Float32 angle;
  453.  
  454.                 if (result.fingerAngle != -1) {
  455.                     angle.data = result.fingerAngle;
  456.                     fingerAnglePublish.publish(angle);
  457.                 }
  458.  
  459.                 if (result.wristAngle != -1) {
  460.                     angle.data = result.wristAngle;
  461.  
  462.                     // raise wrist
  463.                     wristAnglePublish.publish(angle);
  464.                 }
  465.  
  466.                 if (result.giveUp) {
  467.                     targetDetected = false;
  468.                     stateMachineState = STATE_MACHINE_TRANSFORM;
  469.                     sendDriveCommand(0,0);
  470.                     pickUpController.reset();
  471.                 }
  472.  
  473.                 if (result.pickedUp) {
  474.                     pickUpController.reset();
  475.  
  476.                     // assume target has been picked up by gripper
  477.                     targetCollected = true;
  478.                     result.pickedUp = false;
  479.                     stateMachineState = STATE_MACHINE_ROTATE;
  480.  
  481.                     goalLocation.theta = atan2(centerLocationOdom.y - currentLocation.y, centerLocationOdom.x - currentLocation.x);
  482.  
  483.                     // set center as goal position
  484.                     goalLocation.x = centerLocationOdom.x = 0;
  485.                     goalLocation.y = centerLocationOdom.y;
  486.  
  487.                     // lower wrist to avoid ultrasound sensors
  488.                     std_msgs::Float32 angle;
  489.                     angle.data = 0.8;
  490.                     wristAnglePublish.publish(angle);
  491.                     sendDriveCommand(0.0,0);
  492.  
  493.                     return;
  494.                 }
  495.             } else {
  496.                 stateMachineState = STATE_MACHINE_TRANSFORM;
  497.             }
  498.  
  499.             break;
  500.         }
  501.  
  502.         case STATE_MACHINE_DROPOFF: {
  503.             stateMachineMsg.data = "DROPOFF";
  504.             break;
  505.         }
  506.  
  507.         default: {
  508.             break;
  509.         }
  510.  
  511.         } /* end of switch() */
  512.     }
  513.     // mode is NOT auto
  514.     else {
  515.         // publish current state for the operator to see
  516.         stateMachineMsg.data = "WAITING";
  517.     }
  518.  
  519.     // publish state machine string for user, only if it has changed, though
  520.     if (strcmp(stateMachineMsg.data.c_str(), prev_state_machine) != 0) {
  521.         stateMachinePublish.publish(stateMachineMsg);
  522.         sprintf(prev_state_machine, "%s", stateMachineMsg.data.c_str());
  523.     }
  524. }
  525.  
  526. void sendDriveCommand(double linearVel, double angularError)
  527. {
  528.     velocity.linear.x = linearVel,
  529.     velocity.angular.z = angularError;
  530.  
  531.     // publish the drive commands
  532.     driveControlPublish.publish(velocity);
  533. }
  534.  
  535. /*************************
  536.  * ROS CALLBACK HANDLERS *
  537.  *************************/
  538.  
  539. void targetHandler(const apriltags_ros::AprilTagDetectionArray::ConstPtr& message) {
  540.  
  541.     // If in manual mode do not try to automatically pick up the target
  542.     if (currentMode == 1 || currentMode == 0) return;
  543.  
  544.     // if a target is detected and we are looking for center tags
  545.     if (message->detections.size() > 0 && !reachedCollectionPoint) {
  546.         float cameraOffsetCorrection = 0.020; //meters;
  547.  
  548.         centerSeen = false;
  549.         double count = 0;
  550.         double countRight = 0;
  551.         double countLeft = 0;
  552.  
  553.         // this loop is to get the number of center tags
  554.         for (int i = 0; i < message->detections.size(); i++) {
  555.             if (message->detections[i].id == 256) {
  556.                 geometry_msgs::PoseStamped cenPose = message->detections[i].pose;
  557.  
  558.                 // checks if tag is on the right or left side of the image
  559.                 if (cenPose.pose.position.x + cameraOffsetCorrection > 0) {
  560.                     countRight++;
  561.  
  562.                 } else {
  563.                     countLeft++;
  564.                 }
  565.  
  566.                 centerSeen = true;
  567.                 count++;
  568.             }
  569.         }
  570.  
  571.         if (centerSeen && targetCollected) {
  572.             stateMachineState = STATE_MACHINE_TRANSFORM;
  573.             goalLocation = currentLocation;
  574.         }
  575.  
  576.         dropOffController.setDataTargets(count,countLeft,countRight);
  577.  
  578.         // if we see the center and we dont have a target collected
  579.         if (centerSeen && !targetCollected) {
  580.  
  581.             float centeringTurn = 0.15; //radians
  582.             stateMachineState = STATE_MACHINE_TRANSFORM;
  583.  
  584.             // this code keeps the robot from driving over
  585.             // the center when searching for blocks
  586.             if (right) {
  587.                 // turn away from the center to the left if just driving
  588.                 // around/searching.
  589.                 goalLocation.theta += centeringTurn;
  590.             } else {
  591.                 // turn away from the center to the right if just driving
  592.                 // around/searching.
  593.                 goalLocation.theta -= centeringTurn;
  594.             }
  595.  
  596.             // continues an interrupted search
  597.             goalLocation = searchController.continueInterruptedSearch(currentLocation, goalLocation);
  598.  
  599.             targetDetected = false;
  600.             pickUpController.reset();
  601.  
  602.             return;
  603.         }
  604.     }
  605.     // end found target and looking for center tags
  606.  
  607.     // found a target april tag and looking for april cubes;
  608.     // with safety timer at greater than 5 seconds.
  609.     PickUpResult result;
  610.  
  611.     if (message->detections.size() > 0 && !targetCollected && timerTimeElapsed > 5) {
  612.         targetDetected = true;
  613.  
  614.         // pickup state so target handler can take over driving.
  615.         stateMachineState = STATE_MACHINE_PICKUP;
  616.         result = pickUpController.selectTarget(message);
  617.  
  618.         std_msgs::Float32 angle;
  619.  
  620.         if (result.fingerAngle != -1) {
  621.             angle.data = result.fingerAngle;
  622.             fingerAnglePublish.publish(angle);
  623.         }
  624.  
  625.         if (result.wristAngle != -1) {
  626.             angle.data = result.wristAngle;
  627.             wristAnglePublish.publish(angle);
  628.         }
  629.     }
  630. }
  631.  
  632. void modeHandler(const std_msgs::UInt8::ConstPtr& message) {
  633.     currentMode = message->data;
  634.     sendDriveCommand(0.0, 0.0);
  635. }
  636.  
  637. void obstacleHandler(const std_msgs::UInt8::ConstPtr& message) {
  638.     if ((!targetDetected || targetCollected) && (message->data > 0)) {
  639.         // obstacle on right side
  640.         if (message->data == 1) {
  641.             // select new heading 0.2 radians to the left
  642.             goalLocation.theta = currentLocation.theta + 0.6;
  643.             thetaPublish.publish( (currentLocation.theta));
  644.         }
  645.  
  646.         // obstacle in front or on left side
  647.         else if (message->data == 2) {
  648.             // select new heading 0.2 radians to the right
  649.             goalLocation.theta = currentLocation.theta + 0.6;
  650.             thetaPublish.publish( (currentLocation.theta));
  651.         }
  652.  
  653.         // continues an interrupted search
  654.         goalLocation = searchController.continueInterruptedSearch(currentLocation, goalLocation);
  655.  
  656.         // switch to transform state to trigger collision avoidance
  657.         stateMachineState = STATE_MACHINE_ROTATE;
  658.  
  659.         avoidingObstacle = true;
  660.     }
  661.  
  662.     // the front ultrasond is blocked very closely. 0.14m currently
  663.     if (message->data == 4) {
  664.         blockBlock = true;
  665.     } else {
  666.         blockBlock = false;
  667.     }
  668. }
  669.  
  670. void odometryHandler(const nav_msgs::Odometry::ConstPtr& message) {
  671.     //Get (x,y) location directly from pose
  672.     currentLocation.x = message->pose.pose.position.x;
  673.     currentLocation.y = message->pose.pose.position.y;
  674.  
  675.     //Get theta rotation by converting quaternion orientation to pitch/roll/yaw
  676.     tf::Quaternion q(message->pose.pose.orientation.x, message->pose.pose.orientation.y, message->pose.pose.orientation.z, message->pose.pose.orientation.w);
  677.     tf::Matrix3x3 m(q);
  678.     double roll, pitch, yaw;
  679.     m.getRPY(roll, pitch, yaw);
  680.     currentLocation.theta = yaw;
  681. }
  682.  
  683. void mapHandler(const nav_msgs::Odometry::ConstPtr& message) {
  684.     //Get (x,y) location directly from pose
  685.     currentLocationMap.x = message->pose.pose.position.x;
  686.     currentLocationMap.y = message->pose.pose.position.y;
  687.  
  688.     //Get theta rotation by converting quaternion orientation to pitch/roll/yaw
  689.     tf::Quaternion q(message->pose.pose.orientation.x, message->pose.pose.orientation.y, message->pose.pose.orientation.z, message->pose.pose.orientation.w);
  690.     tf::Matrix3x3 m(q);
  691.     double roll, pitch, yaw;
  692.     m.getRPY(roll, pitch, yaw);
  693.     currentLocationMap.theta = yaw;
  694. }
  695.  
  696. void joyCmdHandler(const sensor_msgs::Joy::ConstPtr& message) {
  697.     if (currentMode == 0 || currentMode == 1) {
  698.         sendDriveCommand(abs(message->axes[4]) >= 0.1 ? message->axes[4] : 0, abs(message->axes[3]) >= 0.1 ? message->axes[3] : 0);
  699.     }
  700. }
  701.  
  702.  
  703. void publishStatusTimerEventHandler(const ros::TimerEvent&) {
  704.     std_msgs::String msg;
  705.     msg.data = "online";
  706.     status_publisher.publish(msg);
  707. }
  708.  
  709.  
  710. void targetDetectedReset(const ros::TimerEvent& event) {
  711.     targetDetected = false;
  712.  
  713.     std_msgs::Float32 angle;
  714.     angle.data = 0;
  715.  
  716.     // close fingers
  717.     fingerAnglePublish.publish(angle);
  718.  
  719.     // raise wrist
  720.     wristAnglePublish.publish(angle);
  721. }
  722.  
  723. void sigintEventHandler(int sig) {
  724.     // All the default sigint handler does is call shutdown()
  725.     ros::shutdown();
  726. }
  727.  
  728. void mapAverage() {
  729.     // store currentLocation in the averaging array
  730.     mapLocation[mapCount] = currentLocationMap;
  731.     mapCount++;
  732.  
  733.     if (mapCount >= mapHistorySize) {
  734.         mapCount = 0;
  735.     }
  736.  
  737.     double x = 0;
  738.     double y = 0;
  739.     double theta = 0;
  740.  
  741.     // add up all the positions in the array
  742.     for (int i = 0; i < mapHistorySize; i++) {
  743.         x += mapLocation[i].x;
  744.         y += mapLocation[i].y;
  745.         theta += mapLocation[i].theta;
  746.     }
  747.  
  748.     // find the average
  749.     x = x/mapHistorySize;
  750.     y = y/mapHistorySize;
  751.    
  752.     // Get theta rotation by converting quaternion orientation to pitch/roll/yaw
  753.     theta = theta/100;
  754.     currentLocationAverage.x = x;
  755.     currentLocationAverage.y = y;
  756.     currentLocationAverage.theta = theta;
  757.  
  758.  
  759.     // only run below code if a centerLocation has been set by initilization
  760.     if (init) {
  761.         // map frame
  762.         geometry_msgs::PoseStamped mapPose;
  763.  
  764.         // setup msg to represent the center location in map frame
  765.         mapPose.header.stamp = ros::Time::now();
  766.  
  767.         mapPose.header.frame_id = publishedName + "/map";
  768.         mapPose.pose.orientation = tf::createQuaternionMsgFromRollPitchYaw(0, 0, centerLocationMap.theta);
  769.         mapPose.pose.position.x = centerLocationMap.x;
  770.         mapPose.pose.position.y = centerLocationMap.y;
  771.         geometry_msgs::PoseStamped odomPose;
  772.         string x = "";
  773.  
  774.         try { //attempt to get the transform of the center point in map frame to odom frame.
  775.             tfListener->waitForTransform(publishedName + "/map", publishedName + "/odom", ros::Time::now(), ros::Duration(1.0));
  776.             tfListener->transformPose(publishedName + "/odom", mapPose, odomPose);
  777.         }
  778.  
  779.         catch(tf::TransformException& ex) {
  780.             ROS_INFO("Received an exception trying to transform a point from \"map\" to \"odom\": %s", ex.what());
  781.             x = "Exception thrown " + (string)ex.what();
  782.             std_msgs::String msg;
  783.             stringstream ss;
  784.             ss << "Exception in mapAverage() " + (string)ex.what();
  785.             msg.data = ss.str();
  786.             infoLogPublisher.publish(msg);
  787.         }
  788.  
  789.         // Use the position and orientation provided by the ros transform.
  790.         centerLocation.x = odomPose.pose.position.x; //set centerLocation in odom frame
  791.         centerLocation.y = odomPose.pose.position.y;
  792.  
  793.  
  794.     }
  795.    
  796.  
  797. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement