我尝试使用QTimer
函数运行一个函数约5秒钟。在研究了文档和测试之后,我似乎找不到在Qt中执行此操作的函数。
我尝试过以下方法:
QTimer *timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(myFunction());
timer->start(5000);
此方法每5秒后运行一次该功能。这不是我想要实现的目标。我还尝试使用以下代码使用singleShot()
属性:
QTimer::singleShot(5000,this,SLOT(myFunction()));
此功能只会激活我的功能一次。是否有QTimer
的任何属性可以在给定时间内运行我的函数。类似的东西:
run function and timeout function after 5 seconds.
编辑:更多信息:
这是我大学的机器人比赛。我驾驶的是通过TCP驱动机器人的车轮。我知道两个车轮需要多少秒才能让机器人转动一定的角度。 myFunction
中的SLOT将类似于senddatatoRobot()
该函数基本上通过TCP将数据发送到我的机器人,根据机器人从所需端点的方向将其转动一定角度。例如,我知道如果我将左侧和右侧车轮的PWM值4096和0发送5秒钟,我的机器人将转动360度。因此,为了进行45度转弯,我会发送指定秒数的数据。
答案 0 :(得分:1)
您可以尝试这样的事情:
QElapsedTimer t;
t.start();
while (t.elapsed() < 5000) { ...do stuff... } // this will block the thread
您也可以这样做:
startDoingStuff(); // must not block the thread
QTimer::singleShot(5000, this, "stopDoingStuff");
但是从您的评论中可以看出,您需要分享该功能的实际功能,并且绝对能够更多地了解事件驱动编程,然后您将能够提出更好的设计。
该功能基本上通过TCP将数据发送到我的机器人,将其变为a 基于机器人方向的特定角度 端点。例如,我知道我的机器人将转向360度 我将PWM值4096和0发送到左右轮5 秒。所以以45度转弯为例,我会输入发送 数据指定的秒数。
对我而言,更有效的解决方案似乎只是发送值更改而不是重复发送相同的数据。
因此,在机器人的微控制器代码中,您将连续缓存并使用这些值,并且从控制器应用程序中,您将只“设置”远程值:
public slots:
void reset() { send(0, 0); }
...
// begin turning
send(4096, 0);
QTimer::singleShot(5000, this, "reset"); // end turning in 5 secs
更好的解决方案是,不是发送PWM值,而是发送机器人特定的命令,让机器人的微控制器保持时间,因为它最有可能比QTimer
更好。您甚至可以获得更具体的信息,例如在T秒内转动X度的命令。你肯定在机器人微控制器代码方面有很大的改进空间。
如果您必须使用您当前正在尝试的方法,只要您放置工作人员,就可以使用QElapsedTimer
方法实现具有函数void send(v1, v2, time)
的工作程序在另一个线程中,所以你不要阻止主线程,这将导致操作系统将你的应用程序报告为“没有响应”。但是这样命令不能被中断,并且在当前命令完成之前不能发出新命令。您可以通过实施非阻塞工作程序来改进这一点,如this example中所述。这样,您就可以通过中断来完成当前命令之前发出新命令。
答案 1 :(得分:1)
您尚未指定命令机器人的方式。有两种方法:
在间隔开始时发送ON命令,然后在间隔结束时发送OFF命令;
在间隔期间反复发送ON命令,电机关闭&#34;很快&#34;收到最后一个命令后,没有明确的OFF命令。
使用状态机很容易实现这两种方法。让我们看看如何实施第一种方法。
控制器可以封装行为。 isIdle
和isActive
信号将连接到向机器人发送命令的操作。
class Controller : public QObject {
Q_OBJECT
QStateMachine m_machine{this};
QState
m_idle {&m_machine},
m_active {&m_machine};
Transition
m_go{&m_idle, &m_active};
Delay
m_activeTime{&m_active, &m_idle, 0};
public:
Controller(QObject * parent = 0) : QObject(parent) {
connect(&m_idle, &QState::entered, this, &Controller::isIdle);
connect(&m_active, &QState::entered, this, &Controller::isActive);
m_machine.setInitialState(&m_idle);
m_machine.start();
}
Q_SLOT void moveFor(int ms) {
m_activeTime.setDuration(ms);
m_go();
}
Q_SIGNAL void isIdle();
Q_SIGNAL void isActive();
};
Transition
和Delay
类实现与状态转换相关联的行为:
// https://github.com/KubaO/stackoverflown/tree/master/questions/robot-state-timer-36769933
#include <QtWidgets>
struct Transition : public QObject {
Q_OBJECT
public:
Transition(QState * source, QState * destination) : QObject(source->machine()) {
source->addTransition(this, &Transition::trigger, destination);
}
Q_SIGNAL void trigger();
void operator()() { trigger(); }
};
class Delay : public Transition {
Q_OBJECT
int m_duration;
QBasicTimer m_timer;
void timerEvent(QTimerEvent * ev) {
if (m_timer.timerId() != ev->timerId()) return;
m_timer.stop();
trigger();
}
public:
Delay(QState * src, QState * dst, int ms) : Transition(src, dst), m_duration(ms) {
connect(src, &QState::entered, this, [this]{ m_timer.start(m_duration, this);});
}
Q_SLOT void setDuration(int duration) { m_duration = duration; }
};
测试工具可以使示例完整。
int main(int argc, char ** argv) {
QApplication app{argc, argv};
Controller ctl;
QWidget w;
QFormLayout layout{&w};
QPushButton start{"Go"};
QLineEdit duration{"5000"};
QPlainTextEdit log;
log.setReadOnly(true);
layout.addRow("Duration", &duration);
layout.addRow(&start);
layout.addRow(&log);
QObject::connect(&ctl, &Controller::isIdle, &log, [&]{ log.appendPlainText("Idle"); });
QObject::connect(&ctl, &Controller::isActive, &log, [&]{ log.appendPlainText("Active"); });
QObject::connect(&start, &QPushButton::clicked, &ctl, [&]{
ctl.moveFor(duration.text().toInt());
});
w.show();
return app.exec();
}
#include "main.moc"