YARP
Yet Another Robot Platform
 
Loading...
Searching...
No Matches
mainwindow.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2006-2021 Istituto Italiano di Tecnologia (IIT)
3 * SPDX-FileCopyrightText: 2006-2010 RobotCub Consortium
4 * SPDX-License-Identifier: LGPL-2.1-or-later
5 */
6
7#include "mainwindow.h"
8#include "ui_mainwindow.h"
9
10#include "flowlayout.h"
11#include "jointitem.h"
12#include "partitem.h"
13
14#include <QToolBar>
15#include <QDebug>
16#include <QHBoxLayout>
17#include <QScrollArea>
18#include <QFont>
19#include <QFontMetrics>
20#include <QMessageBox>
21#include <QSettings>
22#include <QFileDialog>
23#include <QShortcut>
24#include <map>
25#include <cstdlib>
26#include <yarp/os/LogStream.h>
28
29MainWindow::MainWindow(QWidget *parent) :
30 QMainWindow(parent),
31 m_ui(new Ui::MainWindow)
32{
33 m_ui->setupUi(this);
34
35 QLocale::setDefault(QLocale::C);
36 m_tabPanel = nullptr;
37 m_sequenceActiveCount = 0;
38
39 setWindowTitle("Qt Robot Motor GUI V2.0");
41
42 m_sliderOpt = nullptr;
43
44 QString globalLabel("Global Joints Commands ");
45 m_globalToolBar = new QToolBar("Global Joints Commands", this);
47
48 QFont f = label1->font();
49 f.setBold(true);
50 label1->setFont(f);
51 m_globalToolBar->addWidget(label1)->setCheckable(false);
52
53
54 m_globalToolBar->addSeparator();
55 m_goAll = m_globalToolBar->addAction(QIcon(":/play-all.svg"), "Go All");
56 m_globalToolBar->addSeparator();
57 m_runAllSeq = m_globalToolBar->addAction(QIcon(":/images/runSequence.png"), "Run All Sequences (use joint speeds from Speed tab)");
58 m_runAllSeqTime = m_globalToolBar->addAction(QIcon(":/images/runSequenceTime.png"), "Run All Sequences (ignore Speed tab, produce coordinated movement using Timing)");
59 m_saveAllSeq = m_globalToolBar->addAction(QIcon(":/file-save.svg"), "Save All Sequences");
60 m_loadAllSeq = m_globalToolBar->addAction(QIcon(":/file-open.svg"), "Load All Sequences");
61 m_cycleAllSeq = m_globalToolBar->addAction(QIcon(":/images/cycleAllSequence.png"), "Cycle All Sequences (use joint speeds from Speed tab)");
62 m_cycleAllSeqTime = m_globalToolBar->addAction(QIcon(":/images/cycleAllSequenceTime.png"), "Cycle All Sequences (ignore Speed tab, produce coordinated movement using Timing)");
63 m_stopAllSeq = m_globalToolBar->addAction(QIcon(":/stop.svg"), "Stop All Sequences");
64 m_globalToolBar->addSeparator();
65 m_idleAllParts = m_globalToolBar->addAction(QIcon(":/idle.svg"), "Idle All Parts");
66 m_runAllParts = m_globalToolBar->addAction(QIcon(":/play.svg"), "Run All Parts");
67 m_homeAllParts = m_globalToolBar->addAction(QIcon(":/home.svg"), "Home All Parts");
68 m_globalToolBar->addSeparator();
69 m_script1 = m_globalToolBar->addAction(QIcon(":/action1.svg"), "Execute User Script1");
70 m_script2 = m_globalToolBar->addAction(QIcon(":/action2.svg"), "Execute User Script2");
71 addToolBar(m_globalToolBar);
72
73 QMenu *globalMenuCommands = m_ui->menuBar->addMenu("Global Joints Commands ");
74 globalMenuCommands->addAction(m_goAll);
75 globalMenuCommands->addSeparator();
76 globalMenuCommands->addAction(m_runAllSeq);
77 globalMenuCommands->addAction(m_runAllSeqTime);
78 globalMenuCommands->addAction(m_saveAllSeq);
79 globalMenuCommands->addAction(m_loadAllSeq);
80 globalMenuCommands->addAction(m_cycleAllSeq);
81 globalMenuCommands->addAction(m_cycleAllSeqTime);
82 globalMenuCommands->addAction(m_stopAllSeq);
83 globalMenuCommands->addSeparator();
84 globalMenuCommands->addAction(m_idleAllParts);
85 globalMenuCommands->addAction(m_runAllParts);
86 globalMenuCommands->addAction(m_homeAllParts);
87 //Looking for custom positions in the config file
89 //Positions have the following form: "customPosition_{NAME_OF_CUSTOM_POSITION}"
90 //To iterate on all groups, transform the finder into Bottle
91 yarp::os::Bottle ini(finder.toString());
92
93 std::map<std::string, yarp::os::Bottle> customPositions;
94
95 for (size_t index = 0; index < ini.size(); ++index) {
96 //Look for groups starting with "customPosition_"
97 yarp::os::Value item = ini.get(index);
98 if (!item.isList()) {
99 continue;
100 }
101 yarp::os::Bottle *subElement = item.asList();
102 //At least two elements and first should be string
103 if (!subElement
104 || subElement->size() < 2
105 || !subElement->get(0).isString()) {
106 continue;
107 }
108 //get first element
109 std::string key = subElement->get(0).asString();
110 std::string pattern = "customPosition_";
111 size_t subStringPosition = key.find(pattern);
112 if (subStringPosition != 0) {
113 continue; //not starting or not found
114 }
115
116 std::string customPositionName = key.substr(pattern.size());
117 customPositions.insert(std::map<std::string, yarp::os::Bottle>::value_type(customPositionName, subElement->tail()));
118 }
119
120 m_customPositionsAllParts.reserve(customPositions.size());
121 if (customPositions.size() > 0) {
122 //If there are customPositions create a submenu item
123 QMenu *customPositionsMenu = globalMenuCommands->addMenu(QIcon(":/home.svg"), "Custom positions");
124
125 unsigned keyIndex = 0;
126 for (std::map<std::string, yarp::os::Bottle>::const_iterator it(customPositions.begin()); it != customPositions.end(); ++it) {
127
128 QAction *newAction = customPositionsMenu->addAction(("Move all parts to " + it->first).c_str());
129 m_customPositionsAllParts.push_back(newAction);
130 //
131 const yarp::os::Bottle &position = it->second;
132
133 // Adding shortcut (to only the first 9 sequences)
134 if (keyIndex < 9) {
135 QKeySequence shortcut(Qt::CTRL + Qt::META + (Qt::Key_1 + keyIndex++));
136 newAction->setShortcut(shortcut);
137 newAction->setShortcutContext(Qt::ApplicationShortcut);
138 }
139
140 //copy position in the lambda
141 connect(newAction, &QAction::triggered, this, [this, position]{onHomeAllPartsToCustomPosition(position); });
142 }
143 }
144
145 globalMenuCommands->addSeparator();
146 globalMenuCommands->addAction(m_script1);
147 globalMenuCommands->addAction(m_script2);
148
149 connect(m_goAll, SIGNAL(triggered()), this, SLOT(onGoAll()));
150 connect(m_idleAllParts, SIGNAL(triggered()), this, SLOT(onIdleAllParts()));
151 connect(m_runAllParts, SIGNAL(triggered()), this, SLOT(onRunAllParts()));
152 connect(m_homeAllParts, SIGNAL(triggered()), this, SLOT(onHomeAllParts()));
153
154 connect(m_runAllSeq, SIGNAL(triggered()), this, SLOT(onRunAllSeq()));
155 connect(m_runAllSeqTime, SIGNAL(triggered()), this, SLOT(onRunTimeAllSeq()));
156 connect(m_cycleAllSeq, SIGNAL(triggered()), this, SLOT(onCycleAllSeq()));
157 connect(m_cycleAllSeqTime, SIGNAL(triggered()), this, SLOT(onCycleTimeAllSeq()));
158
159 connect(m_stopAllSeq, SIGNAL(triggered()), this, SLOT(onStopAllSeq()));
160 connect(m_loadAllSeq, SIGNAL(triggered()), this, SLOT(onLoadAllSeq()));
161 connect(m_saveAllSeq, SIGNAL(triggered()), this, SLOT(onSaveAllSeq()));
162
163 connect(m_script1, SIGNAL(triggered()), this, SLOT(onExecuteScript1()));
164 connect(m_script2, SIGNAL(triggered()), this, SLOT(onExecuteScript2()));
165
166 //addToolBarBreak();
167
168 m_partToolBar = new QToolBar("Current Part", this);
169 m_partToolBar->setMovable(true);
170 m_partToolBar->setFloatable(true);
171 m_partToolBar->setAllowedAreas(Qt::AllToolBarAreas);
172
173 m_partName = new QLabel("NONE");
174 f = m_partName->font();
175 f.setBold(true);
176 m_partName->setFont(f);
177
178 m_partToolBar->addWidget(m_partName)->setCheckable(false);
179
180 m_partToolBar->addSeparator();
181 openSequenceAction = m_partToolBar->addAction(QIcon(":/file-new.svg"), "Open Sequence Tab");
182 m_partToolBar->addSeparator();
183 m_runSinglePart = m_partToolBar->addAction(QIcon(":/play.svg"), "Run all joints of this part");
184 m_idleSinglePart = m_partToolBar->addAction(QIcon(":/idle.svg"), "Idle all joints of this part");
185 m_calibSinglePart = m_partToolBar->addAction(QIcon(":/images/calibrate.png"), "Calibrate all joints of this part");
186 m_homeSinglePart = m_partToolBar->addAction(QIcon(":/home.svg"), "Home all joints of this part");
187
188 m_customPositionsSinglePartToolbar.reserve(customPositions.size());
189 if (customPositions.size() > 0) {
190 for (std::map<std::string, yarp::os::Bottle>::const_iterator it(customPositions.begin()); it != customPositions.end(); ++it) {
191 QAction *newAction = m_partToolBar->addAction(QIcon(":/home.svg"), ("Move all joints of this part to " + it->first).c_str());
192 m_customPositionsSinglePartToolbar.push_back(newAction);
193 //
194 const yarp::os::Bottle &position = it->second;
195
196 //copy position in the lambda
197 connect(newAction, &QAction::triggered, this, [this, position]{onHomeSinglePartToCustomPosition(position); });
198 }
199 }
200
201 addToolBar(m_partToolBar);
202
203 m_currentPartMenu = m_ui->menuBar->addMenu("Current Part: ");
204 m_currentPartMenu->addAction(openSequenceAction);
205 m_currentPartMenu->addSeparator();
206 m_currentPartMenu->addAction(m_runSinglePart);
207 m_currentPartMenu->addAction(m_calibSinglePart);
208 m_currentPartMenu->addAction(m_homeSinglePart);
209 m_currentPartMenu->addAction(m_idleSinglePart);
210
211 m_customPositionsSinglePart.reserve(customPositions.size());
212 if (customPositions.size() > 0) {
213
214 //If there are customPositions create a submenu item
215 QMenu *customPositionsMenu = m_currentPartMenu->addMenu(QIcon(":/home.svg"), "Custom positions");
216
217 unsigned keyIndex = 0;
218 for (std::map<std::string, yarp::os::Bottle>::const_iterator it(customPositions.begin()); it != customPositions.end(); ++it) {
219 QAction *newAction = customPositionsMenu->addAction(("Move all joints of this part to " + it->first).c_str());
220 m_customPositionsSinglePartToolbar.push_back(newAction);
221 //
222 const yarp::os::Bottle &position = it->second;
223
224 // Adding shortcut (to only the first 9 sequences)
225 if (keyIndex < 9) {
226 QKeySequence shortcut(Qt::CTRL + Qt::ALT + Qt::META + (Qt::Key_1 + keyIndex++));
227 newAction->setShortcut(shortcut);
228 newAction->setShortcutContext(Qt::ApplicationShortcut);
229 }
230 //copy position in the lambda
231 connect(newAction, &QAction::triggered, this, [this, position]{onHomeSinglePartToCustomPosition(position); });
232
233 }
234 }
235
236
237 connect(openSequenceAction,SIGNAL(triggered()),this,SLOT(onOpenSequenceTab()));
238 connect(m_runSinglePart, SIGNAL(triggered()), this, SLOT(onRunSinglePart()));
239 connect(m_idleSinglePart, SIGNAL(triggered()), this, SLOT(onIdleSinglePart()));
240 connect(m_homeSinglePart, SIGNAL(triggered()), this, SLOT(onHomeSinglePart()));
241 connect(m_calibSinglePart, SIGNAL(triggered()), this, SLOT(onCalibSinglePart()));
242
243 QMenu *windows = m_ui->menuBar->addMenu("View");
244 QAction *viewGlobalToolbar = windows->addAction("Global Commands Toolbar");
245 QAction *viewPartToolbar = windows->addAction("Part Commands Toolbar");
246 QAction *viewSpeedValues = windows->addAction("View Speed Values");
247 QAction *viewCurrentValues = windows->addAction("View Current Values");
248 QAction *viewMotorPosition = windows->addAction("View Motor Position");
249 QAction *viewDutyCycles = windows->addAction("View Duty Cycles");
250 QAction *viewPositionTargetBox = windows->addAction("View Position Target Box");
251 QAction* viewPositionTargetValue = windows->addAction("View Position Target Value");
252 QAction *enableControlVelocity = windows->addAction("Enable Velocity Control");
253 QAction *enableControlMixed = windows->addAction("Enable Mixed Control");
254 QAction *enableControlPositionDirect = windows->addAction("Enable Position Direct Control");
255 QAction *enableControlPWM = windows->addAction("Enable PWM Control");
256 QAction *enableControlCurrent = windows->addAction("Enable Current Control");
257 QAction *enableControlTorque = windows->addAction("Enable Torque Control");
258 QAction *sliderOptions = windows->addAction("Slider Options...");
259
260 viewGlobalToolbar->setCheckable(true);
261 viewPartToolbar->setCheckable(true);
262 viewSpeedValues->setCheckable(true);
263 viewCurrentValues->setCheckable(true);
264 viewMotorPosition->setCheckable(true);
265 viewDutyCycles->setCheckable(true);
266 enableControlVelocity->setCheckable(true);
267 enableControlMixed->setCheckable(true);
268 enableControlPositionDirect->setCheckable(true);
269 enableControlPWM->setCheckable(true);
270 enableControlCurrent->setCheckable(true);
271 enableControlTorque->setCheckable(true);
272 viewPositionTargetBox->setCheckable(true);
273 viewPositionTargetValue->setCheckable(true);
274
275 QSettings settings("YARP","yarpmotorgui");
276 bool bViewGlobalToolbar = settings.value("GlobalToolVisible",true).toBool();
277 bool bViewPartToolbar = settings.value("PartToolVisible",true).toBool();
278 bool bSpeedValues = settings.value("SpeedValuesVisible",false).toBool();
279 bool bViewPositionTargetBox = settings.value("ViewPositionTargetBox", true).toBool();
280 bool bViewPositionTargetValue = settings.value("ViewPositionTargetValue", false).toBool();
281 bool bviewMotorPosition = settings.value("MotorPositionVisible", false).toBool();
282 bool bviewDutyCycles = settings.value("DutyCycleVisible", false).toBool();
283 bool bCurrentValues = settings.value("CurrentsVisible", false).toBool();
284
287 viewSpeedValues->setChecked(bSpeedValues);
290 viewDutyCycles->setChecked(bviewDutyCycles);
291 viewPositionTargetBox->setChecked(bViewPositionTargetBox);
292 viewPositionTargetValue->setChecked(bViewPositionTargetValue);
293 enableControlVelocity->setChecked(false);
294 enableControlMixed->setChecked(false);
295 enableControlPositionDirect->setChecked(false);
296 enableControlPWM->setChecked(false);
297 enableControlCurrent->setChecked(false);
298 enableControlTorque->setChecked(false);
299
300 m_globalToolBar->setVisible(bViewGlobalToolbar);
301 m_partToolBar->setVisible(bViewPartToolbar);
302
303 connect(viewGlobalToolbar,SIGNAL(triggered(bool)),this,SLOT(onViewGlobalToolbar(bool)));
304 connect(viewPartToolbar,SIGNAL(triggered(bool)),this,SLOT(onViewPartToolbar(bool)));
305 connect(viewSpeedValues,SIGNAL(triggered(bool)),this,SLOT(onViewSpeeds(bool)));
306 connect(viewCurrentValues, SIGNAL(triggered(bool)), this, SLOT(onViewCurrents(bool)));
307 connect(viewMotorPosition, SIGNAL(triggered(bool)), this, SLOT(onViewMotorPositions(bool)));
308 connect(viewDutyCycles, SIGNAL(triggered(bool)), this, SLOT(onViewDutyCycles(bool)));
309 connect(viewPositionTargetBox, SIGNAL(triggered(bool)), this, SLOT(onViewPositionTargetBox(bool)));
310 connect(viewPositionTargetValue, SIGNAL(triggered(bool)), this, SLOT(onViewPositionTargetValue(bool)));
311 connect(enableControlVelocity, SIGNAL(triggered(bool)), this, SLOT(onEnableControlVelocity(bool)));
312 connect(enableControlMixed, SIGNAL(triggered(bool)), this, SLOT(onEnableControlMixed(bool)));
313 connect(enableControlPositionDirect, SIGNAL(triggered(bool)), this, SLOT(onEnableControlPositionDirect(bool)));
314 connect(enableControlPWM, SIGNAL(triggered(bool)), this, SLOT(onEnableControlPWM(bool)));
315 connect(enableControlCurrent, SIGNAL(triggered(bool)), this, SLOT(onEnableControlCurrent(bool)));
316 connect(enableControlTorque, SIGNAL(triggered(bool)), this, SLOT(onEnableControlTorque(bool)));
317 connect(sliderOptions, SIGNAL(triggered()), this, SLOT(onSliderOptionsClicked()));
318
319 connect(this,SIGNAL(sig_internalClose()),this,SLOT(close()),Qt::QueuedConnection);
320
321 auto* lay = new QHBoxLayout();
322 lay->setMargin(0);
323 lay->setSpacing(0);
324 lay->setSizeConstraint(QLayout::SetMaximumSize);
325 m_ui->treeWidgetContainer->setLayout(lay);
326 m_modesTreeManager = new ModesTreeManager(lay, m_ui->treeWidgetContainer);
327 connect(m_modesTreeManager, SIGNAL(sig_jointClicked(int,int)), this, SLOT(onJointClicked(int,int)));
328 connect(m_modesTreeManager, SIGNAL(sig_partDoubleClicked(int)), this, SLOT(onPartDoubleClicked(int)));
329
330 m_timer.setInterval(200);
331 m_timer.setSingleShot(false);
332 connect(&m_timer, SIGNAL(timeout()), this, SLOT(onUpdate()), Qt::QueuedConnection);
333 m_timer.start();
334
335 const qreal blurRadius = 40.0;
336 const int glowDuration_msec = 2000;
337 m_glowEffect = new QGraphicsDropShadowEffect(this);
338 m_glowEffect->setOffset(.0);
339 m_glowEffect->setBlurRadius(blurRadius);
340 m_glowEffect->setColor(Qt::yellow);
341 m_glowTimer.setInterval(glowDuration_msec);
342 m_glowTimer.setSingleShot(true);
343 connect(&m_glowTimer, SIGNAL(timeout()), this, SLOT(onGlowTimerExpired()));
344}
345
347{
348 m_mutex.lock();
349
350 disconnect(&m_timer, SIGNAL(timeout()), this, SLOT(onUpdate()));
351 m_timer.stop();
352
353 onStopAllSeq();
354
355 if (m_tabPanel){
356 disconnect(m_tabPanel, SIGNAL(currentChanged(int)), this, SLOT(onCurrentPartChanged(int)));
357 for (int i = 0; i<m_tabPanel->count(); i++)
358 {
359 if (m_tabPanel->widget(i))
360 {
361 delete m_tabPanel->widget(i);
362 }
363 }
364 delete m_tabPanel;
365 m_tabPanel = nullptr;
366 }
367
368 delete m_ui;
369
370 m_mutex.unlock();
371}
372
374{
376 this->close();
377}
378
379void MainWindow::onSequenceActivated()
380{
381 m_sequenceActiveCount++;
382 m_goAll->setEnabled(false);
383 m_runAllSeq->setEnabled(false);
384 m_runAllSeqTime->setEnabled(false);
385 m_saveAllSeq->setEnabled(false);
386 m_loadAllSeq->setEnabled(false);
387 m_cycleAllSeq->setEnabled(false);
388 m_cycleAllSeqTime->setEnabled(false);
389 m_runAllParts->setEnabled(false);
390 m_idleAllParts->setEnabled(false);
391 m_homeAllParts->setEnabled(false);
392}
393
394void MainWindow::onSequenceStopped()
395{
396 m_sequenceActiveCount--;
397 if (m_sequenceActiveCount <= 0)
398 {
399 m_sequenceActiveCount = 0;
400 m_goAll->setEnabled(true);
401 m_runAllSeq->setEnabled(true);
402 m_runAllSeqTime->setEnabled(true);
403 m_saveAllSeq->setEnabled(true);
404 m_loadAllSeq->setEnabled(true);
405 m_cycleAllSeq->setEnabled(true);
406 m_cycleAllSeqTime->setEnabled(true);
407 m_runAllParts->setEnabled(true);
408 m_idleAllParts->setEnabled(true);
409 m_homeAllParts->setEnabled(true);
410 }
411}
412
413
414void MainWindow::onViewGlobalToolbar(bool val)
415{
416 QSettings settings("YARP","yarpmotorgui");
417 settings.setValue("GlobalToolVisible",val);
418 if(!val){
419 m_globalToolBar->hide();
420 }else{
421 m_globalToolBar->show();
422 }
423
424}
425
426void MainWindow::onViewPartToolbar(bool val)
427{
428 QSettings settings("YARP","yarpmotorgui");
429 settings.setValue("PartToolVisible",val);
430 if(!val){
431 m_partToolBar->hide();
432 }else{
433 m_partToolBar->show();
434 }
435}
436
437void MainWindow::onEnableControlVelocity(bool val)
438{
440}
441
442void MainWindow::onEnableControlMixed(bool val)
443{
445}
446
447void MainWindow::onEnableControlPositionDirect(bool val)
448{
450}
451
452void MainWindow::onEnableControlPWM(bool val)
453{
455}
456
457void MainWindow::onEnableControlCurrent(bool val)
458{
460}
461
462void MainWindow::onEnableControlTorque(bool val)
463{
465}
466
467void MainWindow::onSliderOptionsClicked()
468{
469 m_sliderOpt = new sliderOptions(this);
470
471 m_sliderOpt->exec();
472
473 delete m_sliderOpt;
474 m_sliderOpt = nullptr;
475}
476
477void MainWindow::onViewSpeeds(bool val)
478{
479 QSettings settings("YARP","yarpmotorgui");
480 settings.setValue("SpeedValuesVisible",val);
481
483}
484
485void MainWindow::onViewCurrents(bool val)
486{
487 QSettings settings("YARP", "yarpmotorgui");
488 settings.setValue("CurrentValuesVisible", val);
489
491}
492
493void MainWindow::onViewMotorPositions(bool val)
494{
495 QSettings settings("YARP", "yarpmotorgui");
496 settings.setValue("MotorPositionVisible", val);
497
499}
500
501void MainWindow::onViewDutyCycles(bool val)
502{
503 QSettings settings("YARP", "yarpmotorgui");
504 settings.setValue("DutyCyclesVisible", val);
505
507}
508
509void MainWindow::onViewPositionTargetBox(bool val)
510{
511 QSettings settings("YARP", "yarpmotorgui");
512 settings.setValue("ViewPositionTarget", val);
513
515}
516
517void MainWindow::onViewPositionTargetValue(bool val)
518{
519 QSettings settings("YARP", "yarpmotorgui");
520 settings.setValue("ViewPositionTarget", val);
521
523}
524
525void MainWindow::onSetPosSliderOptionMW(int choice, double val, int digits)
526{
528}
529void MainWindow::onSetVelSliderOptionMW(int choice, double val)
530{
532}
533void MainWindow::onSetTrqSliderOptionMW(int choice, double val)
534{
536}
537
538void MainWindow::onJointClicked(int partIndex, int jointIndex)
539{
540 if (!m_tabPanel){
541 return;
542 }
543
544 m_tabPanel->setCurrentIndex(partIndex);
545 auto* scroll = static_cast<QScrollArea*>(m_tabPanel->widget(partIndex));
546 auto* part = static_cast<PartItem*>(scroll->widget());
547 auto* jointWidget = part->getJointWidget(jointIndex);
548 scroll->ensureWidgetVisible(jointWidget);
549 m_glowEffect->setEnabled(false);
550 jointWidget->setGraphicsEffect(m_glowEffect);
551 m_glowEffect->setEnabled(true);
552 m_glowTimer.start();
553}
554
555void MainWindow::onGlowTimerExpired()
556{
557 m_glowEffect->setEnabled(false);
558}
559
560void MainWindow::onPartDoubleClicked(int partIndex)
561{
562 if (!m_tabPanel){
563 return;
564 }
565
566 m_tabPanel->setCurrentIndex(partIndex);
567}
568
570{
571
572 m_mutex.lock();
573
574 this->setVisible(false);
575
576 disconnect(&m_timer, SIGNAL(timeout()), this, SLOT(onUpdate()));
577 m_timer.stop();
578
579 onStopAllSeq();
580
581 if (m_tabPanel){
582 disconnect(m_tabPanel, SIGNAL(currentChanged(int)), this, SLOT(onCurrentPartChanged(int)));
583 for (int i = 0; i<m_tabPanel->count(); i++){
584 if (m_tabPanel->widget(i)){
585 delete m_tabPanel->widget(i);
586 }
587 }
588 delete m_tabPanel;
589 m_tabPanel = nullptr;
590 }
591
592 m_mutex.unlock();
593
594 QMainWindow::closeEvent(event);
595
596}
597
598
599
600
601bool MainWindow::init(std::vector<std::string> enabledParts,
605 bool enable_calib_all)
606{
607 m_tabPanel = new QTabWidget(m_ui->mainContainer);
608
610 {
611 m_calibSinglePart->setEnabled(false);
612 }
613
614 int errorCount = 0;
615 QScrollArea *scroll = nullptr;
616 PartItem *part = nullptr;
617 m_finder = finder;
618 m_user_script1 = m_finder.find("script1").asString();
619 m_user_script2 = m_finder.find("script2").asString();
620
621 struct robot_type
622 {
623 std::string robot_name_without_slash;
624 };
625
626 struct part_type
627 {
628 std::string robot_name_without_slash;
629 std::string robot_name;
630 std::string complete_name;
631 std::string part_name_without_slash;
632 int partindex;
633 };
634
635 std::map<std::string, robot_type> robots;
636 std::map<std::string, part_type> parts;
637
638 for (int i = 0; i < enabledParts.size(); i++)
639 {
640 std::string ss = enabledParts.at(i);
641 size_t b1 = ss.find('/');
642 size_t b2 = ss.find('/', b1 + 1);
643 if (b1 == std::string::npos ||
644 b2 == std::string::npos)
645 {
646 yError() << "Invalid parts name, missing / char?";
647 return false;
648 }
649 std::string cur_robot_name = ss.substr(b1, b2 - b1);
650 auto it = robots.find(cur_robot_name);
651 if (it == robots.end())
652 {
653 robot_type r;
654 r.robot_name_without_slash = cur_robot_name;
655 if (r.robot_name_without_slash[0] == '/') {
656 r.robot_name_without_slash.erase(0, 1);
657 }
659 }
660 part_type p;
661 p.partindex = i;
662 p.complete_name = enabledParts.at(i);
663 p.part_name_without_slash = ss.substr(b2);
664 if (p.part_name_without_slash[0] == '/') {
665 p.part_name_without_slash.erase(0, 1);
666 }
667 p.robot_name = cur_robot_name;
668 p.robot_name_without_slash = robots[cur_robot_name].robot_name_without_slash;
669 parts[ss.substr(b2)] = p;
670 }
671
672 for (auto& robot : robots)
673 {
674 m_modesTreeManager->addRobot(robot.first.c_str());
675 }
676
677 for (auto& i_parts : parts)
678 {
679 //JointItem *item = new JointItem();
680 //layout->addWidget(item);
681 scroll = new QScrollArea(m_tabPanel);
682 scroll->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
683 scroll->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
684 scroll->setWidgetResizable(true);
685 std::string part_name = i_parts.first;
686 std::string robot_name = i_parts.second.robot_name;
687 std::string robot_name_without_slash = i_parts.second.robot_name_without_slash;
688 std::string part_name_without_slash = i_parts.second.part_name_without_slash;
689 int part_id = i_parts.second.partindex;
691
692 if(part && !part->getInterfaceError())
693 {
694 connect(part,SIGNAL(sequenceActivated()),this,SLOT(onSequenceActivated()));
695 connect(part,SIGNAL(sequenceStopped()),this,SLOT(onSequenceStopped()));
696 connect(this,SIGNAL(sig_viewSpeedValues(bool)),part,SLOT(onViewSpeedValues(bool)));
697 connect(this, SIGNAL(sig_viewCurrentValues(bool)), part, SLOT(onViewCurrentValues(bool)));
698 connect(this, SIGNAL(sig_viewMotorPositions(bool)), part, SLOT(onViewMotorPositions(bool)));
699 connect(this, SIGNAL(sig_viewDutyCycles(bool)), part, SLOT(onViewDutyCycles(bool)));
700 connect(this, SIGNAL(sig_setPosSliderOptionMW(int,double,int)), part, SLOT(onSetPosSliderOptionPI(int,double,int)));
701 connect(this, SIGNAL(sig_setVelSliderOptionMW(int,double)), part, SLOT(onSetVelSliderOptionPI(int,double)));
702 connect(this, SIGNAL(sig_setTrqSliderOptionMW(int,double)), part, SLOT(onSetTrqSliderOptionPI(int,double)));
703 connect(this, SIGNAL(sig_viewPositionTargetBox(bool)), part, SLOT(onViewPositionTargetBox(bool)));
704 connect(this, SIGNAL(sig_viewPositionTargetValue(bool)), part, SLOT(onViewPositionTargetValue(bool)));
705 connect(this, SIGNAL(sig_enableControlVelocity(bool)), part, SLOT(onEnableControlVelocity(bool)));
706 connect(this, SIGNAL(sig_enableControlMixed(bool)), part, SLOT(onEnableControlMixed(bool)));
707 connect(this, SIGNAL(sig_enableControlPositionDirect(bool)), part, SLOT(onEnableControlPositionDirect(bool)));
708 connect(this, SIGNAL(sig_enableControlPWM(bool)), part, SLOT(onEnableControlPWM(bool)));
709 connect(this, SIGNAL(sig_enableControlCurrent(bool)), part, SLOT(onEnableControlCurrent(bool)));
710 connect(this, SIGNAL(sig_enableControlTorque(bool)), part, SLOT(onEnableControlTorque(bool)));
711
712 scroll->setWidget(part);
713 int tabIndex = m_tabPanel->addTab(scroll, part_name.c_str());
714 if (part_id == 0)
715 {
716 QString auxName = part_name.c_str();
717 auxName.replace(0, 1, QString(part_name.c_str()).at(0).toUpper());
718 m_currentPartMenu->setTitle(QString("%1 Commands ").arg(auxName));
719 this->m_partName->setText(QString("%1 Commands ").arg(auxName));
720 }
721
722 m_modesTreeManager->addRobotPart(robot_name, part_name, tabIndex, part);
723 }
724 else
725 {
726 if(part)
727 {
728 delete part;
729 part = nullptr;
730 }
731 if(scroll)
732 {
733 delete scroll;
734 scroll = nullptr;
735 }
736 errorCount++;
737 }
738 }
739
740 if((unsigned int)errorCount == parts.size())
741 {
742 return false;
743 }
744
745 auto* lay = new QHBoxLayout();
746 lay->setMargin(0);
747 lay->setSpacing(0);
748 m_ui->mainContainer->setLayout(lay);
749 m_ui->mainContainer->layout()->addWidget(m_tabPanel);
750 connect(m_tabPanel, SIGNAL(currentChanged(int)), this, SLOT(onCurrentPartChanged(int)));
751
752 QSettings settings("YARP","yarpmotorgui");
753 bool speedVisible = settings.value("SpeedValuesVisible",false).toBool();
754 bool motorPosVisible = settings.value("MotorPositionVisible", false).toBool();
755 bool currentVisible = settings.value("CurrentsVisible", false).toBool();
756 bool dutyVisible = settings.value("DutyCyclesVisible", false).toBool();
757
758 onViewSpeeds(speedVisible);
759 onViewCurrents(currentVisible);
760 onViewMotorPositions(motorPosVisible);
761 onViewDutyCycles(dutyVisible);
762 return true;
763}
764
765
766void MainWindow::onCurrentPartChanged(int index)
767{
768 if(index < 0){
769 return;
770 }
771 QString partName = m_tabPanel->tabText(index);
772
773 QString auxName = partName;
774 auxName.replace(0,1,partName.at(0).toUpper());
775 m_currentPartMenu->setTitle(QString("%1 Commands").arg(auxName));
776 this->m_partName->setText(QString("%1 Commands").arg(auxName));
777
778 auto* scroll = (QScrollArea *)m_tabPanel->widget(index);
779 auto* part = (PartItem*)scroll->widget();
780 if(!part){
781 return;
782 }
783
784 part->resizeWidget(part->width());
785
786}
787
788void MainWindow::onCalibSinglePart()
789{
790 if (!m_tabPanel){
791 return;
792 }
793
794 auto* scroll = (QScrollArea *)m_tabPanel->currentWidget();
795 auto* part = (PartItem*)scroll->widget();
796 if(!part){
797 return;
798 }
799
800 if (QMessageBox::question(this, "Question", QString("Do you really want to recalibrate all joints of this part?")) == QMessageBox::Yes)
801 {
802 part->calibratePart(); // Error message is thrown inside
803 }
804}
805
806void MainWindow::onExecuteScript1()
807{
808 if (m_user_script1 == "")
809 {
810 QMessageBox::information(this, "Info", QString("user script1 not specified. use --script1 option"));
811 return;
812 }
813
814 if (QMessageBox::question(this, "Question", QString("Do you really want to execute user script1?")) == QMessageBox::Yes)
815 {
816 if (system(nullptr))
817 {
818 std::string script1_file = this->m_finder.findFileByName(m_user_script1);
819 if (script1_file != "")
820 {
821 int r = system(script1_file.c_str());
822 yDebug() << "yarpmotorgui_script1 returned value:" << r;
823 }
824 else
825 {
826 QMessageBox::information(this, "Info", QString("Unable to find script1 file"));
827 }
828 }
829 else
830 {
831 QMessageBox::information(this, "Info", QString("System is unable to run script1"));
832 }
833 }
834}
835
836void MainWindow::onExecuteScript2()
837{
838 if (m_user_script2 == "")
839 {
840 QMessageBox::information(this, "Info", QString("user script2 not specified. use --script2 option"));
841 return;
842 }
843
844 if (QMessageBox::question(this, "Question", QString("Do you really want to execute user script2?")) == QMessageBox::Yes)
845 {
846 if (system(nullptr))
847 {
848 std::string script2_file = this->m_finder.findFileByName(m_user_script2);
849 if (script2_file != "")
850 {
851 int r = system(script2_file.c_str());
852 yDebug() << "yarpmotorgui_script2 returned value:" << r;
853 }
854 else
855 {
856 QMessageBox::information(this, "Info", QString("Unable to find script2 file"));
857 }
858 }
859 else
860 {
861 QMessageBox::information(this, "Info", QString("System is unable to run script2"));
862 }
863 }
864}
865
866void MainWindow::onHomeSinglePart()
867{
868 if (QMessageBox::question(this, "Question", "Do you really want to home all joints of this part?") != QMessageBox::Yes){
869 return;
870 }
871
872 if (!m_tabPanel){
873 return;
874 }
875
876 auto* scroll = (QScrollArea *)m_tabPanel->currentWidget();
877 auto* part = (PartItem*)scroll->widget();
878 if (!part){
879 return;
880 }
881
882 part->homePart();
883}
884
885void MainWindow::onHomeAllParts()
886{
887 if (QMessageBox::question(this, "Question", "Do you really want to home all parts?") != QMessageBox::Yes){
888 return;
889 }
890
891 if (!m_tabPanel){
892 return;
893 }
894
895 for (int i = 0; i<m_tabPanel->count(); i++)
896 {
897 auto* scroll = (QScrollArea *)m_tabPanel->widget(i);
898 auto* part = (PartItem*)scroll->widget();
899 if (!part)
900 {
901 continue;
902 }
903
904 part->homePart();
905 }
906}
907
908void MainWindow::onHomeAllPartsToCustomPosition(const yarp::os::Bottle& positionElement)
909{
910 if (QMessageBox::question(this, "Question", "Do you really want to home all parts?") != QMessageBox::Yes){
911 return;
912 }
913
914 if (!m_tabPanel){
915 return;
916 }
917
918 for (int i = 0; i<m_tabPanel->count(); i++)
919 {
920 auto* scroll = (QScrollArea *)m_tabPanel->widget(i);
921 auto* part = (PartItem*)scroll->widget();
922 QString currName = QString("/%1/%2").arg(QString(m_finder.find("robot").asString().c_str())).arg(part->getPartName());
923 bool partPresent = positionElement.check(currName.toStdString() + "_Position") && positionElement.check(currName.toStdString() + "_Velocity");
924 if(!part || ! partPresent)
925 {
926 continue;
927 }
928 part->homeToCustomPosition(positionElement);
929 }
930}
931
932void MainWindow::onHomeSinglePartToCustomPosition(const yarp::os::Bottle& positionElement)
933{
934 if (QMessageBox::question(this, "Question", "Do you really want to home all joints of this part?") != QMessageBox::Yes){
935 return;
936 }
937
938 if (!m_tabPanel){
939 return;
940 }
941
942 auto* scroll = (QScrollArea *)m_tabPanel->currentWidget();
943 auto* part = (PartItem*)scroll->widget();
944 if(!part){
945 return;
946 }
947
948 part->homeToCustomPosition(positionElement);
949}
950
951void MainWindow::onIdleSinglePart()
952{
953 if (!m_tabPanel){
954 return;
955 }
956
957 auto* scroll = (QScrollArea *)m_tabPanel->currentWidget();
958 auto* part = (PartItem*)scroll->widget();
959 if(!part){
960 return;
961 }
962
963 part->idlePart();
964}
965
966void MainWindow::onCycleTimeAllSeq()
967{
968 if (!m_tabPanel){
969 return;
970 }
971
973
974 for (int i = 0; i<m_tabPanel->count(); i++){
975 auto* scroll = (QScrollArea *)m_tabPanel->widget(i);
976 auto* part = (PartItem*)scroll->widget();
977 if(!part){
978 continue;
979 }
980
981 bool done = part->checkAndCycleTimeAllSeq();
982 if(!done){
983 notSelectedParts.append(QString("- %1\n").arg(part->getPartName()));
984 }
985 }
986 if(!notSelectedParts.isEmpty()){
987 QMessageBox::critical(this,"Error", QString("Load a valid sequence before performing this action for these parts:\n%1").arg(notSelectedParts));
988 }
989}
990
991void MainWindow::onCycleAllSeq()
992{
993 if (!m_tabPanel){
994 return;
995 }
996
998
999 for (int i = 0; i<m_tabPanel->count(); i++){
1000 auto* scroll = (QScrollArea *)m_tabPanel->widget(i);
1001 auto* part = (PartItem*)scroll->widget();
1002 if(!part){
1003 continue;
1004 }
1005
1006 bool done = part->checkAndCycleAllSeq();
1007 if(!done){
1008 notSelectedParts.append(QString("- %1\n").arg(part->getPartName()));
1009 }
1010 }
1011 if(!notSelectedParts.isEmpty()){
1012 QMessageBox::critical(this,"Error", QString("Load a valid sequence before performing this action for these parts:\n%1").arg(notSelectedParts));
1013 }
1014}
1015
1016void MainWindow::onRunAllSeq()
1017{
1018 if (!m_tabPanel){
1019 return;
1020 }
1021
1023
1024 for (int i = 0; i<m_tabPanel->count(); i++){
1025 auto* scroll = (QScrollArea *)m_tabPanel->widget(i);
1026 auto* part = (PartItem*)scroll->widget();
1027 if(!part){
1028 continue;
1029 }
1030
1031 bool done = part->checkAndRunAllSeq();
1032 if(!done){
1033 notSelectedParts.append(QString("- %1\n").arg(part->getPartName()));
1034 }
1035 }
1036 if(!notSelectedParts.isEmpty()){
1037 QMessageBox::critical(this,"Error", QString("Load a valid sequence before performing this action for these parts:\n%1").arg(notSelectedParts));
1038 }
1039}
1040
1041
1042void MainWindow::onRunTimeAllSeq()
1043{
1044 if (!m_tabPanel){
1045 return;
1046 }
1047
1049
1050 for (int i = 0; i<m_tabPanel->count(); i++){
1051 auto* scroll = (QScrollArea *)m_tabPanel->widget(i);
1052 auto* part = (PartItem*)scroll->widget();
1053 if(!part){
1054 continue;
1055 }
1056
1057 bool done = part->checkAndRunTimeAllSeq();
1058 if(!done){
1059 notSelectedParts.append(QString("- %1\n").arg(part->getPartName()));
1060 }
1061 }
1062 if(!notSelectedParts.isEmpty()){
1063 QMessageBox::critical(this,"Error", QString("Load a valid sequence before performing this action for these parts:\n%1").arg(notSelectedParts));
1064 }
1065}
1066
1067void MainWindow::onLoadAllSeq()
1068{
1069 if (!m_tabPanel){
1070 return;
1071 }
1072
1073
1074 for (int i = 0; i<m_tabPanel->count(); i++){
1075 auto* scroll = (QScrollArea *)m_tabPanel->widget(i);
1076 auto* part = (PartItem*)scroll->widget();
1077 if(!part){
1078 continue;
1079 }
1080
1081 part->loadSequence();
1082
1083 }
1084}
1085
1086void MainWindow::onSaveAllSeq()
1087{
1088 if (!m_tabPanel){
1089 return;
1090 }
1091
1092 QString fileName = QFileDialog::getSaveFileName(this, QString("Save Sequence for all parts as:"), QDir::homePath());
1093
1094 for (int i = 0; i<m_tabPanel->count(); i++)
1095 {
1096 auto* scroll = (QScrollArea *)m_tabPanel->widget(i);
1097 auto* part = (PartItem*)scroll->widget();
1098 if(!part)
1099 {
1100 continue;
1101 }
1102 part->saveSequence(fileName);
1103 part->closeSequenceWindow();
1104 }
1105}
1106
1107void MainWindow::onStopAllSeq()
1108{
1109 if (!m_tabPanel){
1110 return;
1111 }
1112
1113
1114 for (int i = 0; i<m_tabPanel->count(); i++){
1115 auto* scroll = (QScrollArea *)m_tabPanel->widget(i);
1116 auto* part = (PartItem*)scroll->widget();
1117 if(!part){
1118 continue;
1119 }
1120
1121 part->stopSequence();
1122
1123 }
1124
1125 }
1126
1127void MainWindow::onGoAll()
1128{
1129 if (!m_tabPanel){
1130 return;
1131 }
1132
1134
1135 for (int i = 0; i<m_tabPanel->count(); i++){
1136 auto* scroll = (QScrollArea *)m_tabPanel->widget(i);
1137 auto* part = (PartItem*)scroll->widget();
1138 if(!part){
1139 continue;
1140 }
1141
1142 bool done = part->checkAndGo();
1143 if(!done){
1144 notSelectedParts.append(QString("- %1\n").arg(part->getPartName()));
1145 }
1146 }
1147
1148 if(!notSelectedParts.isEmpty()){
1149 QMessageBox::critical(this,"Error", QString("Select a valid entry in the table before performing a movement for these parts:\n%1").arg(notSelectedParts));
1150 }
1151
1152}
1153
1154void MainWindow::onIdleAllParts()
1155{
1156 if (QMessageBox::question(this, "Question", "Do you really want to idle all parts?") != QMessageBox::Yes){
1157 return;
1158 }
1159
1160 if (!m_tabPanel){
1161 return;
1162 }
1163
1164 for (int i = 0; i<m_tabPanel->count(); i++)
1165 {
1166 auto* scroll = (QScrollArea *)m_tabPanel->widget(i);
1167 auto* part = (PartItem*)scroll->widget();
1168 if (!part){
1169 continue;
1170 }
1171
1172 part->idlePart();
1173 }
1174}
1175
1176void MainWindow::onRunAllParts()
1177{
1178 if (!m_tabPanel){
1179 return;
1180 }
1181
1182 for (int i = 0; i<m_tabPanel->count(); i++){
1183 auto* scroll = (QScrollArea *)m_tabPanel->widget(i);
1184 auto* part = (PartItem*)scroll->widget();
1185 if(!part){
1186 continue;
1187 }
1188
1189 part->runPart();
1190 }
1191}
1192
1193void MainWindow::onRunSinglePart()
1194{
1195 if (!m_tabPanel){
1196 return;
1197 }
1198
1199 auto* scroll = (QScrollArea *)m_tabPanel->currentWidget();
1200 auto* part = (PartItem*)scroll->widget();
1201 if(!part){
1202 return;
1203 }
1204
1205 part->runPart();
1206}
1207
1208void MainWindow::onOpenSequenceTab()
1209{
1210 if (!m_tabPanel){
1211 return;
1212 }
1213
1214 auto* scroll = (QScrollArea *)m_tabPanel->currentWidget();
1215 auto* part = (PartItem*)scroll->widget();
1216 if(!part){
1217 return;
1218 }
1219 part->openSequenceWindow();
1220}
1221
1222
1223
1224void MainWindow::onUpdate()
1225{
1226 if (!m_tabPanel){
1227 return;
1228 }
1229 m_mutex.lock();
1230
1231 auto* scroll = (QScrollArea *)m_tabPanel->currentWidget();
1232 if(!scroll){
1233 m_mutex.unlock();
1234 return;
1235 }
1236 auto* currentPart = (PartItem*)scroll->widget();
1237 if(!currentPart){
1238 m_mutex.unlock();
1239 return;
1240 }
1241 for (int i = 0; i<m_tabPanel->count(); i++)
1242 {
1243 auto* tabScroll = (QScrollArea *)m_tabPanel->widget(i);
1244 auto* item = (PartItem*)tabScroll->widget();
1245 item->updateControlMode();
1246 m_modesTreeManager->updateRobotPart(i);
1247 if(item == currentPart)
1248 {
1249 if (item->updatePart() == false)
1250 {
1251 //this part is disconnected!
1252 }
1253 }
1254 }
1255 m_mutex.unlock();
1256}
#define yError(...)
Definition Log.h:361
#define yDebug(...)
Definition Log.h:275
int SIGNAL(int pid, int signum)
MainWindow class.
Definition display.h:22
void sig_enableControlMixed(bool)
void sig_enableControlPWM(bool)
void closeEvent(QCloseEvent *event) override
void sig_setPosSliderOptionMW(int, double, int)
void sig_enableControlTorque(bool)
void sig_setVelSliderOptionMW(int, double)
void sig_enableControlVelocity(bool)
void init(yarp::os::Property config)
Init the application with the current configuration.
MainWindow(const yarp::os::ResourceFinder &rf, yarp::dev::IBattery *ibat, QWidget *parent=0, double refresh_period=10.0)
Definition display.cpp:186
void sig_viewPositionTargetValue(bool)
void sig_viewSpeedValues(bool)
void sig_enableControlPositionDirect(bool)
void sig_setTrqSliderOptionMW(int, double)
void sig_viewMotorPositions(bool)
void sig_internalClose()
void sig_viewDutyCycles(bool)
void sig_enableControlCurrent(bool)
void sig_viewCurrentValues(bool)
void sig_viewPositionTargetBox(bool)
void updateRobotPart(int index)
void addRobotPart(const std::string &robotName, const std::string &partName, int partIndex, PartItem *part)
void addRobot(const std::string &robotName)
bool getInterfaceError()
Definition partitem.cpp:481
A simple collection of objects that can be described and transmitted in a portable way.
Definition Bottle.h:64
A mini-server for performing network communication in the background.
Helper class for finding config files and other external resources.
Value & find(const std::string &key) const override
Gets a value corresponding to a given keyword.
static ResourceFinder & getResourceFinderSingleton()
Access a ResourceFinder singleton whose lifetime will match that of the YARP library.
std::string findFileByName(const std::string &name)
Find the full path to a file.
A single value (typically within a Bottle).
Definition Value.h:43
virtual std::string asString() const
Get string value.
Definition Value.cpp:234
bool speedview_param_enabled
Definition main.cpp:35
bool debug_param_enabled
Definition main.cpp:34
bool enable_calib_all
Definition main.cpp:36
Definition aboutdlg.h:11
#define MAX_WIDTH_JOINT
Definition partitem.h:37