5 * @brief Module providing communication through ORTE
9 * robot_orte.c 08/04/21
11 * Robot's orte stuffs.
13 * Copyright: (c) 2008-2010 CTU Dragons
14 * CTU FEE - Department of Control Engineering
15 * License: GNU GPL v.2
19 #include <roboorte_robottype.h>
22 #include <movehelper.h>
25 #include "map_handling.h"
26 #include "match-timing.h"
28 #include <can_msg_def.h>
29 #include <actuators.h>
31 #include <lidar_params.h>
33 UL_LOG_CUST(ulogd_robot_orte); /* Log domain name = ulogd + name of the file */
36 #define DBG(format, ...) ul_logdeb(format, ##__VA_ARGS__)
38 #define DBG(format, ...)
42 extern sem_t measurement_received;
44 /* ----------------------------------------------------------------------
45 * PUBLISHER CALLBACKS - GENERIC
46 * ---------------------------------------------------------------------- */
48 void send_ref_pos_cb(const ORTESendInfo *info, void *vinstance,
49 void *sendCallBackParam)
51 struct robot_pos_type *instance = (struct robot_pos_type *)vinstance;
54 *instance = robot.ref_pos;
55 ROBOT_UNLOCK(ref_pos);
58 void send_est_pos_odo_cb(const ORTESendInfo *info, void *vinstance,
59 void *sendCallBackParam)
61 struct robot_pos_type *instance = (struct robot_pos_type *)vinstance;
63 ROBOT_LOCK(est_pos_odo);
64 *instance = robot.est_pos_odo;
65 ROBOT_UNLOCK(est_pos_odo);
68 void send_est_pos_indep_odo_cb(const ORTESendInfo *info, void *vinstance,
69 void *sendCallBackParam)
71 struct robot_pos_type *instance = (struct robot_pos_type *)vinstance;
73 ROBOT_LOCK(est_pos_indep_odo);
74 *instance = robot.est_pos_indep_odo;
75 ROBOT_UNLOCK(est_pos_indep_odo);
78 static void send_est_pos_best_cb(const ORTESendInfo *info, void *vinstance,
79 void *sendCallBackParam)
81 struct robot_pos_type *instance = (struct robot_pos_type *)vinstance;
83 robot_get_est_pos(&instance->x, &instance->y, &instance->phi);
86 void send_dummy_cb(const ORTESendInfo *info, void *vinstance,
87 void *sendCallBackParam)
91 void send_match_time_cb(const ORTESendInfo *info, void *vinstance,
92 void *sendCallBackParam)
94 struct match_time_type *instance = (struct match_time_type *)vinstance;
96 if (robot.start_state == POWER_ON || robot.start_state == START_PLUGGED_IN) {
99 instance->time = 600 - robot_current_time();
102 /* ----------------------------------------------------------------------
103 * SUBSCRIBER CALLBACKS - GENERIC
104 * ---------------------------------------------------------------------- */
105 void rcv_odo_data_cb(const ORTERecvInfo *info, void *vinstance,
106 void *recvCallBackParam)
108 struct odo_data_type *instance = (struct odo_data_type *)vinstance;
109 double dleft, dright, dtang, dphi;
110 static bool first_run = true;
111 /* spocitat prevodovy pomer */
112 const double n = (double)(1.0 / 1.0);
114 /* vzdalenost na pulz IRC */
115 const double c = (M_PI*2*ODOMETRY_WHEEL_RADIUS_M) / (n * 4*4096.0);
117 switch (info->status) {
120 ROBOT_LOCK(odo_data);
121 robot.odo_data = *instance;
122 ROBOT_UNLOCK(odo_data);
127 dleft = ((robot.odo_data.left - instance->left) >> 8) * c * robot.odo_cal_a; // TODO >> 8 ?
128 dright = ((instance->right - robot.odo_data.right) >> 8) * c * robot.odo_cal_b;
130 dtang = (dleft + dright) / 2.0;
131 dphi = (dright - dleft) / (2.0*ODOMETRY_ROTATION_RADIUS_M);
133 ROBOT_LOCK(est_pos_indep_odo);
134 robot.odo_distance_a +=dleft;
135 robot.odo_distance_b +=dright;
136 double a = robot.est_pos_indep_odo.phi;
137 robot.est_pos_indep_odo.x += dtang*cos(a);
138 robot.est_pos_indep_odo.y += dtang*sin(a);
139 robot.est_pos_indep_odo.phi += dphi;
140 ROBOT_UNLOCK(est_pos_indep_odo);
142 ROBOT_LOCK(odo_data);
143 robot.odo_data = *instance;
144 ROBOT_UNLOCK(odo_data);
146 robot.indep_odometry_works = true;
148 /* wake up motion-control/thread_trajectory_follower */
149 sem_post(&measurement_received);
151 //robot.hw_status[COMPONENT_ODO] = STATUS_OK;
154 robot.indep_odometry_works = false;
155 //robot.hw_status[COMPONENT_ODO] = STATUS_FAILED;
156 DBG("ORTE deadline occurred - odo_data receive\n");
161 void rcv_motion_irc_cb(const ORTERecvInfo *info, void *vinstance,
162 void *recvCallBackParam)
164 struct motion_irc_type *instance = (struct motion_irc_type *)vinstance;
165 double dleft, dright, dtang, dphi;
166 static bool first_run = true;
167 /* spocitat prevodovy pomer */
168 const double n = (double)(ROBOT_MOTOR_GEARBOX_RATIO / 1.0);
170 /* vzdalenost na pulz IRC */
171 const double c = (M_PI*2*ROBOT_WHEEL_RADIUS_M) / (n * 4*ROBOT_MOTOR_IRC_RESOLUTION);
172 switch (info->status) {
175 ROBOT_LOCK(motion_irc);
176 robot.motion_irc = *instance;
177 ROBOT_UNLOCK(motion_irc);
183 /* FIXME maybe it is not correct to do this nasty hack here (switch dleft and dright),
184 what is the right solution?
185 This was neccessary to view motor odometry correctly in robomon. */
186 dright = ((robot.motion_irc.left - instance->left) >> 8) * c;
187 dleft = ((instance->right - robot.motion_irc.right) >> 8) * c;
189 dtang = (dleft + dright) / 2.0;
190 dphi = (dright - dleft) / (2.0*ROBOT_ROTATION_RADIUS_M);
192 ROBOT_LOCK(est_pos_odo);
193 double a = robot.est_pos_odo.phi;
194 robot.est_pos_odo.x += dtang*cos(a);
195 robot.est_pos_odo.y += dtang*sin(a);
196 robot.est_pos_odo.phi += dphi;
197 ROBOT_UNLOCK(est_pos_odo);
199 /* locking should not be needed, but... */
200 ROBOT_LOCK(motion_irc);
201 robot.motion_irc = *instance;
202 robot.motion_irc_received = 1;
203 ROBOT_UNLOCK(motion_irc);
205 robot.odometry_works = true;
207 robot.status[COMPONENT_MOTOR] = STATUS_OK;
210 robot.odometry_works = false;
211 robot.status[COMPONENT_MOTOR] = STATUS_FAILED;
212 DBG("ORTE deadline occurred - motion_irc receive\n");
217 void rcv_motion_speed_cb(const ORTERecvInfo *info, void *vinstance,
218 void *recvCallBackParam)
220 switch (info->status) {
224 DBG("ORTE deadline occurred - motion_speed receive\n");
229 void rcv_motion_status_cb(const ORTERecvInfo *info, void *vinstance,
230 void *recvCallBackParam)
232 switch (info->status) {
236 DBG("ORTE deadline occurred - motion_status receive\n");
241 void rcv_pwr_voltage_cb(const ORTERecvInfo *info, void *vinstance,
242 void *recvCallBackParam)
244 switch (info->status) {
246 robot.status[COMPONENT_POWER]=STATUS_OK;
249 robot.status[COMPONENT_POWER]=STATUS_FAILED;
250 DBG("ORTE deadline occurred - pwr_voltage receive\n");
255 void rcv_pwr_ctrl_cb(const ORTERecvInfo *info, void *vinstance,
256 void *recvCallBackParam)
258 switch (info->status) {
262 DBG("ORTE deadline occurred - pwr_ctrl receive\n");
267 void rcv_robot_cmd_cb(const ORTERecvInfo *info, void *vinstance,
268 void *recvCallBackParam)
270 struct robot_cmd_type *instance = (struct robot_cmd_type *)vinstance;
271 static struct robot_cmd_type last_instance;
273 switch (info->status) {
275 /* Stupid way of controlling the robot by
276 * pluggin in and out start connector. */
277 switch (robot.start_state) {
279 if (!instance->start_condition) {
280 robot.status[COMPONENT_START] = STATUS_WARNING;
281 robot.start_state = START_PLUGGED_IN;
282 ul_logmsg("START_PLUGGED_IN\n");
286 case START_PLUGGED_IN:
287 robot.status[COMPONENT_START] = STATUS_OK;
288 /* Competition starts when plugged out */
289 if (instance->start_condition) {
290 FSM_SIGNAL(MAIN, EV_START, NULL);
291 robot.start_state = COMPETITION_STARTED;
292 ul_logmsg("STARTED\n");
296 case COMPETITION_STARTED: {
297 /* Subsequent plug-in stops the robot */
299 if (!instance->start_condition) {
300 robot.status[COMPONENT_START] = STATUS_WARNING;
307 last_instance = *instance;
310 robot.status[COMPONENT_START] = STATUS_FAILED;
311 DBG("ORTE deadline occurred - robot_cmd receive\n");
316 void rcv_hokuyo_scan_cb(const ORTERecvInfo *info, void *vinstance,
317 void *recvCallBackParam)
319 struct lidar_scan_type *instance = (struct lidar_scan_type *)vinstance;
321 switch (info->status) {
324 robot.hokuyo = *instance;
325 robot.status[COMPONENT_HOKUYO] = STATUS_OK;
326 ROBOT_UNLOCK(hokuyo);
327 if(!robot.ignore_hokuyo)
329 //update_map_lidar(&hokuyo_params, instance);
334 robot.status[COMPONENT_HOKUYO] = STATUS_FAILED;
335 //system("killall -9 hokuyo");
336 DBG("%s: ORTE deadline occurred\n", __FUNCTION__);
341 void rcv_sick_scan_cb(const ORTERecvInfo *info, void *vinstance,
342 void *recvCallBackParam)
344 struct lidar_scan_type *instance = (struct lidar_scan_type *)vinstance;
346 switch (info->status) {
349 robot.sick = *instance;
350 robot.status[COMPONENT_SICK] = STATUS_OK;
352 if(!robot.ignore_sick)
354 update_map_lidar(&sick_params, instance);
359 robot.status[COMPONENT_SICK] = STATUS_FAILED;
360 DBG("%s: ORTE deadline occurred\n", __FUNCTION__);
365 void rcv_sick551_scan_cb(const ORTERecvInfo *info, void *vinstance,
366 void *recvCallBackParam)
368 struct lidar_scan_type *instance = (struct lidar_scan_type *)vinstance;
370 switch (info->status) {
373 robot.sick551 = *instance;
374 robot.status[COMPONENT_SICK551] = STATUS_OK;
375 ROBOT_UNLOCK(sick551);
376 if(!robot.ignore_sick551)
378 update_map_lidar(&sick551_params, instance);
383 robot.status[COMPONENT_SICK551] = STATUS_FAILED;
384 DBG("%s: ORTE deadline occurred\n", __FUNCTION__);
389 void rcv_camera_result_cb(const ORTERecvInfo *info, void *vinstance,
390 void *recvCallBackParam)
392 struct camera_result_type *instance = (struct camera_result_type *)vinstance;
393 static bool last_response = false;
395 switch (info->status) {
397 if (instance->data_valid && instance->data_valid != last_response) {
398 ROBOT_LOCK(camera_result);
399 robot.target_valid = instance->target_valid;
400 robot.target_ang = instance->angle_deg;
401 ROBOT_UNLOCK(camera_result);
402 FSM_SIGNAL(MAIN, EV_CAMERA_DONE, NULL);
404 last_response = instance->data_valid;
408 if (robot.orte.camera_control.on) {
409 robot.status[COMPONENT_CAMERA] = STATUS_FAILED;
412 DBG("%s: ORTE deadline occurred\n", __FUNCTION__);
416 /* ----------------------------------------------------------------------
417 * SUBSCRIBER CALLBACKS - EB2008
418 * ---------------------------------------------------------------------- */
420 void rcv_jaws_status_cb(const ORTERecvInfo *info, void *vinstance,
421 void *recvCallBackParam)
423 struct jaws_status_type *instance = (struct jaws_status_type *)vinstance;
424 static int last_response_left = 0;
425 static int last_response_right = 0;
426 switch (info->status) {
428 // new data arrived and requested position equals actual position
429 if (instance->flags.left == 0 &&
430 instance->flags.right == 0)
431 robot.status[COMPONENT_JAWS] = STATUS_OK;
433 robot.status[COMPONENT_JAWS] = STATUS_WARNING;
435 if (instance->response.left != last_response_left &&
436 instance->response.right != last_response_right &&
437 instance->response.left == act_jaw_left_get_last_reqest() &&
438 instance->response.left == act_jaw_right_get_last_reqest())
439 FSM_SIGNAL(MAIN, EV_JAWS_DONE, NULL);
441 last_response_left = instance->response.left;
442 last_response_right = instance->response.right;
445 robot.status[COMPONENT_JAWS] = STATUS_FAILED;
446 DBG("ORTE deadline occurred - actuator_status receive\n");
451 void rcv_lift_status_cb(const ORTERecvInfo *info, void *vinstance,
452 void *recvCallBackParam)
454 struct lift_status_type *instance = (struct lift_status_type *)vinstance;
455 static int last_response = 0;
456 switch (info->status) {
458 // new data arrived and requested position equals actual position
459 if (instance->flags == 0)
460 robot.status[COMPONENT_LIFT] = STATUS_OK;
462 robot.status[COMPONENT_LIFT] = STATUS_WARNING;
464 if (instance->response != last_response &&
465 instance->response == act_lift_get_last_reqest())
466 FSM_SIGNAL(MAIN, EV_LIFT_DONE, NULL);
467 last_response = instance->response;
470 robot.status[COMPONENT_LIFT] = STATUS_FAILED;
471 DBG("ORTE deadline occurred - actuator_status receive\n");
476 void rcv_robot_switches_cb(const ORTERecvInfo *info, void *vinstance,
477 void *recvCallBackParam)
479 struct robot_switches_type *instance = (struct robot_switches_type *)vinstance;
480 static bool last_strategy;
481 switch (info->status) {
483 robot.team_color = instance->team_color;
485 if (!last_strategy && instance->strategy) {
486 /* strategy switching */
487 FSM_SIGNAL(MAIN, EV_SWITCH_STRATEGY, NULL);
489 last_strategy = instance->strategy;
496 void rcv_robot_bumpers_cb(const ORTERecvInfo *info, void *vinstance,
497 void *recvCallBackParam)
499 struct robot_bumpers_type *instance = (struct robot_bumpers_type *)vinstance;
500 static bool last_left, last_right;
501 switch (info->status) {
503 if (instance->bumper_right_across || instance->bumper_left_across || instance->bumper_rear_left || instance->bumper_rear_right)
504 FSM_SIGNAL(MOTION, EV_OBSTACLE_BEHIND, NULL);
506 if (instance->bumper_left || instance->bumper_right) {
507 FSM_SIGNAL(MOTION, EV_OBSTACLE_SIDE, NULL);
515 void rcv_cl_sensor_status_cb(const ORTERecvInfo *info, void *vinstance,
516 void *recvCallBackParam)
518 struct cl_sensor_status_type *instance = (struct cl_sensor_status_type *)vinstance;
519 static bool last_pattern_match = 0;
520 switch (info->status) {
522 if ((last_pattern_match != instance->pattern_match) && instance->pattern_match)
523 FSM_SIGNAL(MAIN, EV_OMRON_DONE, NULL);
525 last_pattern_match = instance->pattern_match;
534 static int cmp_double(const void *v1, const void *v2)
536 const double *d1 = v1, *const d2 = v2;
546 int robot_init_orte()
550 robot.orte.strength = 20;
552 rv = robottype_roboorte_init(&robot.orte);
556 /* creating publishers */
557 robottype_publisher_motion_speed_create(&robot.orte, NULL, &robot.orte);
558 robottype_publisher_ref_pos_create(&robot.orte, send_ref_pos_cb, &robot.orte);
559 robottype_publisher_est_pos_odo_create(&robot.orte, send_est_pos_odo_cb, &robot.orte);
560 robottype_publisher_est_pos_indep_odo_create(&robot.orte, send_est_pos_indep_odo_cb, &robot.orte);
561 robottype_publisher_est_pos_best_create(&robot.orte, send_est_pos_best_cb, &robot.orte);
562 robottype_publisher_match_time_create(&robot.orte, send_match_time_cb, &robot.orte);
563 //???robottype_publisher_pwr_ctrl_create(&robot.orte, NULL, &robot.orte);
565 // I didn't know what was the difference between the callback function pointer
566 // being NULL and being set to pointer to empty send_dummy_cb function. The DIFFERENCE
568 // - NULL: message is published only when OrtePublicationSend called
569 // - pointer to empty function: message is published periodically
570 robottype_publisher_fsm_main_create(&robot.orte, send_dummy_cb, &robot.orte);
571 robottype_publisher_fsm_act_create(&robot.orte, send_dummy_cb, &robot.orte);
572 robottype_publisher_fsm_motion_create(&robot.orte, send_dummy_cb, &robot.orte);
573 robottype_publisher_camera_control_create(&robot.orte, send_dummy_cb, &robot.orte);
574 robottype_publisher_jaws_cmd_create(&robot.orte, send_dummy_cb, &robot.orte);
575 robottype_publisher_lift_cmd_create(&robot.orte, send_dummy_cb, &robot.orte);
577 /* create generic subscribers */
578 robottype_subscriber_odo_data_create(&robot.orte, rcv_odo_data_cb, &robot.orte);
579 robottype_subscriber_motion_irc_create(&robot.orte, rcv_motion_irc_cb, &robot.orte);
580 robottype_subscriber_motion_speed_create(&robot.orte, rcv_motion_speed_cb, &robot.orte);
581 robottype_subscriber_motion_status_create(&robot.orte, rcv_motion_status_cb, &robot.orte);
582 robottype_subscriber_pwr_voltage_create(&robot.orte, rcv_pwr_voltage_cb, &robot.orte);
583 //robottype_subscriber_pwr_ctrl_create(&robot.orte, rcv_pwr_ctrl_cb, &robot.orte);
584 robottype_subscriber_robot_cmd_create(&robot.orte, rcv_robot_cmd_cb, &robot.orte);
585 robottype_subscriber_sick_scan_create(&robot.orte, rcv_sick_scan_cb, &robot.orte);
586 robottype_subscriber_jaws_status_create(&robot.orte, rcv_jaws_status_cb, &robot.orte);
587 robottype_subscriber_lift_status_create(&robot.orte, rcv_lift_status_cb, &robot.orte);
588 robottype_subscriber_robot_switches_create(&robot.orte, rcv_robot_switches_cb, &robot.orte);
589 robottype_subscriber_robot_bumpers_create(&robot.orte, rcv_robot_bumpers_cb, &robot.orte);
590 robottype_subscriber_camera_result_create(&robot.orte, rcv_camera_result_cb, &robot.orte);
591 robottype_subscriber_cl_sensor_status_create(&robot.orte, rcv_cl_sensor_status_cb, &robot.orte);