You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

ROS从YAML读取含元组的数组报错,求解决方案

这个问题我之前在ROS项目里踩过坑——核心原因是**ROS的参数系统默认不支持直接解析std::vector<std::pair<double, double>>**这种类型,因为ROS的param接口没有内置对std::pair的序列化/反序列化逻辑,所以才会抛出no matching function的编译错误。下面给你几个可行的解决思路:

解决办法1:改用std::vector<std::vector<double>>接收(最简单,改动最小)

ROS原生支持解析二维数组类型的参数,所以我们可以先把YAML里的trajectory读取到std::vector<std::vector<double>>中,再手动转换成std::vector<std::pair<double, double>>

ros::NodeHandle nh_;
std::vector<std::vector<double>> temp_trajectory;
// 先读取到二维vector里
nh_.param<std::vector<std::vector<double>>>(obj_topic, temp_trajectory, {});

// 转换为你需要的vector<pair>类型
std::vector<std::pair<double, double>> trajectory_;
trajectory_.reserve(temp_trajectory.size()); // 提前分配空间提升效率
for (const auto& point : temp_trajectory) {
    if (point.size() == 2) { // 确保每个点是x,y两个值
        trajectory_.emplace_back(point[0], point[1]);
    } else {
        ROS_WARN("Skipping invalid trajectory point (not 2 elements)");
    }
}

解决办法2:自定义ROS参数解析适配器(适合频繁使用该类型的场景)

如果你的项目里需要多次读取std::vector<std::pair<double, double>>类型的参数,可以自定义ROS的ParamAdapter模板特化,让ROS支持这种类型的解析。在你的代码中添加以下适配器代码:

#include <ros/ros.h>
#include <XmlRpcValue.h>
#include <vector>
#include <utility>

namespace ros {
namespace parameter_adapter {

// 为std::pair<double, double>添加参数解析适配
template<>
struct ParamAdapter<std::pair<double, double>> {
    using Param = std::pair<double, double>;
    static bool get(const std::string& name, Param& val, const NodeHandle& nh) {
        XmlRpc::XmlRpcValue xml_val;
        if (!nh.getParam(name, xml_val)) {
            return false;
        }
        // 检查是否是包含两个元素的数组
        if (xml_val.getType() != XmlRpc::XmlRpcValue::TypeArray || xml_val.size() != 2) {
            ROS_ERROR_STREAM("Parameter " << name << " is not a valid 2-element array for pair<double,double>");
            return false;
        }
        val.first = static_cast<double>(xml_val[0]);
        val.second = static_cast<double>(xml_val[1]);
        return true;
    }
};

// 为std::vector<std::pair<double, double>>添加参数解析适配
template<>
struct ParamAdapter<std::vector<std::pair<double, double>>> {
    using Param = std::vector<std::pair<double, double>>;
    static bool get(const std::string& name, Param& val, const NodeHandle& nh) {
        XmlRpc::XmlRpcValue xml_val;
        if (!nh.getParam(name, xml_val)) {
            return false;
        }
        if (xml_val.getType() != XmlRpc::XmlRpcValue::TypeArray) {
            ROS_ERROR_STREAM("Parameter " << name << " is not a valid array for vector<pair<double,double>>");
            return false;
        }
        val.clear();
        val.reserve(xml_val.size());
        for (int i = 0; i < xml_val.size(); ++i) {
            XmlRpc::XmlRpcValue point_xml = xml_val[i];
            if (point_xml.getType() != XmlRpc::XmlRpcValue::TypeArray || point_xml.size() != 2) {
                ROS_WARN_STREAM("Skipping invalid point at index " << i << " in parameter " << name);
                continue;
            }
            double x = static_cast<double>(point_xml[0]);
            double y = static_cast<double>(point_xml[1]);
            val.emplace_back(x, y);
        }
        return true;
    }
};

} // namespace parameter_adapter
} // namespace ros

添加完这段代码后,你就可以直接用原来的代码读取参数了:

ros::NodeHandle nh_;
std::vector<std::pair<double, double>> trajectory_;
nh_.param<std::vector<std::pair<double, double>>>(obj_topic, trajectory_, {});

解决办法3:手动解析XmlRpcValue(最灵活,适合复杂场景)

如果你不想改动变量类型,也不想写适配器,可以直接读取原始的XmlRpc::XmlRpcValue对象,然后手动解析成目标类型:

ros::NodeHandle nh_;
std::vector<std::pair<double, double>> trajectory_;
XmlRpc::XmlRpcValue traj_xml;

if (nh_.getParam(obj_topic, traj_xml)) {
    if (traj_xml.getType() == XmlRpc::XmlRpcValue::TypeArray) {
        trajectory_.reserve(traj_xml.size());
        for (int i = 0; i < traj_xml.size(); ++i) {
            XmlRpc::XmlRpcValue point_xml = traj_xml[i];
            // 检查每个点是否是包含两个元素的数组
            if (point_xml.getType() == XmlRpc::XmlRpcValue::TypeArray && point_xml.size() == 2) {
                double x = static_cast<double>(point_xml[0]);
                double y = static_cast<double>(point_xml[1]);
                trajectory_.emplace_back(x, y);
            } else {
                ROS_WARN_STREAM("Invalid trajectory point at index " << i << ", skipping");
            }
        }
    } else {
        ROS_ERROR_STREAM("Parameter " << obj_topic << " is not a valid array");
    }
} else {
    ROS_WARN_STREAM("Failed to get parameter " << obj_topic << ", using empty trajectory");
}

总结

如果只是偶尔读取这种类型的参数,解决办法1是最省心的;如果项目里经常用到std::pair<double, double>作为参数,解决办法2一劳永逸;如果需要自定义解析逻辑(比如过滤无效点、类型转换容错),解决办法3最灵活。

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

火山引擎 最新活动