]> rtime.felk.cvut.cz Git - eurobot/public.git/blob - src/robomon/RobomonAtlantis.cpp
Merge branch 'master' of benesp7@rtime.felk.cvut.cz:/var/git/eurobot
[eurobot/public.git] / src / robomon / RobomonAtlantis.cpp
1 /*
2  * RobomonAtlantis.cpp                  07/10/31
3  *
4  * Robot`s visualization and control GUI for robot of the
5  * Eurobot 2008 (Mission to Mars).
6  *
7  * Copyright: (c) 2008 CTU Dragons
8  *            CTU FEE - Department of Control Engineering
9  * Authors: Martin Zidek, Michal Sojka, Tran Duy Khanh
10  * License: GNU GPL v.2
11  */
12
13 #include <QtGui>
14 #include <queue>
15 #include <cstdlib>
16 #include <sys/shm.h>
17 #include <sys/stat.h>
18 #include <sys/socket.h>
19 #include <netinet/in.h>
20 #include <arpa/inet.h>
21 #include <stdio.h>
22 #include <unistd.h>
23 #include <math.h>
24
25 #include <orte.h>
26 #include <path_planner.h>
27 #include <robodim.h>
28 #include <sharp.h>
29 #include <trgen.h>
30 #include <map.h>
31 #include <robomath.h>
32 #include <hokuyo.h>
33 #include <actuators.h>
34 #include "PlaygroundScene.h"
35 #include "MiscGui.h"
36 #include "robomon_orte.h"
37 #include "RobomonAtlantis.h"
38
39 #include <QCoreApplication>
40 #include <QEvent>
41 #include <QKeyEvent>
42 #include <QDebug>
43 #include <QMessageBox>
44
45 RobomonAtlantis::RobomonAtlantis(QWidget *parent)
46         : QWidget(parent)
47 {
48         QFont font;
49         font.setPointSize(7);
50         setFont(font);
51
52         debugWindowEnabled = false;
53
54         createLeftLayout();
55         createRightLayout();
56
57         QHBoxLayout *mainLayout = new QHBoxLayout;
58         mainLayout->addLayout(leftLayout);
59         mainLayout->addLayout(rightLayout);
60         setLayout(mainLayout);
61
62         createOrte();
63         createRobots();
64         createActions();
65
66         setFocusPolicy(Qt::StrongFocus);
67         sharedMemoryOpened = false;
68         WDBG("Youuuhouuuu!!");
69 }
70
71 /**********************************************************************
72  * GUI
73  **********************************************************************/
74 void RobomonAtlantis::createLeftLayout()
75 {
76         leftLayout = new QVBoxLayout();
77         
78         createDebugGroupBox();
79         debugWindowEnabled = true;
80         createPlaygroundGroupBox();
81
82         leftLayout->addWidget(playgroundGroupBox);
83         leftLayout->addWidget(debugGroupBox);
84 }
85
86 void RobomonAtlantis::createRightLayout()
87 {
88         rightLayout = new QVBoxLayout();
89         QGridLayout *layout = new QGridLayout();
90         QVBoxLayout *vlayout = new QVBoxLayout();
91         
92         createPositionGroupBox();
93         createMiscGroupBox();
94         createActuatorsGroupBox();
95         createDIOGroupBox();
96         createPowerGroupBox();
97         createSensorsGroupBox();
98
99         vlayout->addWidget(positionGroupBox);
100         vlayout->addWidget(miscGroupBox);
101         layout->addLayout(vlayout, 0, 0);
102         layout->addWidget(actuatorsGroupBox, 0, 1);
103 //      layout->addWidget(dioGroupBox, 0, 2);
104
105         rightLayout->addLayout(layout);
106         rightLayout->addWidget(powerGroupBox);
107         rightLayout->addWidget(sensorsGroupBox);
108 }
109
110 void RobomonAtlantis::createPlaygroundGroupBox()
111 {
112         playgroundGroupBox = new QGroupBox(tr("Playground"));
113         QHBoxLayout *layout = new QHBoxLayout();
114
115         playgroundScene = 
116                 new PlaygroundScene(PlaygroundScene::PLAYGROUND_EUROBOT2008);
117         playgroundSceneView = new QGraphicsView(playgroundScene);
118         playgroundSceneView->setMinimumWidth((int)(playgroundScene->width())+15);
119         playgroundSceneView->setMinimumHeight((int)(playgroundScene->height())+15);
120         layout->addWidget(playgroundSceneView);
121
122         playgroundGroupBox->setLayout(layout);
123 }
124
125 void RobomonAtlantis::createPositionGroupBox()
126 {
127         positionGroupBox = new QGroupBox(tr("Position state"));
128         QGridLayout *layout = new QGridLayout();
129
130         actPosX = new QLineEdit();
131         actPosY = new QLineEdit();
132         actPosPhi = new QLineEdit();
133
134         estPosX = new QLineEdit();
135         estPosY = new QLineEdit();
136         estPosPhi = new QLineEdit();
137         
138         actPosX->setReadOnly(true);
139         actPosY->setReadOnly(true);
140         actPosPhi->setReadOnly(true);
141
142         estPosX->setReadOnly(true);
143         estPosY->setReadOnly(true);
144         estPosPhi->setReadOnly(true);
145
146         layout->addWidget(MiscGui::createLabel("X"), 1, 0);
147         layout->addWidget(MiscGui::createLabel("Y"), 2, 0);
148         layout->addWidget(MiscGui::createLabel("Phi"), 3, 0);
149
150         layout->addWidget(MiscGui::createLabel("X"), 5, 0);
151         layout->addWidget(MiscGui::createLabel("Y"), 6, 0);
152         layout->addWidget(MiscGui::createLabel("Phi"), 7, 0);
153
154         layout->addWidget(MiscGui::createLabel("Actual", Qt::AlignLeft), 0, 1);
155         layout->addWidget(actPosX, 1, 1);
156         layout->addWidget(actPosY, 2, 1);
157         layout->addWidget(actPosPhi, 3, 1);
158
159         layout->addWidget(MiscGui::createLabel("Estimated", Qt::AlignLeft), 4, 1);
160         layout->addWidget(estPosX, 5, 1);
161         layout->addWidget(estPosY, 6, 1);
162         layout->addWidget(estPosPhi, 7, 1);
163
164         positionGroupBox->setLayout(layout);
165 }
166
167 void RobomonAtlantis::createMiscGroupBox()
168 {
169         miscGroupBox = new QGroupBox(tr("Miscellaneous"));
170         QGridLayout *layout = new QGridLayout();
171
172         showMapPushButton = new QPushButton(tr("Show &map"));
173         showMapPushButton->setShortcut(tr("m"));
174
175         layout->addWidget(showMapPushButton, 0, 0);
176
177         miscGroupBox->setLayout(layout);
178 }
179
180 void RobomonAtlantis::createDebugGroupBox()
181 {
182         debugGroupBox = new QGroupBox(tr("Debug window"));
183         QHBoxLayout *layout = new QHBoxLayout();
184
185         debugWindow = new QTextEdit();
186         debugWindow->setReadOnly(true);
187
188         layout->addWidget(debugWindow);
189         debugGroupBox->setLayout(layout);
190 }
191
192 void RobomonAtlantis::createActuatorsGroupBox()
193 {
194         actuatorsGroupBox = new QGroupBox(tr("Actuators"));
195         QHBoxLayout *layout = new QHBoxLayout();
196
197         createMotorsGroupBox();
198         createPickerGroupBox();
199
200         layout->setAlignment(Qt::AlignLeft);
201         layout->addWidget(enginesGroupBox);
202         layout->addWidget(pickerGroupBox);
203         actuatorsGroupBox->setLayout(layout);
204 }
205
206 void RobomonAtlantis::createDIOGroupBox()
207 {
208         dioGroupBox = new QGroupBox(tr("DIO"));
209         QGridLayout *layout = new QGridLayout();
210         QFont font;
211
212         font.setPointSize(5);
213         dioGroupBox->setFont(font);
214
215         for (int i=0; i<8; i++) {
216                 diCheckBox[i] = new QCheckBox(QString("DI%1").arg(i));
217                 doCheckBox[i] = new QCheckBox(QString("D0%1").arg(i));
218                 layout->addWidget(diCheckBox[i], i, 0);
219                 layout->addWidget(doCheckBox[i], i+8, 0);
220         }
221
222         dioGroupBox->setMaximumWidth(70);
223         dioGroupBox->setLayout(layout);
224 }
225
226 void RobomonAtlantis::createPowerGroupBox()
227 {
228         powerGroupBox = new QGroupBox(tr("Power management"));
229         QGridLayout *layout = new QGridLayout();
230
231         voltage33CheckBox = new QCheckBox(tr("&3.3V"));
232         voltage50CheckBox = new QCheckBox(tr("&5.0V"));
233         voltage80CheckBox = new QCheckBox(tr("&8.0V"));
234
235         voltage33CheckBox->setShortcut(tr("3"));
236         voltage50CheckBox->setShortcut(tr("5"));
237         voltage80CheckBox->setShortcut(tr("8"));
238
239         layout->addWidget(voltage33CheckBox, 0, 0);
240         layout->addWidget(voltage50CheckBox, 0, 2);
241         layout->addWidget(voltage80CheckBox, 0, 4); //1, 0);
242         layout->addWidget(MiscGui::createLabel("BAT"), 0, 6); //1, 2);
243
244         voltage33LineEdit = new QLineEdit();
245         voltage50LineEdit = new QLineEdit();
246         voltage80LineEdit = new QLineEdit();
247         voltageBATLineEdit = new QLineEdit();
248
249         voltage33LineEdit->setReadOnly(true);
250         voltage50LineEdit->setReadOnly(true);
251         voltage80LineEdit->setReadOnly(true);
252         voltageBATLineEdit->setReadOnly(true);
253
254         layout->addWidget(voltage33LineEdit, 0, 1);
255         layout->addWidget(voltage50LineEdit, 0, 3);
256         layout->addWidget(voltage80LineEdit, 0, 5); //1, 1);
257         layout->addWidget(voltageBATLineEdit, 0, 7); //1, 3);
258
259         powerGroupBox->setLayout(layout);
260 }
261
262 void RobomonAtlantis::createSensorsGroupBox()
263 {
264         sensorsGroupBox = new QGroupBox(tr("Sensors"));
265         QVBoxLayout *layout = new QVBoxLayout();
266
267         createSharpSensorsLayout();
268
269         layout->addLayout(sharpSensorsLayout);
270         sensorsGroupBox->setLayout(layout);
271 }
272
273 void RobomonAtlantis::createMotorsGroupBox()
274 {
275         enginesGroupBox = new QGroupBox(tr("Motors"));
276         QVBoxLayout *layout = new QVBoxLayout();
277         QHBoxLayout *layout1 = new QHBoxLayout();
278         QHBoxLayout *layout2 = new QHBoxLayout();
279
280         leftMotorSlider = new QSlider(Qt::Vertical);
281         rightMotorSlider = new QSlider(Qt::Vertical);
282         bothMotorsCheckBox = new QCheckBox(tr("Lock both"));
283         stopMotorsPushButton = new QPushButton(tr("Stop Motors"));
284
285         leftMotorSlider->setMinimum(-100);
286         leftMotorSlider->setMaximum(100);
287         leftMotorSlider->setTracking(false);
288         leftMotorSlider->setTickPosition(QSlider::TicksLeft);
289
290         rightMotorSlider->setMinimum(-100);
291         rightMotorSlider->setMaximum(100);
292         rightMotorSlider->setTracking(false);
293         rightMotorSlider->setTickPosition(QSlider::TicksRight);
294
295         stopMotorsPushButton->setMaximumWidth(90);
296
297         layout1->addWidget(leftMotorSlider);
298         layout1->addWidget(MiscGui::createLabel("0"));
299         layout1->addWidget(rightMotorSlider);
300
301         layout2->addWidget(bothMotorsCheckBox);
302
303         layout->addWidget(MiscGui::createLabel("100"));
304         layout->addLayout(layout1);
305         layout->addWidget(MiscGui::createLabel("-100"));
306         layout->addLayout(layout2);
307         layout->addWidget(stopMotorsPushButton);
308         enginesGroupBox->setLayout(layout);
309 }
310
311 void RobomonAtlantis::createPickerGroupBox()
312 {
313         pickerGroupBox = new QGroupBox(tr("Picker"));
314         QVBoxLayout *layout = new QVBoxLayout();
315
316         leftBeltCheckBox = new QCheckBox(tr("L Belt"));
317         rightBeltCheckBox = new QCheckBox(tr("R Belt"));
318         leftChelaCheckBox = new QCheckBox(tr("L Chela"));
319         rightChelaCheckBox = new QCheckBox(tr("R Chela"));
320         leftBeltDial = new QDial();
321         rightBeltDial = new QDial();
322         leftChelaDial = new QDial();
323         rightChelaDial = new QDial();
324         pickPushButton = new QPushButton(tr("Pick!"));
325
326         leftBeltDial->setMinimum(0);
327         leftBeltDial->setMaximum(200);
328         leftBeltDial->setValue(100);
329
330         rightBeltDial->setMinimum(0);
331         rightBeltDial->setMaximum(200);
332         rightBeltDial->setValue(100);
333
334         leftChelaDial->setMinimum(0);
335         leftChelaDial->setMaximum(255);
336         leftChelaDial->setValue(127);
337
338         rightChelaDial->setMinimum(0);
339         rightChelaDial->setMaximum(255);
340         rightChelaDial->setValue(127);
341
342         layout->addWidget(leftChelaDial);
343         layout->addWidget(leftChelaCheckBox);
344         layout->addWidget(rightChelaDial);
345         layout->addWidget(rightChelaCheckBox);
346         layout->addWidget(leftBeltDial);
347         layout->addWidget(leftBeltCheckBox);
348         layout->addWidget(rightBeltDial);
349         layout->addWidget(rightBeltCheckBox);
350         layout->addWidget(pickPushButton);
351
352         pickerGroupBox->setLayout(layout);
353 }
354
355 void RobomonAtlantis::createSharpSensorsLayout()
356 {
357         sharpSensorsLayout = new QVBoxLayout();
358         QGridLayout *layout3 = new QGridLayout();
359
360         obstacleSimulationCheckBox = new QCheckBox(tr("&Obstacle simulation"));
361
362         obstacleSimulationCheckBox->setShortcut(tr("o"));
363
364         layout3->addWidget(obstacleSimulationCheckBox, 0, 1);
365
366         sharpSensorsLayout->addLayout(layout3);
367 }
368
369 void RobomonAtlantis::createRobots()
370 {
371         robotActPos = new Robot(NULL, playgroundScene, Qt::black);
372         robotActPos->setZValue(10);
373         robotEstPos = new Robot(NULL, playgroundScene, Qt::green);
374         robotEstPos->setZValue(10);
375
376         playgroundScene->addItem(robotActPos);
377         playgroundScene->addItem(robotEstPos);
378 }
379
380 /**********************************************************************
381  * GUI actions
382  **********************************************************************/
383 void RobomonAtlantis::createActions()
384 {
385         /* power management */
386         connect(voltage33CheckBox, SIGNAL(stateChanged(int)), 
387                         this, SLOT(setVoltage33(int)));
388         connect(voltage50CheckBox, SIGNAL(stateChanged(int)), 
389                         this, SLOT(setVoltage50(int)));
390         connect(voltage80CheckBox, SIGNAL(stateChanged(int)), 
391                         this, SLOT(setVoltage80(int)));
392
393         /* motors */
394         connect(leftMotorSlider, SIGNAL(valueChanged(int)), 
395                         this, SLOT(setLeftMotor(int)));
396         connect(rightMotorSlider, SIGNAL(valueChanged(int)), 
397                         this, SLOT(setRightMotor(int)));
398         connect(stopMotorsPushButton, SIGNAL(clicked()), 
399                         this, SLOT(stopMotors()));
400
401         /* DIO */
402         for (int i=0; i<8; i++)
403                 connect(doCheckBox[0], SIGNAL(stateChanged(int)), 
404                                         this, SLOT(setDO(int)));
405
406         /* path planning map */
407         connect(showMapPushButton, SIGNAL(clicked()),
408                         this, SLOT(showMap()));
409
410         /* obstacle simulation */
411         simulationEnabled = 0;
412         connect(obstacleSimulationCheckBox, SIGNAL(stateChanged(int)),
413                         this, SLOT(setSimulation(int)));
414         connect(obstacleSimulationCheckBox, SIGNAL(stateChanged(int)),
415                         this, SLOT(setObstacleSimulation(int)));
416         connect(obstacleSimulationCheckBox, SIGNAL(stateChanged(int)),
417                         playgroundScene, SLOT(showObstacle(int)));
418         connect(playgroundScene, SIGNAL(obstacleChanged(QPointF)), 
419                         this, SLOT(changeObstacle(QPointF)));
420
421         /* Actuators */
422         connect(pickPushButton, SIGNAL(clicked()), this, SLOT(pick()));
423         connect(leftBeltCheckBox, SIGNAL(stateChanged(int)), this, SLOT(setBelts(int)));
424         connect(rightBeltCheckBox, SIGNAL(stateChanged(int)), this, SLOT(setBelts(int)));
425         connect(leftChelaCheckBox, SIGNAL(stateChanged(int)), this, SLOT(setChelae(int)));
426         connect(rightChelaCheckBox, SIGNAL(stateChanged(int)), this, SLOT(setChelae(int)));
427         connect(leftBeltDial, SIGNAL(valueChanged(int)), this, SLOT(setBelts(int)));
428         connect(rightBeltDial, SIGNAL(valueChanged(int)), this, SLOT(setBelts(int)));
429         connect(leftChelaDial, SIGNAL(valueChanged(int)), this, SLOT(setChelae(int)));
430         connect(rightChelaDial, SIGNAL(valueChanged(int)), this, SLOT(setChelae(int)));
431 }
432
433 void RobomonAtlantis::setVoltage33(int state)
434 {
435         if (state)
436                 orte.pwr_ctrl.voltage33 = true;
437         else
438                 orte.pwr_ctrl.voltage33 = false;
439 }
440
441 void RobomonAtlantis::setVoltage50(int state)
442 {
443         if (state)
444                 orte.pwr_ctrl.voltage50 = true;
445         else
446                 orte.pwr_ctrl.voltage50 = false;
447 }
448
449 void RobomonAtlantis::setVoltage80(int state)
450 {
451         if (state)
452                 orte.pwr_ctrl.voltage80 = true;
453         else
454                 orte.pwr_ctrl.voltage80 = false;
455 }
456
457 void RobomonAtlantis::setLeftMotor(int value)
458 {
459         short int leftMotor;
460         short int rightMotor;
461         
462         if(bothMotorsCheckBox->isChecked())
463                 rightMotorSlider->setValue(value);
464
465         leftMotor = (short int)(MOTOR_LIMIT * (leftMotorSlider->value()/100.0));
466         rightMotor = (short int)(MOTOR_LIMIT * (rightMotorSlider->value()/100.0));
467         
468         orte.motion_speed.left = leftMotor;
469         orte.motion_speed.right = rightMotor;
470         
471 }
472
473 void RobomonAtlantis::setRightMotor(int value)
474 {
475         short int leftMotor;
476         short int rightMotor;
477         
478         if(bothMotorsCheckBox->isChecked())
479                 leftMotorSlider->setValue(value);
480
481         leftMotor = (short int)(MOTOR_LIMIT * (leftMotorSlider->value()/100.0));
482         rightMotor = (short int)(MOTOR_LIMIT * (rightMotorSlider->value()/100.0));
483         
484         orte.motion_speed.left = leftMotor;
485         orte.motion_speed.right = rightMotor;
486         
487 }
488
489 void RobomonAtlantis::stopMotors()
490 {
491         leftMotorSlider->setValue(0);
492         rightMotorSlider->setValue(0);
493 }
494
495
496 void RobomonAtlantis::setDO(int state)
497 {
498         Q_UNUSED(state);
499         /* FIXME: digital output control comes here */
500 }
501
502 void RobomonAtlantis::pick()
503 {
504         // TODO: send signal to the fsmact
505 }
506
507 void RobomonAtlantis::setBelts(int value)
508 {
509         Q_UNUSED(value);
510         unsigned char leftBelt;
511         unsigned char rightBelt;
512
513         leftBelt = (unsigned char)leftBeltDial->value();
514         rightBelt = (unsigned char)rightBeltDial->value();
515
516         act_belts(leftBelt, rightBelt);
517 }
518
519 void RobomonAtlantis::setChelae(int value)
520 {
521         Q_UNUSED(value);
522         unsigned char leftChela;
523         unsigned char rightChela;
524
525         leftChela = (unsigned char)leftChelaDial->value();
526         rightChela = (unsigned char)rightChelaDial->value();
527
528         act_chelae(leftChela, rightChela);
529 }
530
531 void RobomonAtlantis::showMap()
532 {
533         openSharedMemory();
534
535         if (sharedMemoryOpened == false)
536                 return;
537
538         mapTimer = new QTimer(this);
539         connect(mapTimer, SIGNAL(timeout()), this, SLOT(paintMap()));
540         mapTimer->start(200);
541
542         showMapPushButton->setText(tr("Show Playground"));
543         showMapPushButton->setShortcut(tr("p"));
544         disconnect(showMapPushButton, SIGNAL(clicked()), this, SLOT(showMap()));
545         connect(showMapPushButton, SIGNAL(clicked()),
546                                 this, SLOT(showPlayground()));
547 }
548
549 void RobomonAtlantis::showPlayground()
550 {
551         mapTimer->stop();
552         disconnect(mapTimer, SIGNAL(timeout()), this, SLOT(paintMap()));
553
554         /* FIXME: */
555
556         showMapPushButton->setText(tr("Show &map"));
557         showMapPushButton->setShortcut(tr("m"));
558         disconnect(showMapPushButton, SIGNAL(clicked()),
559                                 this, SLOT(showPlayground()));
560         connect(showMapPushButton, SIGNAL(clicked()), this, SLOT(showMap()));
561 }
562
563 void RobomonAtlantis::paintMap()
564 {
565         using namespace Qt;
566         static QGraphicsRectItem *rects[MAP_WIDTH][MAP_HEIGHT];
567         static bool firstMap = true;
568         int x, y;
569         struct map *map = ShmapIsMapInit();
570
571         if (!map) return;
572         
573         for(int i=0; i < MAP_WIDTH; i++) {
574                 for(int j=0; j<MAP_HEIGHT; j++) {
575                         x = TOP_LEFT_X+i*cellSize;
576                         y = TOP_LEFT_Y+j*cellSize;
577                                 
578                         if(firstMap) {                  
579                                 rects[i][j] = playgroundScene->addRect(
580                                                 QRectF(x,y,cellSize,cellSize), 
581                                                 QPen(QBrush(Qt::black), 
582                                                 1,
583                                                 Qt::SolidLine,
584                                                 Qt::FlatCap,
585                                                 Qt::BevelJoin),
586                                                 QBrush(Qt::lightGray));
587                                 rects[i][j]->setZValue(4);
588                         }
589                         
590                         QColor color;
591                                 
592                         struct map_cell *cell = &map->cells[j][i];
593                         color = lightGray;
594                         if (cell->flags & MAP_FLAG_WALL)
595                                 color = darkYellow;
596                         if (cell->flags & MAP_FLAG_IGNORE_OBST)
597                                 color = darkGreen;
598                         if (cell->flags & MAP_FLAG_SIMULATED_WALL)
599                                 color = yellow;
600                         if (cell->flags & MAP_FLAG_PATH)
601                                 color = darkRed;
602                         if (cell->flags & MAP_FLAG_START)
603                                 color = red;
604                         if (cell->flags & MAP_FLAG_GOAL)
605                                 color = green;
606                         if (cell->detected_obstacle) {
607                                 QColor c1(color), c2(blue);
608                                 double f = (double)cell->detected_obstacle/MAP_NEW_OBSTACLE*0.7;
609                                 QColor c(c1.red()   + (int)(f*(c2.red()   - c1.red())),
610                                          c1.green() + (int)(f*(c2.green() - c1.green())),
611                                          c1.blue()  + (int)(f*(c2.blue()  - c1.blue())));
612                                 color = c;
613                         }
614                         if (cell->flags & MAP_FLAG_DET_OBST)
615                                 color = cyan;
616                         
617                         rects[i][j]->setBrush(QBrush(color));
618                 }
619         }
620         firstMap = false;
621 }
622
623 void RobomonAtlantis::setSimulation(int state)
624 {
625         if(state) { 
626                 robottype_publisher_hokuyo_scan_create(&orte, 
627                                                        dummy_publisher_callback, this);
628         } else {
629                 if (!simulationEnabled)
630                         return;
631                 robottype_publisher_hokuyo_scan_destroy(&orte);
632         }
633         simulationEnabled = state;
634 }
635
636 /*!     
637         \fn RobomonAtlantis::setObstacleSimulation(int state)
638  */
639 void RobomonAtlantis::setObstacleSimulation(int state)
640 {
641         if (state) {
642                 /* TODO Maybe it is possible to attach only once to Shmap */
643                 ShmapInit(0);
644                 obstacleSimulationTimer = new QTimer(this);
645                 connect(obstacleSimulationTimer, SIGNAL(timeout()), 
646                         this, SLOT(simulateObstaclesHokuyo()));
647                 obstacleSimulationTimer->start(100);
648                 setMouseTracking(true);
649         } else {
650                 if (obstacleSimulationTimer) 
651                         delete obstacleSimulationTimer;
652                 //double distance = 0.8;
653         }
654 }
655
656
657 void RobomonAtlantis::simulateObstaclesHokuyo()
658 {
659         double distance, wall_distance;
660         int i;
661         uint16_t *hokuyo[34] = { // FIXME should be HOKUYO_CLUSTER_CNT
662                 &orte.hokuyo_scan.data1,
663                 &orte.hokuyo_scan.data2,
664                 &orte.hokuyo_scan.data3,
665                 &orte.hokuyo_scan.data4,
666                 &orte.hokuyo_scan.data5,
667                 &orte.hokuyo_scan.data6,
668                 &orte.hokuyo_scan.data7,
669                 &orte.hokuyo_scan.data8,
670                 &orte.hokuyo_scan.data9,
671                 &orte.hokuyo_scan.data10,
672                 &orte.hokuyo_scan.data11,
673                 &orte.hokuyo_scan.data12,
674                 &orte.hokuyo_scan.data13,
675                 &orte.hokuyo_scan.data14,
676                 &orte.hokuyo_scan.data15,
677                 &orte.hokuyo_scan.data16,
678                 &orte.hokuyo_scan.data17,
679                 &orte.hokuyo_scan.data18,
680                 &orte.hokuyo_scan.data19,
681                 &orte.hokuyo_scan.data20,
682                 &orte.hokuyo_scan.data21,
683                 &orte.hokuyo_scan.data22,
684                 &orte.hokuyo_scan.data23,
685                 &orte.hokuyo_scan.data24,
686                 &orte.hokuyo_scan.data25,
687                 &orte.hokuyo_scan.data26,
688                 &orte.hokuyo_scan.data27,
689                 &orte.hokuyo_scan.data28,
690                 &orte.hokuyo_scan.data29,
691                 &orte.hokuyo_scan.data30,
692                 &orte.hokuyo_scan.data31,
693                 &orte.hokuyo_scan.data32,
694                 &orte.hokuyo_scan.data33,
695                 &orte.hokuyo_scan.data34,
696         };
697
698         
699         for (i=0; i<HOKUYO_CLUSTER_CNT; i++) {
700                 wall_distance = distanceToWallHokuyo(i);
701                 distance = distanceToObstacleHokuyo(i, simulatedObstacle, SIM_OBST_SIZE_M/*meters*/);
702                 if (wall_distance < distance) 
703                         distance = wall_distance;
704                 *hokuyo[i] = (uint16_t)(distance*1000);
705         }
706         ORTEPublicationSend(orte.publication_hokuyo_scan);
707         
708 }
709
710 void RobomonAtlantis::changeObstacle(QPointF position)
711 {
712         if (!simulationEnabled) {
713                 simulationEnabled = 1;
714                 obstacleSimulationCheckBox->setChecked(true);
715         }
716
717         simulatedObstacle.x = position.x();
718         simulatedObstacle.y = position.y();
719         simulateObstaclesHokuyo();
720 }       
721
722 /**********************************************************************
723  * EVENTS
724  **********************************************************************/
725 bool RobomonAtlantis::event(QEvent *event)
726 {
727         switch (event->type()) {
728                 case QEVENT(QEV_MOTION_STATUS):
729                         emit motionStatusReceivedSignal();
730                         break;
731                 case QEVENT(QEV_ACTUAL_POSITION):
732                         emit actualPositionReceivedSignal();
733                         break;
734                 case QEVENT(QEV_ESTIMATED_POSITION):
735                         emit estimatedPositionReceivedSignal();
736                         break;
737                 case QEVENT(QEV_DI):
738                         emit diReceivedSignal();
739                         break;
740                 case QEVENT(QEV_ACCELEROMETER):
741                         emit accelerometerReceivedSignal();
742                         break;
743                 case QEVENT(QEV_ACCUMULATOR):
744                         emit accumulatorReceivedSignal();
745                         break;
746                 case QEVENT(QEV_POWER_VOLTAGE):
747                         emit powerVoltageReceivedSignal();
748                         break;
749                 default:
750                         if (event->type() == QEvent::Close)
751                                 closeEvent((QCloseEvent *)event);
752                         else if (event->type() == QEvent::KeyPress)
753                                 keyPressEvent((QKeyEvent *)event);
754                         else if (event->type() == QEvent::KeyRelease)
755                                 keyReleaseEvent((QKeyEvent *)event);
756                         else if (event->type() == QEvent::FocusIn)
757                                 grabKeyboard();
758                         else if (event->type() == QEvent::FocusOut)
759                                 releaseKeyboard();
760                         else {
761                                 event->ignore();
762                                 return false;
763                         }
764                         break;
765         }
766         event->accept();
767         return true;
768 }
769
770 void RobomonAtlantis::keyPressEvent(QKeyEvent *event)
771 {
772         double peak, gain;
773
774         if (event->isAutoRepeat()) {
775                 switch (event->key()) {
776                         case Qt::Key_Down:
777                                 peak = leftMotorSlider->minimum()/2;
778                                 if (leftMotorValue < peak ||
779                                         rightMotorValue < peak)
780                                         gain = 1.01;
781                                 else
782                                         gain = 1.3;
783                                 leftMotorValue *= gain;
784                                 rightMotorValue *= gain;
785                                 leftMotorSlider->setValue((int)leftMotorValue);
786                                 rightMotorSlider->setValue((int)rightMotorValue);
787                                 break;
788
789                         case Qt::Key_Up:
790                         case Qt::Key_Left:
791                         case Qt::Key_Right:
792                                 peak = leftMotorSlider->maximum()/2;
793                                 if (leftMotorValue > peak ||
794                                         rightMotorValue > peak)
795                                         gain = 1.01;
796                                 else
797                                         gain = 1.3;
798                                 leftMotorValue *= gain;
799                                 rightMotorValue *= gain;
800                                 leftMotorSlider->setValue((int)leftMotorValue);
801                                 rightMotorSlider->setValue((int)rightMotorValue);
802                                 break;
803
804                         default:
805                                 event->ignore();
806                                 break;
807                 }
808                 return;
809         }
810
811         switch (event->key()) {
812                 case Qt::Key_Up:
813                         leftMotorValue = 1;
814                         rightMotorValue = 1;
815                         bothMotorsCheckBox->setChecked(true);
816                         leftMotorSlider->setValue((int)leftMotorValue);
817                         setLeftMotor((int)leftMotorValue);
818                         break;
819                 case Qt::Key_Down:
820                         leftMotorValue = -1;
821                         rightMotorValue = -1;
822                         bothMotorsCheckBox->setChecked(true);
823                         leftMotorSlider->setValue((int)leftMotorValue);
824                         setLeftMotor((int)leftMotorValue);
825                         break;
826                 case Qt::Key_Left:
827                         leftMotorValue = -1;
828                         rightMotorValue = 1;
829                         leftMotorSlider->setValue((int)leftMotorValue);
830                         rightMotorSlider->setValue((int)rightMotorValue);
831                         setLeftMotor((int)leftMotorValue);
832                         setRightMotor((int)leftMotorValue);
833                         break;
834                 case Qt::Key_Right:
835                         leftMotorValue = 1;
836                         rightMotorValue = -1;
837                         leftMotorSlider->setValue((int)leftMotorValue);
838                         rightMotorSlider->setValue((int)rightMotorValue);
839                         setLeftMotor((int)leftMotorValue);
840                         setRightMotor((int)rightMotorValue);
841                         break;
842                 default:
843                         event->ignore();
844                         break;
845         }
846         event->accept();
847 }
848
849 void RobomonAtlantis::keyReleaseEvent(QKeyEvent *event)
850 {
851         if (event->isAutoRepeat()) {
852                 event->ignore();
853                 return;
854         }
855
856         switch (event->key()) {
857                 case Qt::Key_Up:
858                 case Qt::Key_Down:
859                 case Qt::Key_Left:
860                 case Qt::Key_Right:
861                         leftMotorValue = 0;
862                         rightMotorValue = 0;
863                         bothMotorsCheckBox->setChecked(false);
864                         leftMotorSlider->setValue((int)leftMotorValue);
865                         rightMotorSlider->setValue((int)rightMotorValue);
866                         break;
867                 default:
868                         event->ignore();
869                         break;
870         }
871         event->accept();
872 }
873
874 void RobomonAtlantis::closeEvent(QCloseEvent *)
875 {
876         robottype_roboorte_destroy(&orte);
877 }
878
879 /**********************************************************************
880  * ORTE
881  **********************************************************************/
882 void RobomonAtlantis::createOrte()
883 {
884         int rv;
885
886         orte.strength = 11;
887         
888         rv = robottype_roboorte_init(&orte);
889         if (rv) {
890                 printf("RobomonAtlantis: Unable to initialize ORTE\n");
891         }
892
893         /* publishers */
894         robottype_publisher_motion_speed_create(&orte, dummy_publisher_callback, NULL);
895
896         robottype_publisher_pwr_ctrl_create(&orte, dummy_publisher_callback, NULL);
897         robottype_publisher_lift_create(&orte, NULL, &orte);
898         robottype_publisher_pusher_create(&orte, NULL, &orte);
899         robottype_publisher_chelae_create(&orte, NULL, &orte);
900         robottype_publisher_belts_create(&orte, NULL, &orte);
901         robottype_publisher_holder_create(&orte, NULL, &orte);
902
903         /* subscribers */
904         robottype_subscriber_pwr_voltage_create(&orte, 
905                                 receivePowerVoltageCallBack, this);
906         robottype_subscriber_motion_status_create(&orte, 
907                                 receiveMotionStatusCallBack, this);
908         robottype_subscriber_ref_pos_create(&orte, 
909                                 receiveActualPositionCallBack, this);
910         robottype_subscriber_est_pos_create(&orte, 
911                                 receiveEstimatedPositionCallBack, this);
912
913         //robottype_subscriber_actuator_status_create(orte, receiveActuatorStatusCallBack, this);
914
915
916         /*createDISubscriber(this, &orteData);*/
917         /*createAccelerometerSubscriber(this, &orteData);*/
918         /*createAccumulatorSubscriber(this, &orteData);*/
919         /* motors */
920         orte.motion_speed.left = 0;
921         orte.motion_speed.right = 0;
922         /* power management */
923         orte.pwr_ctrl.voltage33 = true;
924         orte.pwr_ctrl.voltage50 = true;
925         orte.pwr_ctrl.voltage80 = true;
926         voltage33CheckBox->setChecked(true);
927         voltage50CheckBox->setChecked(true);
928         voltage80CheckBox->setChecked(true);
929
930         act_init(&orte);
931
932         /* set actions to do when we receive data from orte */
933         connect(this, SIGNAL(motionStatusReceivedSignal()), 
934                         this, SLOT(motionStatusReceived()));
935         connect(this, SIGNAL(actualPositionReceivedSignal()), 
936                         this, SLOT(actualPositionReceived()));
937         connect(this, SIGNAL(estimatedPositionReceivedSignal()), 
938                         this, SLOT(estimatedPositionReceived()));
939         connect(this, SIGNAL(diReceivedSignal()), 
940                         this, SLOT(diReceived()));
941         connect(this, SIGNAL(accelerometerReceivedSignal()), 
942                         this, SLOT(accelerometerReceived()));
943         connect(this, SIGNAL(accumulatorReceivedSignal()), 
944                         this, SLOT(accumulatorReceived()));
945         connect(this, SIGNAL(powerVoltageReceivedSignal()), 
946                         this, SLOT(powerVoltageReceived()));
947 }
948
949 void RobomonAtlantis::motionStatusReceived()
950 {
951         WDBG("ORTE received: motion status");
952 }
953
954 void RobomonAtlantis::actualPositionReceived()
955 {
956         actPosX->setText(QString("%1").arg(orte.ref_pos.x, 0, 'f', 3));
957         actPosY->setText(QString("%1").arg(orte.ref_pos.y, 0, 'f', 3));
958         actPosPhi->setText(QString("%1(%2)")
959                         .arg(DEGREES(orte.ref_pos.phi), 0, 'f', 0)
960                         .arg(orte.ref_pos.phi, 0, 'f', 1));
961         robotActPos->moveRobot(orte.ref_pos.x, 
962                 orte.ref_pos.y, orte.ref_pos.phi);
963 }
964
965 void RobomonAtlantis::estimatedPositionReceived()
966 {
967         estPosX->setText(QString("%1").arg(orte.est_pos.x, 0, 'f', 3));
968         estPosY->setText(QString("%1").arg(orte.est_pos.y, 0, 'f', 3));
969         estPosPhi->setText(QString("%1(%2)")
970                         .arg(DEGREES(orte.est_pos.phi), 0, 'f', 0)
971                         .arg(orte.est_pos.phi, 0, 'f', 1));
972         robotEstPos->moveRobot(orte.est_pos.x, 
973                 orte.est_pos.y, orte.est_pos.phi);
974 }
975
976 void RobomonAtlantis::diReceived()
977 {
978         WDBG("ORTE received: DI");
979 }
980
981 void RobomonAtlantis::accelerometerReceived()
982 {
983         WDBG("ORTE received: accelerometer");
984 }
985
986 void RobomonAtlantis::accumulatorReceived()
987 {
988         WDBG("ORTE received: accumulator");
989 }
990
991 void RobomonAtlantis::powerVoltageReceived()
992 {
993         voltage33LineEdit->setText(QString("%1").arg(
994                         orte.pwr_voltage.voltage33, 0, 'f', 3));
995         voltage50LineEdit->setText(QString("%1").arg(
996                         orte.pwr_voltage.voltage50, 0, 'f', 3));
997         voltage80LineEdit->setText(QString("%1").arg(
998                         orte.pwr_voltage.voltage80, 0, 'f', 3));
999         voltageBATLineEdit->setText(QString("%1").arg(
1000                         orte.pwr_voltage.voltageBAT, 0, 'f', 3));
1001
1002 }
1003
1004 /**********************************************************************
1005  * MISCELLANEOUS
1006  **********************************************************************/
1007 void RobomonAtlantis::openSharedMemory()
1008 {
1009         int segmentId;
1010         int sharedSegmentSize;
1011
1012         if (sharedMemoryOpened)
1013                 return;
1014
1015         cellSize = PG_X / MAP_WIDTH;
1016         
1017         sharedSegmentSize = sizeof(char) * MAP_WIDTH * MAP_HEIGHT;
1018         
1019         /* Get segment identificator in a read only mode  */
1020         segmentId = shmget(SHM_MAP_KEY, sharedSegmentSize, S_IRUSR);
1021         if(segmentId == -1) {
1022                 QMessageBox::critical(this, "robomon",
1023                                 "Unable to open shared memory segment!");
1024                 return;
1025         }
1026         
1027         /* Init Shmap */
1028         ShmapInit(0);
1029         
1030         /* Attach the shared memory segment */
1031         //map =  (_Map*)shmat (segmentId, (void*) 0, 0);
1032
1033         sharedMemoryOpened = true;
1034 }
1035
1036 double RobomonAtlantis::distanceToWallHokuyo(int beamnum)
1037 {
1038         double distance=4.0, min_distance=4.0;
1039         int i,j;
1040         Point wall;
1041         struct map *map = ShmapIsMapInit();
1042
1043         if (!map) return min_distance;
1044         
1045         // Simulate obstacles
1046         for(j=0;j<MAP_HEIGHT;j++) {
1047                 for (i=0;i<MAP_WIDTH;i++) {
1048                         struct map_cell *cell = &map->cells[j][i];
1049                         if( cell->flags & MAP_FLAG_SIMULATED_WALL) {
1050                                 // WALL
1051                                 ShmapCell2Point(i, j, &wall.x, &wall.y);
1052                                 
1053                                 distance = distanceToObstacleHokuyo(beamnum, wall, MAP_CELL_SIZE_M);
1054                                 if (distance<min_distance) min_distance = distance;
1055                         }
1056                 }
1057         }
1058
1059         return min_distance;
1060 }
1061
1062 /** 
1063  * Calculation for Hokuyo simulation. Calculates distance that would
1064  * be returned by Hokuyo sensors, if there is only one obstacle (as
1065  * specified by parameters).
1066  *
1067  * @param beamnum Hokuyo's bean number [0..HOKUYO_CLUSTER_CNT]
1068  * @param obstacle Position of the obstacle (x, y in meters).
1069  * @param obstacleSize Size (diameter) of the obstacle in meters.
1070  * 
1071  * @return Distance measured by sensors in meters.
1072  */    
1073 double RobomonAtlantis::distanceToObstacleHokuyo(int beamnum, Point obstacle, double obstacleSize)
1074 {  
1075         struct est_pos_type e = orte.est_pos;
1076         double sensor_a;
1077         struct sharp_pos s;
1078
1079         s.x = HOKUYO_CENTER_OFFSET_M;
1080         s.y = 0.0;
1081         s.ang = HOKUYO_CLUSTER_TO_RAD(beamnum);
1082
1083         Point sensor(e.x + s.x*cos(e.phi) - s.y*sin(e.phi),
1084                      e.y + s.x*sin(e.phi) + s.y*cos(e.phi));
1085         sensor_a = e.phi + s.ang;
1086         
1087         const double sensorRange = 4.0; /*[meters]*/
1088         
1089         double distance, angle;
1090             
1091         angle = sensor.angleTo(obstacle) - sensor_a;
1092         angle = fmod(angle, 2.0*M_PI);
1093         if (angle > +M_PI) angle -= 2.0*M_PI;
1094         if (angle < -M_PI) angle += 2.0*M_PI;
1095         angle = fabs(angle);
1096         distance = sensor.distanceTo(obstacle)-0.11;
1097         if (angle < atan(obstacleSize/2.0 / (distance+0.001))) {
1098                 // We can see the obstackle from here.
1099                 if (angle < M_PI/2.0) {
1100                     distance = distance/cos(angle);
1101                 }
1102                 if (distance > sensorRange) 
1103                         distance = sensorRange;
1104         } else {
1105                 distance = sensorRange;
1106         }
1107
1108         return distance;
1109 }