在Qt中运行计时器5秒钟

时间:2016-04-21 12:39:42

标签: c++ qt

我尝试使用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度转弯,我会发送指定秒数的数据。

2 个答案:

答案 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)

您尚未指定命令机器人的方式。有两种方法:

  1. 在间隔开始时发送ON命令,然后在间隔结束时发送OFF命令;

  2. 在间隔期间反复发送ON命令,电机关闭&#34;很快&#34;收到最后一个命令后,没有明确的OFF命令。

  3. 使用状态机很容易实现这两种方法。让我们看看如何实施第一种方法。

    控制器可以封装行为。 isIdleisActive信号将连接到向机器人发送命令的操作。

    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();
    };
    

    TransitionDelay类实现与状态转换相关联的行为:

    // 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"