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"
27 #include <can_msg_def.h>
28 #include <actuators.h>
31 UL_LOG_CUST(ulogd_robot_orte); /* Log domain name = ulogd + name of the file */
34 #define DBG(format, ...) ul_logdeb(format, ##__VA_ARGS__)
36 #define DBG(format, ...)
40 extern sem_t measurement_received;
43 * Check rrobot component status
44 * @return zero if system OK, else 1
46 int check_prestart_status()
48 if ((robot.status[COMPONENT_MOTOR] == STATUS_FAILED) || (robot.status[COMPONENT_MOTOR] == STATUS_WARNING)) {
50 } else if (robot.status[COMPONENT_ODOMETRY] == STATUS_FAILED) {
52 } else if ((robot.status[COMPONENT_CAMERA] == STATUS_FAILED) || (robot.status[COMPONENT_CAMERA] == STATUS_WARNING)) {
54 } else if (robot.status[COMPONENT_POWER] == STATUS_FAILED) {
56 } else if (robot.status[COMPONENT_HOKUYO] == STATUS_FAILED) {
58 } else if (robot.status[COMPONENT_CRANE] == STATUS_FAILED) {
60 } else if (robot.status[COMPONENT_START] == STATUS_FAILED || robot.status[COMPONENT_START] == STATUS_WARNING) {
66 /* ----------------------------------------------------------------------
67 * PUBLISHER CALLBACKS - GENERIC
68 * ---------------------------------------------------------------------- */
70 void send_ref_pos_cb(const ORTESendInfo *info, void *vinstance,
71 void *sendCallBackParam)
73 struct robot_pos_type *instance = (struct robot_pos_type *)vinstance;
76 *instance = robot.ref_pos;
77 ROBOT_UNLOCK(ref_pos);
80 void send_est_pos_odo_cb(const ORTESendInfo *info, void *vinstance,
81 void *sendCallBackParam)
83 struct robot_pos_type *instance = (struct robot_pos_type *)vinstance;
85 ROBOT_LOCK(est_pos_odo);
86 *instance = robot.est_pos_odo;
87 ROBOT_UNLOCK(est_pos_odo);
90 void send_est_pos_indep_odo_cb(const ORTESendInfo *info, void *vinstance,
91 void *sendCallBackParam)
93 struct robot_pos_type *instance = (struct robot_pos_type *)vinstance;
95 ROBOT_LOCK(est_pos_indep_odo);
96 *instance = robot.est_pos_indep_odo;
97 ROBOT_UNLOCK(est_pos_indep_odo);
100 static void send_est_pos_best_cb(const ORTESendInfo *info, void *vinstance,
101 void *sendCallBackParam)
103 struct robot_pos_type *instance = (struct robot_pos_type *)vinstance;
105 robot_get_est_pos(&instance->x, &instance->y, &instance->phi);
108 static void send_system_status_cb(const ORTESendInfo *info, void *vinstance,
109 void *sendCallBackParam)
111 system_status *instance = (system_status *)vinstance;
113 /* if any component not ready, send warning for display to show APP yellow */
114 if (check_prestart_status()) {
115 instance->system_condition = 1; // system warning
117 instance->system_condition = 0; // system OK
121 void send_dummy_cb(const ORTESendInfo *info, void *vinstance,
122 void *sendCallBackParam)
126 /* ----------------------------------------------------------------------
127 * SUBSCRIBER CALLBACKS - GENERIC
128 * ---------------------------------------------------------------------- */
129 void rcv_odo_data_cb(const ORTERecvInfo *info, void *vinstance,
130 void *recvCallBackParam)
132 struct odo_data_type *instance = (struct odo_data_type *)vinstance;
133 double dleft, dright, dtang, dphi;
134 static bool first_run = true;
135 /* spocitat prevodovy pomer */
136 const double n = (double)(1.0 / 1.0);
138 /* vzdalenost na pulz IRC */
139 const double c = (M_PI*2*ODOMETRY_WHEEL_RADIUS_M) / (n * 4*4096.0);
141 switch (info->status) {
144 ROBOT_LOCK(odo_data);
145 robot.odo_data = *instance;
146 ROBOT_UNLOCK(odo_data);
151 dleft = ((robot.odo_data.left - instance->left) >> 8) * c; // TODO >> 8 ?
152 dright = ((instance->right - robot.odo_data.right) >> 8) * c;
154 dtang = (dleft + dright) / 2.0;
155 dphi = (dright - dleft) / (2.0*ODOMETRY_ROTATION_RADIUS_M);
157 ROBOT_LOCK(est_pos_indep_odo);
158 double a = robot.est_pos_indep_odo.phi;
159 robot.est_pos_indep_odo.x += dtang*cos(a);
160 robot.est_pos_indep_odo.y += dtang*sin(a);
161 robot.est_pos_indep_odo.phi += dphi;
162 ROBOT_UNLOCK(est_pos_indep_odo);
164 ROBOT_LOCK(odo_data);
165 robot.odo_data = *instance;
166 ROBOT_UNLOCK(odo_data);
168 robot.indep_odometry_works = true;
170 /* wake up motion-control/thread_trajectory_follower */
171 sem_post(&measurement_received);
173 robot.status[COMPONENT_ODOMETRY] = STATUS_OK;
176 robot.indep_odometry_works = false;
177 robot.status[COMPONENT_ODOMETRY] = STATUS_FAILED;
178 DBG("ORTE deadline occurred - odo_data receive\n");
183 void rcv_motion_irc_cb(const ORTERecvInfo *info, void *vinstance,
184 void *recvCallBackParam)
186 struct motion_irc_type *instance = (struct motion_irc_type *)vinstance;
187 double dleft, dright, dtang, dphi;
188 static bool first_run = true;
189 /* spocitat prevodovy pomer */
190 const double n = (double)(28.0 / 1.0);
192 /* vzdalenost na pulz IRC */
193 const double c = (M_PI*2*ROBOT_WHEEL_RADIUS_M) / (n * 4*500.0);
195 switch (info->status) {
198 ROBOT_LOCK(motion_irc);
199 robot.motion_irc = *instance;
200 ROBOT_UNLOCK(motion_irc);
205 dleft = ((robot.motion_irc.left - instance->left) >> 8) * c;
206 dright = ((instance->right - robot.motion_irc.right) >> 8) * c;
208 dtang = (dleft + dright) / 2.0;
209 dphi = (dright - dleft) / (2.0*ROBOT_ROTATION_RADIUS_M);
211 ROBOT_LOCK(est_pos_odo);
212 double a = robot.est_pos_odo.phi;
213 robot.est_pos_odo.x += dtang*cos(a);
214 robot.est_pos_odo.y += dtang*sin(a);
215 robot.est_pos_odo.phi += dphi;
216 ROBOT_UNLOCK(est_pos_odo);
218 /* locking should not be needed, but... */
219 ROBOT_LOCK(motion_irc);
220 robot.motion_irc = *instance;
221 robot.motion_irc_received = 1;
222 ROBOT_UNLOCK(motion_irc);
224 robot.odometry_works = true;
226 //robot.status[COMPONENT_MOTOR] = STATUS_OK;
229 robot.odometry_works = false;
230 robot.status[COMPONENT_MOTOR] = STATUS_FAILED;
231 DBG("ORTE deadline occurred - motion_irc receive\n");
236 void rcv_motion_speed_cb(const ORTERecvInfo *info, void *vinstance,
237 void *recvCallBackParam)
239 switch (info->status) {
243 DBG("ORTE deadline occurred - motion_speed receive\n");
248 void rcv_motion_status_cb(const ORTERecvInfo *info, void *vinstance,
249 void *recvCallBackParam)
251 struct motion_status_type *m = (struct motion_status_type *)vinstance;
253 switch (info->status) {
255 if (m->err_left == 0 && m->err_right == 0)
256 robot.status[COMPONENT_MOTOR] = STATUS_OK;
258 robot.status[COMPONENT_MOTOR] = STATUS_WARNING;
261 DBG("ORTE deadline occurred - motion_status receive\n");
266 void rcv_pwr_voltage_cb(const ORTERecvInfo *info, void *vinstance,
267 void *recvCallBackParam)
269 switch (info->status) {
271 robot.status[COMPONENT_POWER]=STATUS_OK;
274 robot.status[COMPONENT_POWER]=STATUS_FAILED;
275 DBG("ORTE deadline occurred - pwr_voltage receive\n");
280 void rcv_pwr_ctrl_cb(const ORTERecvInfo *info, void *vinstance,
281 void *recvCallBackParam)
283 switch (info->status) {
287 DBG("ORTE deadline occurred - pwr_ctrl receive\n");
292 void rcv_robot_cmd_cb(const ORTERecvInfo *info, void *vinstance,
293 void *recvCallBackParam)
295 struct robot_cmd_type *instance = (struct robot_cmd_type *)vinstance;
296 static struct robot_cmd_type last_instance;
298 switch (info->status) {
300 /* Stupid way of controlling the robot by
301 * pluggin in and out start connector. */
302 switch (robot.start_state) {
304 robot.status[COMPONENT_START] = STATUS_WARNING;
305 if (instance->start_condition == START_PLUGGED_IN) {
306 robot.start_state = START_PLUGGED_IN;
307 ul_logmsg("START_PLUGGED_IN\n");
311 case START_PLUGGED_IN:
312 robot.status[COMPONENT_START] = STATUS_OK;
313 /* Competition starts when plugged out, check component status before start */
314 if ((instance->start_condition == COMPETITION_STARTED) && !check_prestart_status()) {
315 FSM_SIGNAL(MAIN, EV_START, NULL);
316 robot.start_state = COMPETITION_STARTED;
317 ul_logmsg("STARTED\n");
321 case COMPETITION_STARTED: {
322 robot.status[COMPONENT_START] = STATUS_WARNING;
323 /* Subsequent plug-in stops the robot */
325 if (instance->start_condition == START_PLUGGED_IN) {
332 last_instance = *instance;
335 robot.status[COMPONENT_START] = STATUS_FAILED;
336 DBG("ORTE deadline occurred - robot_cmd receive\n");
341 void rcv_hokuyo_scan_cb(const ORTERecvInfo *info, void *vinstance,
342 void *recvCallBackParam)
344 struct hokuyo_scan_type *instance = (struct hokuyo_scan_type *)vinstance;
346 switch (info->status) {
349 robot.hokuyo = *instance;
350 robot.status[COMPONENT_HOKUYO] = STATUS_OK;
351 ROBOT_UNLOCK(hokuyo);
352 if(!robot.ignore_hokuyo)
354 update_map_hokuyo(instance);
359 robot.status[COMPONENT_HOKUYO] = STATUS_FAILED;
360 //system("killall -9 hokuyo");
361 DBG("%s: ORTE deadline occurred\n", __FUNCTION__);
366 void rcv_camera_result_cb(const ORTERecvInfo *info, void *vinstance,
367 void *recvCallBackParam)
369 struct camera_result_type *instance = (struct camera_result_type *)vinstance;
370 static bool last_response = false;
372 switch (info->status) {
374 if (instance->error) {
375 robot.status[COMPONENT_CAMERA] = STATUS_FAILED;
376 } else if (instance->data_valid && instance->data_valid != last_response) {
377 ROBOT_LOCK(camera_result);
378 robot.target_valid = instance->target_valid;
379 ROBOT_UNLOCK(camera_result);
380 FSM_SIGNAL(MAIN, EV_CAMERA_DONE, NULL);
381 printf("robot_orte: valid: %d\n", instance->target_valid);
383 robot.status[COMPONENT_CAMERA] = STATUS_OK;
385 last_response = instance->data_valid;
389 if (robot.orte.camera_control.on) {
390 robot.status[COMPONENT_CAMERA] = STATUS_FAILED;
391 //system("killall -9 rozpuk");
394 DBG("%s: ORTE deadline occurred\n", __FUNCTION__);
399 void rcv_crane_status_cb(const ORTERecvInfo *info, void *vinstance,
400 void *recvCallBackParam)
402 struct crane_status_type *instance = (struct crane_status_type *)vinstance;
403 static int last_response = 0;
404 switch (info->status) {
406 // new data arrived and requested position equals actual position
407 if (instance->flags == 0)
408 robot.status[COMPONENT_CRANE]=STATUS_OK;
410 robot.status[COMPONENT_CRANE]=STATUS_WARNING;
412 if (instance->response != last_response &&
413 instance->response == act_crane_get_last_reqest())
414 FSM_SIGNAL(MAIN, EV_CRANE_DONE, NULL);
415 last_response = instance->response;
418 robot.status[COMPONENT_CRANE]=STATUS_FAILED;
419 DBG("ORTE deadline occurred - actuator_status receive\n");
424 void rcv_robot_switches_cb(const ORTERecvInfo *info, void *vinstance,
425 void *recvCallBackParam)
427 struct robot_switches_type *instance = (struct robot_switches_type *)vinstance;
428 static bool last_strategy;
429 switch (info->status) {
431 if ((!last_strategy && instance->strategy) && (robot.start_state == POWER_ON)) {
432 FSM_SIGNAL(MAIN, EV_SWITCH_STRATEGY, NULL);
434 last_strategy = instance->strategy;
441 void rcv_robot_bumpers_cb(const ORTERecvInfo *info, void *vinstance,
442 void *recvCallBackParam)
444 struct robot_bumpers_type *instance = (struct robot_bumpers_type *)vinstance;
445 switch (info->status) {
447 if (!instance->bumper_rear) {
448 FSM_SIGNAL(MOTION, EV_OBSTACLE_BEHIND, NULL);
450 if ((!instance->bumper_left) ||
451 (!instance->bumper_right)) {
452 FSM_SIGNAL(MOTION, EV_OBSTACLE_SIDE, NULL);
463 static int cmp_double(const void *v1, const void *v2)
465 const double *d1 = v1, *const d2 = v2;
475 int robot_init_orte()
479 robot.orte.strength = 20;
481 rv = robottype_roboorte_init(&robot.orte);
485 /* creating publishers */
486 robottype_publisher_motion_speed_create(&robot.orte, NULL, &robot.orte);
487 robottype_publisher_ref_pos_create(&robot.orte, send_ref_pos_cb, &robot.orte);
488 robottype_publisher_est_pos_odo_create(&robot.orte, send_est_pos_odo_cb, &robot.orte);
489 robottype_publisher_est_pos_indep_odo_create(&robot.orte, send_est_pos_indep_odo_cb, &robot.orte);
490 robottype_publisher_est_pos_best_create(&robot.orte, send_est_pos_best_cb, &robot.orte);
491 robottype_publisher_system_status_create(&robot.orte, send_system_status_cb, &robot.orte);
492 //???robottype_publisher_pwr_ctrl_create(&robot.orte, NULL, &robot.orte);
494 // I didn't know what was the difference between the callback function pointer
495 // being NULL and being set to pointer to empty send_dummy_cb function. The DIFFERENCE
497 // - NULL: message is published only when OrtePublicationSend called
498 // - pointer to empty function: message is published periodically
499 robottype_publisher_fsm_main_create(&robot.orte, send_dummy_cb, &robot.orte);
500 robottype_publisher_fsm_act_create(&robot.orte, send_dummy_cb, &robot.orte);
501 robottype_publisher_fsm_motion_create(&robot.orte, send_dummy_cb, &robot.orte);
502 robottype_publisher_camera_control_create(&robot.orte, send_dummy_cb, &robot.orte);
503 robottype_publisher_crane_cmd_create(&robot.orte, send_dummy_cb, &robot.orte);
504 robottype_publisher_magnet_cmd_create(&robot.orte, send_dummy_cb, &robot.orte);
506 /* create generic subscribers */
507 robottype_subscriber_odo_data_create(&robot.orte, rcv_odo_data_cb, &robot.orte);
508 robottype_subscriber_motion_irc_create(&robot.orte, rcv_motion_irc_cb, &robot.orte);
509 robottype_subscriber_motion_speed_create(&robot.orte, rcv_motion_speed_cb, &robot.orte);
510 robottype_subscriber_motion_status_create(&robot.orte, rcv_motion_status_cb, &robot.orte);
511 robottype_subscriber_pwr_voltage_create(&robot.orte, rcv_pwr_voltage_cb, &robot.orte);
512 //robottype_subscriber_pwr_ctrl_create(&robot.orte, rcv_pwr_ctrl_cb, &robot.orte);
513 robottype_subscriber_robot_cmd_create(&robot.orte, rcv_robot_cmd_cb, &robot.orte);
514 robottype_subscriber_hokuyo_scan_create(&robot.orte, rcv_hokuyo_scan_cb, &robot.orte);
515 robottype_subscriber_crane_status_create(&robot.orte, rcv_crane_status_cb, &robot.orte);
516 robottype_subscriber_robot_switches_create(&robot.orte, rcv_robot_switches_cb, &robot.orte);
517 robottype_subscriber_robot_bumpers_create(&robot.orte, rcv_robot_bumpers_cb, &robot.orte);
518 robottype_subscriber_camera_result_create(&robot.orte, rcv_camera_result_cb, &robot.orte);