发布时间: 2026-02-04

CS_ROS2软件包使用案例及说明


以下为使用c++编写的基于ros2的源码,该源码实现了机器人监听数字信号,沿固定线路进行搬运的功能

#include <chrono>
#include <memory>
#include <string>
#include <vector>
#include <unordered_map>
#include <optional>
#include <thread>

#include "control_msgs/action/follow_joint_trajectory.hpp"
#include "rclcpp/rclcpp.hpp"
#include "rclcpp_action/rclcpp_action.hpp"
#include "sensor_msgs/msg/joint_state.hpp"
#include "trajectory_msgs/msg/joint_trajectory_point.hpp"
#include "eli_common_interface/srv/set_io.hpp"
#include "eli_common_interface/msg/io_state.hpp"

namespace {
const std::vector<std::string> JOINTS = {
    "shoulder_pan_joint", "shoulder_lift_joint", "elbow_joint", 
    "wrist_1_joint", "wrist_2_joint", "wrist_3_joint",
};
}  // namespace

class EliteTrajectoryNode : public rclcpp::Node {
public:
    using FollowJT = control_msgs::action::FollowJointTrajectory;
    using GoalHandle = rclcpp_action::ClientGoalHandle<FollowJT>;
    using SetIO = eli_common_interface::srv::SetIO;
    using IOState = eli_common_interface::msg::IOState;

    EliteTrajectoryNode() : rclcpp::Node("elite_trajectory_node") {
        // 参数声明
        controller_ = this->declare_parameter<std::string>(
            "controller", 
            "scaled_joint_trajectory_controller"
        );

        // 创建动作客户端
        client_ = rclcpp_action::create_client<FollowJT>(
            this, 
            "/" + controller_ + "/follow_joint_trajectory"
        );

        // 创建IO服务客户端
        io_service_client_ = this->create_client<SetIO>(
            "/io_and_status_controller/set_io"
        );

        // 订阅关节状态
        joint_sub_ = this->create_subscription<sensor_msgs::msg::JointState>(
            "/joint_states", 
            10,
            std::bind(&EliteTrajectoryNode::jointCallback, this, std::placeholders::_1)
        );

        // 订阅IO状态
        io_state_sub_ = this->create_subscription<IOState>(
            "/io_and_status_controller/io_states", 
            10,
            std::bind(&EliteTrajectoryNode::ioStateCallback, this, std::placeholders::_1)
        );

        RCLCPP_INFO(get_logger(), "Elite Trajectory Node initialized");
    }

