我试图使用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中的插槽将类似于senddatatoRobot() --这个函数基本上是通过TCP将数据发送给我的机器人,根据机器人从期望的端点的方向将它转换成一个特定的角度。例如,我知道我的机器人将进行360度转弯,如果我发送一个PWM值4096和0到左和右车轮5秒。例如,要做一个45度的转弯,我会发送指定的秒数的数据。
发布于 2016-04-21 13:10:06
你可以试试这样的方法:
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将数据发送给我的机器人,根据机器人从期望的端点定位到一定的角度。例如,我知道我的机器人将进行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中所述。这样,您就可以通过中断来在当前命令完成之前发出新命令。
发布于 2016-04-21 13:11:13
你还没有说明你如何指挥你的机器人。有两种方法:
这两种方法都很容易使用状态机实现。让我们看看如何实现第一种方法。
控制器可以封装这些行为。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"https://stackoverflow.com/questions/36769933
复制相似问题