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