1 #ifndef COMMON_STATES_H
2 #define COMMON_STATES_H
9 #include <movehelper.h>
19 #include <shape_detect.h>
22 #include "actuators.h"
23 #include "state_defines.h"
26 std::vector<robot_pos_type> detected_target;
29 * Safe distance for target recognition
31 const double approach_radius = TARGET_RADIUS_M + 3.0*MAP_CELL_SIZE_M + ROBOT_DIAGONAL_RADIUS_M;
33 static bool detect_target();
34 bool goal_is_in_playground(double goalx, double goaly);
35 bool close_goal(double goalx, double goaly);
36 void get_approach_point(double xtarget, double ytarget, double *xapproach, double *yapproach, double *phi_approach);
37 double get_approach_angle(double xtarget, double ytarget);
39 bool goal_is_in_playground(double goalx, double goaly)
41 if ((goalx < 0) || (goalx > PLAYGROUND_WIDTH_M) || (goaly < 0) || (goaly > PLAYGROUND_HEIGHT_M))
47 /* Check if the new point is close to the robot */
48 bool close_goal(double goalx, double goaly)
50 const double close = 0.5;
52 robot.get_est_pos(x, y, phi);
54 if ((abs(goalx - x) < close) && (abs(goaly - y) < close) )
61 * Take data from hokuyo and run shape detection on it.
63 * Absolute positions of all detected targets centers are stored in alobal variable (vector).
65 * @return True if at least one target detected, else false.
67 static bool detect_target()
69 struct hokuyo_scan_type hokuyo = robot.hokuyo;
72 std::vector<Shape_detect::Arc> arcs;
73 sd.prepare(hokuyo.data);
77 detected_target.clear();
79 if (arcs.size() > 0) {
80 robot_pos_type e, target, hok;
82 robot.get_est_pos(e.x, e.y, e.phi);
84 double sinus = sin(e.phi);
85 double cosinus = cos(e.phi);
87 // save absolute positions of all detected targets
88 for (int i = 0; i < arcs.size(); i++) {
89 Shape_detect::Arc *a = &arcs[i];
91 hok.x = HOKUYO_CENTER_OFFSET_M + (double)a->center.x / 1000.0;
92 hok.y = (double)a->center.y / 1000.0;
94 /* transform target position which is relative to Hokuyo
95 center to absolute position in space */
96 target.x = (hok.x * cosinus) - (hok.y * sinus) + e.x;
97 target.y = (hok.x * sinus) + (hok.y * cosinus) + e.y;
99 // filter those targets not in playground range
100 if (goal_is_in_playground(target.x, target.y))
101 detected_target.push_back(target);
104 return detected_target.size();
108 * Calculates point to approach the target.
110 * @param target Position of the center of the target.
111 * @param approach Pointer to the the intersection point of circle around
112 * the target and line between robot center and target.
114 void get_approach_point(double xtarget, double ytarget, double *xapproach, double *yapproach, double *phi_approach)
116 double xrobot, yrobot, phi;
119 robot.get_est_pos(xrobot, yrobot, phi);
121 delta = distance(xrobot, yrobot, xtarget, ytarget);
123 *xapproach = xtarget - (approach_radius * (xtarget - xrobot) / delta);
124 *yapproach = ytarget - (approach_radius * (ytarget - yrobot) / delta);
126 *phi_approach = get_approach_angle(xtarget, ytarget);
130 * Calculates point to approach the target.
132 * @param target Position of the center of the target.
133 * @return Angle to approach the target form.
135 double get_approach_angle(double xtarget, double ytarget)
137 double xrobot, yrobot,phi;
139 robot.get_est_pos(xrobot, yrobot, phi);
141 return atan2((ytarget - yrobot), (xtarget - xrobot));
146 * FSM state for neighborhood observation.
148 * Detect targets using shape_detect.
149 * If no target detected, turn 120deg and try again.
150 * Scan all 360deg and then go back to move_around state.
152 * If target detected, go to approach_target state.
154 struct survey : TimedSimpleState<survey, competing> {
165 sc::result react(const evTimer& ) {
167 return transit<move_around>();
170 return discard_event();
173 sc::result react(const evMotionDone&) {
174 runTimer(t,1000, new evTimer());
175 return discard_event();
179 sc::custom_reaction<evTimer>,
180 sc::custom_reaction<evMotionDone>,
181 sc::transition<evMotionError, move_around>,
182 sc::transition<evTargetDetected, approach_target> > reactions;
184 // DBG_PRINT_EVENT("survey");
185 #if 1 // FIXME just for test
186 if (detect_target()) {
189 robot_pos_type target;
190 detected_target.clear();
191 for (double i = 1; i < 5; i++) {
194 detected_target.push_back(target);
197 // target detected, go to the target
198 robot.sched.queue_event(robot.MAIN, new evTargetDetected());
199 // DBG_PRINT_EVENT("Target detected!");
201 // no target detected in this heading, turn 120°
202 robot.get_est_pos(x, y, phi);
203 robot.move_helper.goto_notrans(x, y, TURN(DEG2RAD(120)+phi), &tcSlow);
205 // DBG_PRINT_EVENT("no target");
211 * FSM state for approaching all detected targets.
213 * Try to approach target.
214 * If approach OK - go to subautomaton and do target recognition, touch and load.
215 * On subautomaton return check if target loaded/valid.
217 * If target loaded, go home.
218 * If target not valid, try next target if any.
219 * If approach not succesfull - go to move_around state.
221 struct approach_target : TimedSimpleState<approach_target, competing, recognize_init> {
224 double x_target, y_tatget;
225 double x_approach, y_approach, phi_approach;
228 // DBG_PRINT_EVENT("approaching target");
235 sc::result react(const evMotionDone&) {
236 // DBG_PRINT_EVENT("target approached");
237 robot.sched.queue_event(robot.MAIN, new evRunSubFSM());
238 return discard_event();
240 sc::result react(const evReturn&) {
241 if (robot.target_loaded) {
242 return transit<go_home>();
243 } else if (robot.target_valid) {
244 //FIXME target is valid but not loaded - try another approach direction
245 return discard_event();
246 } else if (!robot.target_valid && (target_cntr < max_target)) {
247 // go for next target if any
249 return discard_event();
251 // go to new point and survey
252 return transit<move_around>();
255 sc::result react (const evMotionError&) {
256 // DBG_PRINT_EVENT("can not approach target");
257 if (target_cntr < max_target) {
258 return transit<approach_target>();
260 return transit<move_around>();
264 sc::custom_reaction<evMotionDone>,
265 sc::custom_reaction<evReturn>,
266 sc::custom_reaction<evMotionError> > reactions;
268 max_target = detected_target.size();
269 x_target = detected_target[target_cntr].x;
270 y_tatget = detected_target[target_cntr].y;
272 printf("target %d / %d\n", target_cntr, max_target);
274 get_approach_point(x_target, y_tatget, &x_approach, &y_approach, &phi_approach);
275 robot.move_helper.goto_notrans(x_approach, y_approach, ARRIVE_FROM(phi_approach, 0.1), &tcSlow);
279 struct move_around : TimedSimpleState<move_around, competing> {
283 goalx = ((rand()%PLAYGROUND_HEIGHT_MM)/1000.0);
284 goaly += ((rand()%PLAYGROUND_WIDTH_MM)/1000.0);
285 } while (!ShmapIsFreePoint(goalx, goaly) && close_goal(goalx, goaly));
286 robot.move_helper.goto_notrans(goalx, goaly, NO_TURN(), &tcSlow);
287 // DBG_PRINT_EVENT("new survey point");
289 sc::result react(const evMotionError&) {
290 // DBG_PRINT_EVENT("can not access survey point");
291 return transit<survey>();
294 sc::transition<evMotionDone, survey>,
295 sc::custom_reaction<evMotionError> > reactions;
298 struct go_home: TimedSimpleState< go_home, competing> {
301 //DBG_PRINT_EVENT("homing");
302 robot.move_helper.goto_notrans(HOME_POS_X_M, HOME_POS_Y_M, ARRIVE_FROM(DEG2RAD(HOME_POS_ANG_DEG), 0.2), &tcSlow);
304 sc::result react(const evMotionError& ) {
305 //DBG_PRINT_EVENT("ERROR: home position is not reachable!");
306 runTimer(t, 1000, new evTimer());
307 return discard_event();
309 sc::result react (const evMotionDone&) {
310 //DBG_PRINT_EVENT("Mission completed!");
312 return discard_event();
315 sc::custom_reaction<evMotionError>,
316 sc::custom_reaction<evMotionDone>,
317 sc::transition<evTimer, go_home>