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