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 *sliderOptions = windows->addAction("Slider Options...");
258
259 viewGlobalToolbar->setCheckable(true);
260 viewPartToolbar->setCheckable(true);
261 viewSpeedValues->setCheckable(true);
262 viewCurrentValues->setCheckable(true);
263 viewMotorPosition->setCheckable(true);
264 viewDutyCycles->setCheckable(true);
265 enableControlVelocity->setCheckable(true);
266 enableControlMixed->setCheckable(true);
267 enableControlPositionDirect->setCheckable(true);
268 enableControlPWM->setCheckable(true);
269 enableControlCurrent->setCheckable(true);
270 viewPositionTargetBox->setCheckable(true);
271 viewPositionTargetValue->setCheckable(true);
272
273 QSettings settings("YARP","yarpmotorgui");
274 bool bViewGlobalToolbar = settings.value("GlobalToolVisible",true).toBool();
275 bool bViewPartToolbar = settings.value("PartToolVisible",true).toBool();
276 bool bSpeedValues = settings.value("SpeedValuesVisible",false).toBool();
277 bool bViewPositionTargetBox = settings.value("ViewPositionTargetBox", true).toBool();
278 bool bViewPositionTargetValue = settings.value("ViewPositionTargetValue", false).toBool();
279 bool bviewMotorPosition = settings.value("MotorPositionVisible", false).toBool();
280 bool bviewDutyCycles = settings.value("DutyCycleVisible", false).toBool();
281 bool bCurrentValues = settings.value("CurrentsVisible", false).toBool();
282
285 viewSpeedValues->setChecked(bSpeedValues);
288 viewDutyCycles->setChecked(bviewDutyCycles);
289 viewPositionTargetBox->setChecked(bViewPositionTargetBox);
290 viewPositionTargetValue->setChecked(bViewPositionTargetValue);
291 enableControlVelocity->setChecked(false);
292 enableControlMixed->setChecked(false);
293 enableControlPositionDirect->setChecked(false);
294 enableControlPWM->setChecked(false);
295 enableControlCurrent->setChecked(false);
296
297 m_globalToolBar->setVisible(bViewGlobalToolbar);
298 m_partToolBar->setVisible(bViewPartToolbar);
299
300 connect(viewGlobalToolbar,SIGNAL(triggered(bool)),this,SLOT(onViewGlobalToolbar(bool)));
301 connect(viewPartToolbar,SIGNAL(triggered(bool)),this,SLOT(onViewPartToolbar(bool)));
302 connect(viewSpeedValues,SIGNAL(triggered(bool)),this,SLOT(onViewSpeeds(bool)));
303 connect(viewCurrentValues, SIGNAL(triggered(bool)), this, SLOT(onViewCurrents(bool)));
304 connect(viewMotorPosition, SIGNAL(triggered(bool)), this, SLOT(onViewMotorPositions(bool)));
305 connect(viewDutyCycles, SIGNAL(triggered(bool)), this, SLOT(onViewDutyCycles(bool)));
306 connect(viewPositionTargetBox, SIGNAL(triggered(bool)), this, SLOT(onViewPositionTargetBox(bool)));
307 connect(viewPositionTargetValue, SIGNAL(triggered(bool)), this, SLOT(onViewPositionTargetValue(bool)));
308 connect(enableControlVelocity, SIGNAL(triggered(bool)), this, SLOT(onEnableControlVelocity(bool)));
309 connect(enableControlMixed, SIGNAL(triggered(bool)), this, SLOT(onEnableControlMixed(bool)));
310 connect(enableControlPositionDirect, SIGNAL(triggered(bool)), this, SLOT(onEnableControlPositionDirect(bool)));
311 connect(enableControlPWM, SIGNAL(triggered(bool)), this, SLOT(onEnableControlPWM(bool)));
312 connect(enableControlCurrent, SIGNAL(triggered(bool)), this, SLOT(onEnableControlCurrent(bool)));
313 connect(sliderOptions, SIGNAL(triggered()), this, SLOT(onSliderOptionsClicked()));
314
315 connect(this,SIGNAL(sig_internalClose()),this,SLOT(close()),Qt::QueuedConnection);
316
317 auto* lay = new QHBoxLayout();
318 lay->setMargin(0);
319 lay->setSpacing(0);
320 lay->setSizeConstraint(QLayout::SetMaximumSize);
321 m_ui->treeWidgetContainer->setLayout(lay);
322 m_modesTreeManager = new ModesTreeManager(lay, m_ui->treeWidgetContainer);
323 connect(m_modesTreeManager, SIGNAL(sig_jointClicked(int,int)), this, SLOT(onJointClicked(int,int)));
324 connect(m_modesTreeManager, SIGNAL(sig_partDoubleClicked(int)), this, SLOT(onPartDoubleClicked(int)));
325
326 m_timer.setInterval(200);
327 m_timer.setSingleShot(false);
328 connect(&m_timer, SIGNAL(timeout()), this, SLOT(onUpdate()), Qt::QueuedConnection);
329 m_timer.start();
330
331 const qreal blurRadius = 40.0;
332 const int glowDuration_msec = 2000;
333 m_glowEffect = new QGraphicsDropShadowEffect(this);
334 m_glowEffect->setOffset(.0);
335 m_glowEffect->setBlurRadius(blurRadius);
336 m_glowEffect->setColor(Qt::yellow);
337 m_glowTimer.setInterval(glowDuration_msec);
338 m_glowTimer.setSingleShot(true);
339 connect(&m_glowTimer, SIGNAL(timeout()), this, SLOT(onGlowTimerExpired()));
340}
341
343{
344 m_mutex.lock();
345
346 disconnect(&m_timer, SIGNAL(timeout()), this, SLOT(onUpdate()));
347 m_timer.stop();
348
349 onStopAllSeq();
350
351 if (m_tabPanel){
352 disconnect(m_tabPanel, SIGNAL(currentChanged(int)), this, SLOT(onCurrentPartChanged(int)));
353 for (int i = 0; i<m_tabPanel->count(); i++)
354 {
355 if (m_tabPanel->widget(i))
356 {
357 delete m_tabPanel->widget(i);
358 }
359 }
360 delete m_tabPanel;
361 m_tabPanel = nullptr;
362 }
363
364 delete m_ui;
365
366 m_mutex.unlock();
367}
368
370{
372 this->close();
373}
374
375void MainWindow::onSequenceActivated()
376{
377 m_sequenceActiveCount++;
378 m_goAll->setEnabled(false);
379 m_runAllSeq->setEnabled(false);
380 m_runAllSeqTime->setEnabled(false);
381 m_saveAllSeq->setEnabled(false);
382 m_loadAllSeq->setEnabled(false);
383 m_cycleAllSeq->setEnabled(false);
384 m_cycleAllSeqTime->setEnabled(false);
385 m_runAllParts->setEnabled(false);
386 m_idleAllParts->setEnabled(false);
387 m_homeAllParts->setEnabled(false);
388}
389
390void MainWindow::onSequenceStopped()
391{
392 m_sequenceActiveCount--;
393 if (m_sequenceActiveCount <= 0)
394 {
395 m_sequenceActiveCount = 0;
396 m_goAll->setEnabled(true);
397 m_runAllSeq->setEnabled(true);
398 m_runAllSeqTime->setEnabled(true);
399 m_saveAllSeq->setEnabled(true);
400 m_loadAllSeq->setEnabled(true);
401 m_cycleAllSeq->setEnabled(true);
402 m_cycleAllSeqTime->setEnabled(true);
403 m_runAllParts->setEnabled(true);
404 m_idleAllParts->setEnabled(true);
405 m_homeAllParts->setEnabled(true);
406 }
407}
408
409
410void MainWindow::onViewGlobalToolbar(bool val)
411{
412 QSettings settings("YARP","yarpmotorgui");
413 settings.setValue("GlobalToolVisible",val);
414 if(!val){
415 m_globalToolBar->hide();
416 }else{
417 m_globalToolBar->show();
418 }
419
420}
421
422void MainWindow::onViewPartToolbar(bool val)
423{
424 QSettings settings("YARP","yarpmotorgui");
425 settings.setValue("PartToolVisible",val);
426 if(!val){
427 m_partToolBar->hide();
428 }else{
429 m_partToolBar->show();
430 }
431}
432
433void MainWindow::onEnableControlVelocity(bool val)
434{
436}
437
438void MainWindow::onEnableControlMixed(bool val)
439{
441}
442
443void MainWindow::onEnableControlPositionDirect(bool val)
444{
446}
447
448void MainWindow::onEnableControlPWM(bool val)
449{
451}
452
453void MainWindow::onEnableControlCurrent(bool val)
454{
456}
457
458void MainWindow::onSliderOptionsClicked()
459{
460 m_sliderOpt = new sliderOptions(this);
461
462 m_sliderOpt->exec();
463
464 delete m_sliderOpt;
465 m_sliderOpt = nullptr;
466}
467
468void MainWindow::onViewSpeeds(bool val)
469{
470 QSettings settings("YARP","yarpmotorgui");
471 settings.setValue("SpeedValuesVisible",val);
472
474}
475
476void MainWindow::onViewCurrents(bool val)
477{
478 QSettings settings("YARP", "yarpmotorgui");
479 settings.setValue("CurrentValuesVisible", val);
480
482}
483
484void MainWindow::onViewMotorPositions(bool val)
485{
486 QSettings settings("YARP", "yarpmotorgui");
487 settings.setValue("MotorPositionVisible", val);
488
490}
491
492void MainWindow::onViewDutyCycles(bool val)
493{
494 QSettings settings("YARP", "yarpmotorgui");
495 settings.setValue("DutyCyclesVisible", val);
496
498}
499
500void MainWindow::onViewPositionTargetBox(bool val)
501{
502 QSettings settings("YARP", "yarpmotorgui");
503 settings.setValue("ViewPositionTarget", val);
504
506}
507
508void MainWindow::onViewPositionTargetValue(bool val)
509{
510 QSettings settings("YARP", "yarpmotorgui");
511 settings.setValue("ViewPositionTarget", val);
512
514}
515
516void MainWindow::onSetPosSliderOptionMW(int choice, double val, int digits)
517{
519}
520void MainWindow::onSetVelSliderOptionMW(int choice, double val)
521{
523}
524void MainWindow::onSetTrqSliderOptionMW(int choice, double val)
525{
527}
528
529void MainWindow::onJointClicked(int partIndex, int jointIndex)
530{
531 if (!m_tabPanel){
532 return;
533 }
534
535 m_tabPanel->setCurrentIndex(partIndex);
536 auto* scroll = static_cast<QScrollArea*>(m_tabPanel->widget(partIndex));
537 auto* part = static_cast<PartItem*>(scroll->widget());
538 auto* jointWidget = part->getJointWidget(jointIndex);
539 scroll->ensureWidgetVisible(jointWidget);
540 m_glowEffect->setEnabled(false);
541 jointWidget->setGraphicsEffect(m_glowEffect);
542 m_glowEffect->setEnabled(true);
543 m_glowTimer.start();
544}
545
546void MainWindow::onGlowTimerExpired()
547{
548 m_glowEffect->setEnabled(false);
549}
550
551void MainWindow::onPartDoubleClicked(int partIndex)
552{
553 if (!m_tabPanel){
554 return;
555 }
556
557 m_tabPanel->setCurrentIndex(partIndex);
558}
559
561{
562
563 m_mutex.lock();
564
565 this->setVisible(false);
566
567 disconnect(&m_timer, SIGNAL(timeout()), this, SLOT(onUpdate()));
568 m_timer.stop();
569
570 onStopAllSeq();
571
572 if (m_tabPanel){
573 disconnect(m_tabPanel, SIGNAL(currentChanged(int)), this, SLOT(onCurrentPartChanged(int)));
574 for (int i = 0; i<m_tabPanel->count(); i++){
575 if (m_tabPanel->widget(i)){
576 delete m_tabPanel->widget(i);
577 }
578 }
579 delete m_tabPanel;
580 m_tabPanel = nullptr;
581 }
582
583 m_mutex.unlock();
584
585 QMainWindow::closeEvent(event);
586
587}
588
589
590
591
592bool MainWindow::init(std::vector<std::string> enabledParts,
596 bool enable_calib_all)
597{
598 m_tabPanel = new QTabWidget(m_ui->mainContainer);
599
601 {
602 m_calibSinglePart->setEnabled(false);
603 }
604
605 int errorCount = 0;
606 QScrollArea *scroll = nullptr;
607 PartItem *part = nullptr;
608 m_finder = finder;
609 m_user_script1 = m_finder.find("script1").asString();
610 m_user_script2 = m_finder.find("script2").asString();
611
612 struct robot_type
613 {
614 std::string robot_name_without_slash;
615 };
616
617 struct part_type
618 {
619 std::string robot_name_without_slash;
620 std::string robot_name;
621 std::string complete_name;
622 std::string part_name_without_slash;
623 int partindex;
624 };
625
626 std::map<std::string, robot_type> robots;
627 std::map<std::string, part_type> parts;
628
629 for (int i = 0; i < enabledParts.size(); i++)
630 {
631 std::string ss = enabledParts.at(i);
632 size_t b1 = ss.find('/');
633 size_t b2 = ss.find('/', b1 + 1);
634 if (b1 == std::string::npos ||
635 b2 == std::string::npos)
636 {
637 yError() << "Invalid parts name, missing / char?";
638 return false;
639 }
640 std::string cur_robot_name = ss.substr(b1, b2 - b1);
641 auto it = robots.find(cur_robot_name);
642 if (it == robots.end())
643 {
644 robot_type r;
645 r.robot_name_without_slash = cur_robot_name;
646 if (r.robot_name_without_slash[0] == '/') {
647 r.robot_name_without_slash.erase(0, 1);
648 }
650 }
651 part_type p;
652 p.partindex = i;
653 p.complete_name = enabledParts.at(i);
654 p.part_name_without_slash = ss.substr(b2);
655 if (p.part_name_without_slash[0] == '/') {
656 p.part_name_without_slash.erase(0, 1);
657 }
658 p.robot_name = cur_robot_name;
659 p.robot_name_without_slash = robots[cur_robot_name].robot_name_without_slash;
660 parts[ss.substr(b2)] = p;
661 }
662
663 for (auto& robot : robots)
664 {
665 m_modesTreeManager->addRobot(robot.first.c_str());
666 }
667
668 for (auto& i_parts : parts)
669 {
670 //JointItem *item = new JointItem();
671 //layout->addWidget(item);
672 scroll = new QScrollArea(m_tabPanel);
673 scroll->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
674 scroll->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
675 scroll->setWidgetResizable(true);
676 std::string part_name = i_parts.first;
677 std::string robot_name = i_parts.second.robot_name;
678 std::string robot_name_without_slash = i_parts.second.robot_name_without_slash;
679 std::string part_name_without_slash = i_parts.second.part_name_without_slash;
680 int part_id = i_parts.second.partindex;
682
683 if(part && !part->getInterfaceError())
684 {
685 connect(part,SIGNAL(sequenceActivated()),this,SLOT(onSequenceActivated()));
686 connect(part,SIGNAL(sequenceStopped()),this,SLOT(onSequenceStopped()));
687 connect(this,SIGNAL(sig_viewSpeedValues(bool)),part,SLOT(onViewSpeedValues(bool)));
688 connect(this, SIGNAL(sig_viewCurrentValues(bool)), part, SLOT(onViewCurrentValues(bool)));
689 connect(this, SIGNAL(sig_viewMotorPositions(bool)), part, SLOT(onViewMotorPositions(bool)));
690 connect(this, SIGNAL(sig_viewDutyCycles(bool)), part, SLOT(onViewDutyCycles(bool)));
691 connect(this, SIGNAL(sig_setPosSliderOptionMW(int,double,int)), part, SLOT(onSetPosSliderOptionPI(int,double,int)));
692 connect(this, SIGNAL(sig_setVelSliderOptionMW(int,double)), part, SLOT(onSetVelSliderOptionPI(int,double)));
693 connect(this, SIGNAL(sig_setTrqSliderOptionMW(int,double)), part, SLOT(onSetTrqSliderOptionPI(int,double)));
694 connect(this, SIGNAL(sig_viewPositionTargetBox(bool)), part, SLOT(onViewPositionTargetBox(bool)));
695 connect(this, SIGNAL(sig_viewPositionTargetValue(bool)), part, SLOT(onViewPositionTargetValue(bool)));
696 connect(this, SIGNAL(sig_enableControlVelocity(bool)), part, SLOT(onEnableControlVelocity(bool)));
697 connect(this, SIGNAL(sig_enableControlMixed(bool)), part, SLOT(onEnableControlMixed(bool)));
698 connect(this, SIGNAL(sig_enableControlPositionDirect(bool)), part, SLOT(onEnableControlPositionDirect(bool)));
699 connect(this, SIGNAL(sig_enableControlPWM(bool)), part, SLOT(onEnableControlPWM(bool)));
700 connect(this, SIGNAL(sig_enableControlCurrent(bool)), part, SLOT(onEnableControlCurrent(bool)));
701
702 scroll->setWidget(part);
703 int tabIndex = m_tabPanel->addTab(scroll, part_name.c_str());
704 if (part_id == 0)
705 {
706 QString auxName = part_name.c_str();
707 auxName.replace(0, 1, QString(part_name.c_str()).at(0).toUpper());
708 m_currentPartMenu->setTitle(QString("%1 Commands ").arg(auxName));
709 this->m_partName->setText(QString("%1 Commands ").arg(auxName));
710 }
711
712 m_modesTreeManager->addRobotPart(robot_name, part_name, tabIndex, part);
713 }
714 else
715 {
716 if(part)
717 {
718 delete part;
719 part = nullptr;
720 }
721 if(scroll)
722 {
723 delete scroll;
724 scroll = nullptr;
725 }
726 errorCount++;
727 }
728 }
729
730 if((unsigned int)errorCount == parts.size())
731 {
732 return false;
733 }
734
735 auto* lay = new QHBoxLayout();
736 lay->setMargin(0);
737 lay->setSpacing(0);
738 m_ui->mainContainer->setLayout(lay);
739 m_ui->mainContainer->layout()->addWidget(m_tabPanel);
740 connect(m_tabPanel, SIGNAL(currentChanged(int)), this, SLOT(onCurrentPartChanged(int)));
741
742 QSettings settings("YARP","yarpmotorgui");
743 bool speedVisible = settings.value("SpeedValuesVisible",false).toBool();
744 bool motorPosVisible = settings.value("MotorPositionVisible", false).toBool();
745 bool currentVisible = settings.value("CurrentsVisible", false).toBool();
746 bool dutyVisible = settings.value("DutyCyclesVisible", false).toBool();
747
748 onViewSpeeds(speedVisible);
749 onViewCurrents(currentVisible);
750 onViewMotorPositions(motorPosVisible);
751 onViewDutyCycles(dutyVisible);
752 return true;
753}
754
755
756void MainWindow::onCurrentPartChanged(int index)
757{
758 if(index < 0){
759 return;
760 }
761 QString partName = m_tabPanel->tabText(index);
762
763 QString auxName = partName;
764 auxName.replace(0,1,partName.at(0).toUpper());
765 m_currentPartMenu->setTitle(QString("%1 Commands").arg(auxName));
766 this->m_partName->setText(QString("%1 Commands").arg(auxName));
767
768 auto* scroll = (QScrollArea *)m_tabPanel->widget(index);
769 auto* part = (PartItem*)scroll->widget();
770 if(!part){
771 return;
772 }
773
774 part->resizeWidget(part->width());
775
776}
777
778void MainWindow::onCalibSinglePart()
779{
780 if (!m_tabPanel){
781 return;
782 }
783
784 auto* scroll = (QScrollArea *)m_tabPanel->currentWidget();
785 auto* part = (PartItem*)scroll->widget();
786 if(!part){
787 return;
788 }
789
790 if (QMessageBox::question(this, "Question", QString("Do you really want to recalibrate all joints of this part?")) == QMessageBox::Yes)
791 {
792 part->calibratePart(); // Error message is thrown inside
793 }
794}
795
796void MainWindow::onExecuteScript1()
797{
798 if (m_user_script1 == "")
799 {
800 QMessageBox::information(this, "Info", QString("user script1 not specified. use --script1 option"));
801 return;
802 }
803
804 if (QMessageBox::question(this, "Question", QString("Do you really want to execute user script1?")) == QMessageBox::Yes)
805 {
806 if (system(nullptr))
807 {
808 std::string script1_file = this->m_finder.findFileByName(m_user_script1);
809 if (script1_file != "")
810 {
811 int r = system(script1_file.c_str());
812 yDebug() << "yarpmotorgui_script1 returned value:" << r;
813 }
814 else
815 {
816 QMessageBox::information(this, "Info", QString("Unable to find script1 file"));
817 }
818 }
819 else
820 {
821 QMessageBox::information(this, "Info", QString("System is unable to run script1"));
822 }
823 }
824}
825
826void MainWindow::onExecuteScript2()
827{
828 if (m_user_script2 == "")
829 {
830 QMessageBox::information(this, "Info", QString("user script2 not specified. use --script2 option"));
831 return;
832 }
833
834 if (QMessageBox::question(this, "Question", QString("Do you really want to execute user script2?")) == QMessageBox::Yes)
835 {
836 if (system(nullptr))
837 {
838 std::string script2_file = this->m_finder.findFileByName(m_user_script2);
839 if (script2_file != "")
840 {
841 int r = system(script2_file.c_str());
842 yDebug() << "yarpmotorgui_script2 returned value:" << r;
843 }
844 else
845 {
846 QMessageBox::information(this, "Info", QString("Unable to find script2 file"));
847 }
848 }
849 else
850 {
851 QMessageBox::information(this, "Info", QString("System is unable to run script2"));
852 }
853 }
854}
855
856void MainWindow::onHomeSinglePart()
857{
858 if (QMessageBox::question(this, "Question", "Do you really want to home all joints of this part?") != QMessageBox::Yes){
859 return;
860 }
861
862 if (!m_tabPanel){
863 return;
864 }
865
866 auto* scroll = (QScrollArea *)m_tabPanel->currentWidget();
867 auto* part = (PartItem*)scroll->widget();
868 if (!part){
869 return;
870 }
871
872 part->homePart();
873}
874
875void MainWindow::onHomeAllParts()
876{
877 if (QMessageBox::question(this, "Question", "Do you really want to home all parts?") != QMessageBox::Yes){
878 return;
879 }
880
881 if (!m_tabPanel){
882 return;
883 }
884
885 for (int i = 0; i<m_tabPanel->count(); i++)
886 {
887 auto* scroll = (QScrollArea *)m_tabPanel->widget(i);
888 auto* part = (PartItem*)scroll->widget();
889 if (!part)
890 {
891 continue;
892 }
893
894 part->homePart();
895 }
896}
897
898void MainWindow::onHomeAllPartsToCustomPosition(const yarp::os::Bottle& positionElement)
899{
900 if (QMessageBox::question(this, "Question", "Do you really want to home all parts?") != QMessageBox::Yes){
901 return;
902 }
903
904 if (!m_tabPanel){
905 return;
906 }
907
908 for (int i = 0; i<m_tabPanel->count(); i++)
909 {
910 auto* scroll = (QScrollArea *)m_tabPanel->widget(i);
911 auto* part = (PartItem*)scroll->widget();
912 QString currName = QString("/%1/%2").arg(QString(m_finder.find("robot").asString().c_str())).arg(part->getPartName());
913 bool partPresent = positionElement.check(currName.toStdString() + "_Position") && positionElement.check(currName.toStdString() + "_Velocity");
914 if(!part || ! partPresent)
915 {
916 continue;
917 }
918 part->homeToCustomPosition(positionElement);
919 }
920}
921
922void MainWindow::onHomeSinglePartToCustomPosition(const yarp::os::Bottle& positionElement)
923{
924 if (QMessageBox::question(this, "Question", "Do you really want to home all joints of this part?") != QMessageBox::Yes){
925 return;
926 }
927
928 if (!m_tabPanel){
929 return;
930 }
931
932 auto* scroll = (QScrollArea *)m_tabPanel->currentWidget();
933 auto* part = (PartItem*)scroll->widget();
934 if(!part){
935 return;
936 }
937
938 part->homeToCustomPosition(positionElement);
939}
940
941void MainWindow::onIdleSinglePart()
942{
943 if (!m_tabPanel){
944 return;
945 }
946
947 auto* scroll = (QScrollArea *)m_tabPanel->currentWidget();
948 auto* part = (PartItem*)scroll->widget();
949 if(!part){
950 return;
951 }
952
953 part->idlePart();
954}
955
956void MainWindow::onCycleTimeAllSeq()
957{
958 if (!m_tabPanel){
959 return;
960 }
961
963
964 for (int i = 0; i<m_tabPanel->count(); i++){
965 auto* scroll = (QScrollArea *)m_tabPanel->widget(i);
966 auto* part = (PartItem*)scroll->widget();
967 if(!part){
968 continue;
969 }
970
971 bool done = part->checkAndCycleTimeAllSeq();
972 if(!done){
973 notSelectedParts.append(QString("- %1\n").arg(part->getPartName()));
974 }
975 }
976 if(!notSelectedParts.isEmpty()){
977 QMessageBox::critical(this,"Error", QString("Load a valid sequence before performing this action for these parts:\n%1").arg(notSelectedParts));
978 }
979}
980
981void MainWindow::onCycleAllSeq()
982{
983 if (!m_tabPanel){
984 return;
985 }
986
988
989 for (int i = 0; i<m_tabPanel->count(); i++){
990 auto* scroll = (QScrollArea *)m_tabPanel->widget(i);
991 auto* part = (PartItem*)scroll->widget();
992 if(!part){
993 continue;
994 }
995
996 bool done = part->checkAndCycleAllSeq();
997 if(!done){
998 notSelectedParts.append(QString("- %1\n").arg(part->getPartName()));
999 }
1000 }
1001 if(!notSelectedParts.isEmpty()){
1002 QMessageBox::critical(this,"Error", QString("Load a valid sequence before performing this action for these parts:\n%1").arg(notSelectedParts));
1003 }
1004}
1005
1006void MainWindow::onRunAllSeq()
1007{
1008 if (!m_tabPanel){
1009 return;
1010 }
1011
1013
1014 for (int i = 0; i<m_tabPanel->count(); i++){
1015 auto* scroll = (QScrollArea *)m_tabPanel->widget(i);
1016 auto* part = (PartItem*)scroll->widget();
1017 if(!part){
1018 continue;
1019 }
1020
1021 bool done = part->checkAndRunAllSeq();
1022 if(!done){
1023 notSelectedParts.append(QString("- %1\n").arg(part->getPartName()));
1024 }
1025 }
1026 if(!notSelectedParts.isEmpty()){
1027 QMessageBox::critical(this,"Error", QString("Load a valid sequence before performing this action for these parts:\n%1").arg(notSelectedParts));
1028 }
1029}
1030
1031
1032void MainWindow::onRunTimeAllSeq()
1033{
1034 if (!m_tabPanel){
1035 return;
1036 }
1037
1039
1040 for (int i = 0; i<m_tabPanel->count(); i++){
1041 auto* scroll = (QScrollArea *)m_tabPanel->widget(i);
1042 auto* part = (PartItem*)scroll->widget();
1043 if(!part){
1044 continue;
1045 }
1046
1047 bool done = part->checkAndRunTimeAllSeq();
1048 if(!done){
1049 notSelectedParts.append(QString("- %1\n").arg(part->getPartName()));
1050 }
1051 }
1052 if(!notSelectedParts.isEmpty()){
1053 QMessageBox::critical(this,"Error", QString("Load a valid sequence before performing this action for these parts:\n%1").arg(notSelectedParts));
1054 }
1055}
1056
1057void MainWindow::onLoadAllSeq()
1058{
1059 if (!m_tabPanel){
1060 return;
1061 }
1062
1063
1064 for (int i = 0; i<m_tabPanel->count(); i++){
1065 auto* scroll = (QScrollArea *)m_tabPanel->widget(i);
1066 auto* part = (PartItem*)scroll->widget();
1067 if(!part){
1068 continue;
1069 }
1070
1071 part->loadSequence();
1072
1073 }
1074}
1075
1076void MainWindow::onSaveAllSeq()
1077{
1078 if (!m_tabPanel){
1079 return;
1080 }
1081
1082 QString fileName = QFileDialog::getSaveFileName(this, QString("Save Sequence for all parts as:"), QDir::homePath());
1083
1084 for (int i = 0; i<m_tabPanel->count(); i++)
1085 {
1086 auto* scroll = (QScrollArea *)m_tabPanel->widget(i);
1087 auto* part = (PartItem*)scroll->widget();
1088 if(!part)
1089 {
1090 continue;
1091 }
1092 part->saveSequence(fileName);
1093 part->closeSequenceWindow();
1094 }
1095}
1096
1097void MainWindow::onStopAllSeq()
1098{
1099 if (!m_tabPanel){
1100 return;
1101 }
1102
1103
1104 for (int i = 0; i<m_tabPanel->count(); i++){
1105 auto* scroll = (QScrollArea *)m_tabPanel->widget(i);
1106 auto* part = (PartItem*)scroll->widget();
1107 if(!part){
1108 continue;
1109 }
1110
1111 part->stopSequence();
1112
1113 }
1114
1115 }
1116
1117void MainWindow::onGoAll()
1118{
1119 if (!m_tabPanel){
1120 return;
1121 }
1122
1124
1125 for (int i = 0; i<m_tabPanel->count(); i++){
1126 auto* scroll = (QScrollArea *)m_tabPanel->widget(i);
1127 auto* part = (PartItem*)scroll->widget();
1128 if(!part){
1129 continue;
1130 }
1131
1132 bool done = part->checkAndGo();
1133 if(!done){
1134 notSelectedParts.append(QString("- %1\n").arg(part->getPartName()));
1135 }
1136 }
1137
1138 if(!notSelectedParts.isEmpty()){
1139 QMessageBox::critical(this,"Error", QString("Select a valid entry in the table before performing a movement for these parts:\n%1").arg(notSelectedParts));
1140 }
1141
1142}
1143
1144void MainWindow::onIdleAllParts()
1145{
1146 if (QMessageBox::question(this, "Question", "Do you really want to idle all parts?") != QMessageBox::Yes){
1147 return;
1148 }
1149
1150 if (!m_tabPanel){
1151 return;
1152 }
1153
1154 for (int i = 0; i<m_tabPanel->count(); i++)
1155 {
1156 auto* scroll = (QScrollArea *)m_tabPanel->widget(i);
1157 auto* part = (PartItem*)scroll->widget();
1158 if (!part){
1159 continue;
1160 }
1161
1162 part->idlePart();
1163 }
1164}
1165
1166void MainWindow::onRunAllParts()
1167{
1168 if (!m_tabPanel){
1169 return;
1170 }
1171
1172 for (int i = 0; i<m_tabPanel->count(); i++){
1173 auto* scroll = (QScrollArea *)m_tabPanel->widget(i);
1174 auto* part = (PartItem*)scroll->widget();
1175 if(!part){
1176 continue;
1177 }
1178
1179 part->runPart();
1180 }
1181}
1182
1183void MainWindow::onRunSinglePart()
1184{
1185 if (!m_tabPanel){
1186 return;
1187 }
1188
1189 auto* scroll = (QScrollArea *)m_tabPanel->currentWidget();
1190 auto* part = (PartItem*)scroll->widget();
1191 if(!part){
1192 return;
1193 }
1194
1195 part->runPart();
1196}
1197
1198void MainWindow::onOpenSequenceTab()
1199{
1200 if (!m_tabPanel){
1201 return;
1202 }
1203
1204 auto* scroll = (QScrollArea *)m_tabPanel->currentWidget();
1205 auto* part = (PartItem*)scroll->widget();
1206 if(!part){
1207 return;
1208 }
1209 part->openSequenceWindow();
1210}
1211
1212
1213
1214void MainWindow::onUpdate()
1215{
1216 if (!m_tabPanel){
1217 return;
1218 }
1219 m_mutex.lock();
1220
1221 auto* scroll = (QScrollArea *)m_tabPanel->currentWidget();
1222 if(!scroll){
1223 m_mutex.unlock();
1224 return;
1225 }
1226 auto* currentPart = (PartItem*)scroll->widget();
1227 if(!currentPart){
1228 m_mutex.unlock();
1229 return;
1230 }
1231 for (int i = 0; i<m_tabPanel->count(); i++)
1232 {
1233 auto* tabScroll = (QScrollArea *)m_tabPanel->widget(i);
1234 auto* item = (PartItem*)tabScroll->widget();
1235 item->updateControlMode();
1236 m_modesTreeManager->updateRobotPart(i);
1237 if(item == currentPart)
1238 {
1239 if (item->updatePart() == false)
1240 {
1241 //this part is disconnected!
1242 }
1243 }
1244 }
1245 m_mutex.unlock();
1246}
#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_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