You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将C++类成员函数作为参数传递,实现机器人自主循环调度?

机器人自主循环功能实现方案

需求描述

制作一款趣味机器人,需要添加**自主循环(Autonomous loop)**功能,让机器人遵循预设命令自主运行。核心需求是实现一个类似如下的函数:

DoFunctionForMe(start_time, end_time, function, start_arguments, end_arguments);

该函数需要在start_time时刻使用start_arguments执行传入的function,并在end_time时刻使用end_arguments执行该函数。

例如期望实现的逻辑:在1到8秒期间驱动机器人,同时在7到9秒期间移动机械臂,代码示例如下:

void Robot::AutoMainLoop(){
    DoFunctionForMe(1,8,Drive,{12,12},{0,0});
    DoFunctionForMe(7,9,Move,{1,0},{0,0});
}

当前代码结构

class Drivetrain{
    public:
        Drivetrain();

        void Drive(int forward, int left){
            drive(forward, left); // 实际驱动逻辑更复杂
        }
};

class Mechanism{
    public:
        Mechanism();

        void Move(int up, int down){
            move(up, down); // 实际机械臂移动逻辑更复杂
        }
};

class Robot{
    public:
        void DrivenMainLoop(); // 手动控制循环

        void AutoMainLoop(); // 自主运行循环

    private:
        Drivetrain m_drivetrain{}; 

        Mechanism m_mechanism{};
};

void Robot::DrivenMainLoop(){
    m_drivetrain.Drive(2,12);
    m_mechanism.Move(1,0);
}

void Robot::AutoMainLoop(){
    // 需要实现自主逻辑
}

遇到的问题

尝试使用函数指针实现时出现错误,错误信息翻译为:

指向绑定函数的指针只能用于调用函数

可行实现方案

核心思路

由于涉及不同类的成员函数,直接用函数指针会因为绑定对象的问题报错。我们可以用std::function和std::tuple封装任务,同时维护一个任务队列,在AutoMainLoop的循环中根据当前时间处理每个任务的触发和结束动作。

具体实现步骤

  1. 定义任务结构体:存储任务的时间参数、要执行的函数以及参数
  2. 封装DoFunctionForMe函数:将任务添加到队列中
  3. 在AutoMainLoop中循环处理任务:根据当前时间判断是否触发任务的开始或结束动作

代码实现

首先添加必要的头文件:

#include <vector>
#include <functional>
#include <tuple>
#include <chrono>
#include <thread>

然后修改Robot类,添加任务队列和相关函数:

class Robot{
    public:
        void DrivenMainLoop();
        void AutoMainLoop();

        // 封装DoFunctionForMe,支持不同成员函数和参数
        template<typename Func, typename... Args>
        void DoFunctionForMe(double start_time, double end_time, Func&& func, std::tuple<Args...> start_args, std::tuple<Args...> end_args){
            m_tasks.emplace_back(start_time, end_time, 
                [func, start_args](){ std::apply(func, start_args); },
                [func, end_args](){ std::apply(func, end_args); });
        }

    private:
        Drivetrain m_drivetrain{}; 
        Mechanism m_mechanism{};

        // 任务结构体
        struct AutoTask{
            double start_time;
            double end_time;
            std::function<void()> start_action;
            std::function<void()> end_action;
            bool started;
            bool finished;

            AutoTask(double st, double et, std::function<void()> sa, std::function<void()> ea)
                : start_time(st), end_time(et), start_action(std::move(sa)), end_action(std::move(ea)), started(false), finished(false) {}
        };

        std::vector<AutoTask> m_tasks;

        // 获取自主循环运行的当前时间(单位:秒)
        double GetCurrentAutoTime(){
            static auto start = std::chrono::steady_clock::now();
            auto now = std::chrono::steady_clock::now();
            return std::chrono::duration<double>(now - start).count();
        }
};

实现AutoMainLoop逻辑:

void Robot::AutoMainLoop(){
    // 初始化任务队列(每次进入自主循环时清空并重新添加任务)
    m_tasks.clear();
    // 绑定成员函数和对象,传入参数
    DoFunctionForMe(1.0, 8.0, 
        std::bind(&Drivetrain::Drive, &m_drivetrain, std::placeholders::_1, std::placeholders::_2),
        std::make_tuple(12, 12),
        std::make_tuple(0, 0));
    
    DoFunctionForMe(7.0, 9.0,
        std::bind(&Mechanism::Move, &m_mechanism, std::placeholders::_1, std::placeholders::_2),
        std::make_tuple(1, 0),
        std::make_tuple(0, 0));

    // 自主循环主逻辑
    while(true){ // 根据实际机器人的循环条件调整,比如直到自主模式结束
        double current_time = GetCurrentAutoTime();

        for(auto& task : m_tasks){
            if(!task.started && current_time >= task.start_time){
                task.start_action();
                task.started = true;
            }
            if(task.started && !task.finished && current_time >= task.end_time){
                task.end_action();
                task.finished = true;
            }
        }

        // 检查是否所有任务完成,退出循环
        bool all_finished = true;
        for(const auto& task : m_tasks){
            if(!task.finished){
                all_finished = false;
                break;
            }
        }
        if(all_finished){
            break;
        }

        // 添加适当的延迟,避免占用过多CPU
        std::this_thread::sleep_for(std::chrono::milliseconds(10));
    }
}

方案说明

  • 使用std::bind将成员函数和对象绑定,生成可调用的函数对象,解决了成员函数需要对象实例的问题
  • 用std::tuple存储参数,通过std::apply将参数传递给函数
  • 任务队列跟踪每个任务的状态(是否已开始、是否已结束),确保每个动作只执行一次
  • GetCurrentAutoTime函数需要根据机器人的实际计时系统调整,比如从自主模式启动时开始计时

内容的提问来源于stack exchange,提问作者ThatAlo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 17:08:08