    bool execute() {
        RCLCPP_INFO(get_logger(), "Starting execution sequence");
        
        // 1. 等待关节状态
        if (!waitForJointStates(5.0)) {
            RCLCPP_ERROR(get_logger(), "Failed to get joint states");
            return false;
        }

        // 2. 等待IO服务
        if (!io_service_client_->wait_for_service(std::chrono::seconds(5))) {
            RCLCPP_ERROR(get_logger(), "IO service not available");
            return false;
        }

        // 3. 执行Home轨迹
        RCLCPP_INFO(get_logger(), "Executing home trajectory");
        std::vector<double> home_position = {0, -1.57, 0, -1.57, 1.57, 0};
        if (!moveToPosition(home_position, 6.0)) {
            RCLCPP_ERROR(get_logger(), "Failed to move to home position");
            return false;
        }

        // 4. 设置IO输出0为true
        RCLCPP_INFO(get_logger(), "Setting digital output 0 to true");
        if (!setDigitalOutput(0, true)) {
            RCLCPP_ERROR(get_logger(), "Failed to set digital output 0");
            return false;
        }

        // 5. 等待IO输出3触发
        RCLCPP_INFO(get_logger(), "Waiting for digital output 3 to be true...");
        while (rclcpp::ok()) {
            rclcpp::spin_some(shared_from_this());
            
            if (checkDigitalOutput(3)) {
                RCLCPP_INFO(get_logger(), "Digital output 3 is true!");
                
                // 执行第一段轨迹
                std::vector<double> position1 = {0.8, -1.5, -1.9, -1.2, 1.5, 0.1};
                RCLCPP_INFO(get_logger(), "Moving to position 1");
                if (!moveToPosition(position1, 4.0)) {
                    RCLCPP_ERROR(get_logger(), "Failed to execute position 1");
                    return false;
                }

                // 设置IO输出1为true
                RCLCPP_INFO(get_logger(), "Setting digital output 1 to true");
                if (!setDigitalOutput(1, true)) {
                    RCLCPP_ERROR(get_logger(), "Failed to set digital output 1");
                    return false;
                }
                
                break;
            }
            
            std::this_thread::sleep_for(std::chrono::milliseconds(100));
        }

        // 6. 等待IO输出4或5触发
        RCLCPP_INFO(get_logger(), "Waiting for digital output 4 or 5...");
        while (rclcpp::ok()) {
            rclcpp::spin_some(shared_from_this());
            
            if (checkDigitalOutput(4)) {
                RCLCPP_INFO(get_logger(), "Digital output 4 is true!");
                
                std::vector<double> position2 = {0.8, -1.7, -2.1, -0.8, 1.5, 0.1};
                if (!moveToPosition(position2, 4.0)) {
                    RCLCPP_ERROR(get_logger(), "Failed to execute joint trajectory 2");
                    return false;
                }

                RCLCPP_INFO(get_logger(), "Executing joint trajectory to get goods succ");
                std::vector<double> position3 = {0.8, -1.5, -1.9, -1.2, 1.5, 0.1};
                std::vector<double> position4 = {0.5, -1.5, -1.9, -1.2, 1.5, 0.1};
                if (!moveToPosition(position3, 4.0)) {
                    RCLCPP_ERROR(get_logger(), "Failed to execute joint trajectory 3");
                    return false;
                }
                if (!moveToPosition(position4, 4.0)) {
                    RCLCPP_ERROR(get_logger(), "Failed to execute joint trajectory 4");
                    return false;
                }
                
                std::vector<double> position5 = {0.5, -1.7, -2.1, -0.8, 1.5, 0.1};
                if (!moveToPosition(position5, 4.0)) {
                    RCLCPP_ERROR(get_logger(), "Failed to execute Cartesian trajectory 5");
                    return false;
                }

                RCLCPP_INFO(get_logger(), "Executing return trajectory to put goods succ");
                std::vector<double> position6 = {0.5, -1.5, -1.9, -1.2, 1.5, 0.1};
                std::vector<double> position7 = {0.8, -1.5, -1.9, -1.2, 1.5, 0.1};
                if (!moveToPosition(position6, 4.0)) {
                    RCLCPP_ERROR(get_logger(), "Failed to execute joint trajectory 6");
                    return false;
                }
                if (!moveToPosition(position7, 4.0)) {
                    RCLCPP_ERROR(get_logger(), "Failed to execute joint trajectory 7");
                    return false;
                }

                // 设置IO输出4为false (
                RCLCPP_INFO(get_logger(), "Setting digital output 4 to false");
                if (!setDigitalOutput(4, false)) {
                    RCLCPP_ERROR(get_logger(), "Failed to set digital output 4");
                }
                
            } else if (checkDigitalOutput(5)) {
                RCLCPP_INFO(get_logger(), "Digital output 5 is true!");
                
                // 清除所有IO输出
                RCLCPP_INFO(get_logger(), "Clearing all digital outputs");
                for (int i = 0; i <= 5; i++) {
                    setDigitalOutput(i, false);
                }
                
                RCLCPP_INFO(get_logger(), "All trajectories completed successfully!");
                return true;
            }
            
            std::this_thread::sleep_for(std::chrono::seconds(1));
        }

        return false;
    }

private:
    // ==================== 关节状态处理 ====================
    void jointCallback(const sensor_msgs::msg::JointState::SharedPtr msg) {
        std::vector<double> positions;
        positions.reserve(JOINTS.size());
        std::unordered_map<std::string, double> joint_map;
        
        for (size_t i = 0; i < msg->name.size(); ++i) {
            if (i < msg->position.size()) {
                joint_map[msg->name[i]] = msg->position[i];
            }
        }
        
        for (const auto& joint_name : JOINTS) {
            auto it = joint_map.find(joint_name);
            if (it == joint_map.end()) {
                return;  // 等待完整的数据集
            }
            positions.push_back(it->second);
        }
        
        current_pos_ = positions;
    }

    bool waitForJointStates(double timeout_sec) {
        RCLCPP_INFO(get_logger(), "Waiting for joint states...");
        
        auto start_time = this->now();
        rclcpp::Rate rate(50);
        
        while (rclcpp::ok()) {
            rclcpp::spin_some(shared_from_this());
            
            if (current_pos_.has_value()) {
                RCLCPP_INFO(get_logger(), "Received joint states");
                return true;
            }
            
            if ((this->now() - start_time).seconds() > timeout_sec) {
                RCLCPP_ERROR(get_logger(), "Timeout waiting for joint states");
                return false;
            }
            
            rate.sleep();
        }
        
        return false;
    }

    // ==================== IO状态处理 ====================
    void ioStateCallback(const IOState::SharedPtr msg) {
        // 保存最新的IO状态
        last_io_state_ = *msg;
    }

    bool checkDigitalOutput(int pin) {
        if (!last_io_state_.has_value()) {
            return false;
        }
        
        const auto& io_state = last_io_state_.value();
        
        // 检查引脚是否在有效范围内
        if (pin < 0 || pin >= static_cast<int>(io_state.standard_out.size())) {
            RCLCPP_WARN(get_logger(), "Pin %d is out of range (max: %zu)", 
                       pin, io_state.standard_out.size());
            return false;
        }
        
        return io_state.standard_out[pin];
    }

    bool setDigitalOutput(int pin, bool state) {
        auto request = std::make_shared<SetIO::Request>();
        request->fun = SetIO::Request::FUN_SET_DIGITAL_OUT;
        request->pin = pin;
        request->state = state ? SetIO::Request::STATE_ON : SetIO::Request::STATE_OFF;
        
        auto future = io_service_client_->async_send_request(request);
        
        // 等待响应
        if (rclcpp::spin_until_future_complete(shared_from_this(), future) != 
            rclcpp::FutureReturnCode::SUCCESS) {
            RCLCPP_ERROR(get_logger(), "Failed to call set_io service");
            return false;
        }
        
        auto response = future.get();
        
        if (response->success) {
            RCLCPP_INFO(get_logger(), "Successfully set digital output pin %d to %s", 
                       pin, state ? "true" : "false");
            return true;
        } else {
            RCLCPP_ERROR(get_logger(), "Failed to set digital output pin %d", pin);
            return false;
        }
    }

    // ==================== 轨迹执行 ====================
    bool moveToPosition(const std::vector<double>& target, double duration) {
        if (target.size() != JOINTS.size()) {
            RCLCPP_ERROR(get_logger(), "Target size mismatch");
            return false;
        }

        if (!client_->wait_for_action_server(std::chrono::seconds(5))) {
            RCLCPP_ERROR(get_logger(), "Action server not available");
            return false;
        }

        auto goal_msg = FollowJT::Goal();
        goal_msg.trajectory.joint_names = JOINTS;

        // 添加起始点(当前位置)
        if (current_pos_.has_value()) {
            trajectory_msgs::msg::JointTrajectoryPoint start;
            start.positions = current_pos_.value();
            start.time_from_start = rclcpp::Duration(0, 0);
            goal_msg.trajectory.points.push_back(start);
        }

        // 添加目标点
        trajectory_msgs::msg::JointTrajectoryPoint target_pt;
        target_pt.positions = target;
        target_pt.time_from_start = rclcpp::Duration::from_seconds(duration);
        goal_msg.trajectory.points.push_back(target_pt);

        // 发送目标
        auto goal_future = client_->async_send_goal(goal_msg);
        if (rclcpp::spin_until_future_complete(shared_from_this(), goal_future) != 
            rclcpp::FutureReturnCode::SUCCESS) {
            RCLCPP_ERROR(get_logger(), "Failed to send goal");
            return false;
        }
        
        auto goal_handle = goal_future.get();
        if (!goal_handle) {
            RCLCPP_ERROR(get_logger(), "Goal rejected");
            return false;
        }

        // 等待结果
        auto result_future = client_->async_get_result(goal_handle);
        if (rclcpp::spin_until_future_complete(shared_from_this(), result_future) != 
            rclcpp::FutureReturnCode::SUCCESS) {
            RCLCPP_ERROR(get_logger(), "Failed to get result");
            return false;
        }
        
        auto result = result_future.get();
        bool success = result.result->error_code == 0;
        
        if (success) {
            current_pos_ = target;
            RCLCPP_INFO(get_logger(), "Move to position successful");
        } else {
            RCLCPP_ERROR(get_logger(), "Move failed with error code: %d", result.result->error_code);
        }
        
        return success;
    }

    // ==================== 成员变量 ====================
    std::string controller_;
    
    rclcpp_action::Client<FollowJT>::SharedPtr client_;
    rclcpp::Client<SetIO>::SharedPtr io_service_client_;
    rclcpp::Subscription<sensor_msgs::msg::JointState>::SharedPtr joint_sub_;
    rclcpp::Subscription<IOState>::SharedPtr io_state_sub_;
    
    std::optional<std::vector<double>> current_pos_;
    std::optional<IOState> last_io_state_;
};

int main(int argc, char* argv[]) {
    rclcpp::init(argc, argv);
    auto node = std::make_shared<EliteTrajectoryNode>();
    bool ok = node->execute();
    rclcpp::shutdown();
    return ok ? 0 : 1;
}

将该代码放入./Elite_Robots_CS_ROS2_Driver/eli_cs_robot_driver/example/cpp后,需要修改编译文件。进入 ./Elite_Robots_CS_ROS2_Driver/eli_cs_robot_driver文件夹

打开CMakeList.txt,添加以下代码,这里file_name请修改成真实的文件名

add_executable(
  file_name
  example/cpp/file_name.cpp
)
ament_target_dependencies(
  file_name
  ${THIS_PACKAGE_DEPENDENCIES}
)
install(
  TARGETS file_name
  DESTINATION lib/${PROJECT_NAME}
)

回到ROS2软件包存放的根目录./

重新编译ROS2软件包

colcon build

提交反馈