Ros学习日记2-2021/7/24

博客讲述了在ROS中遇到的网络速度慢和浏览器问题,以及在进行乌龟跟踪实验时碰到的参数传递错误。通过重装系统、更换浏览器解决了网络问题。在tf乌龟跟踪实验中,发现roslaunch启动节点时额外参数导致问题,通过研究了解到这是ROS的特性。博主使用参数服务器来解决节点参数传递,通过设置和读取参数实现了节点复用,并给出了完整的代码示例,成功实现两个乌龟的tf坐标变换发布。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这几天没遇到什么很困难的问题,前几天发现网速很慢,网上说是dns的问题,折腾了好久,最后把网络给搞崩了,最后只能重装了一下系统,后来发现好像是火狐浏览器的问题,用这个浏览器上网就巨慢,b站都卡的不行,换了chrome之后居然就好了....

之后这几天发现写service client的时候经常会忘记加上这个函数等待。

client.waitForExistence();

所以经常报错,这个以后要多注意一下。

现在遇到的一个比较困难的问题是在做乌龟的跟踪实验时出现的。

我根据奥特学园的教程走,在203P的tf乌龟跟踪实验中,需要用roslaunch配合main函数的arg

argv两个参数来实现对两只乌龟tf坐标变换的获取,根据教程,我的launch文件写成了这样:

<launch>
    <node pkg="turtlesim" type="turtlesim_node" name="turtle1" output="screen" />
    <node pkg="turtlesim" type="turtle_teleop_key" name="key" output="screen" />

    <node pkg="turtle_follow" type="new_turtle" name="turtle2" output="screen" />

    <node pkg="turtle_follow" type="turtle_pose_pub" name="turtle_pose_pub1" output="screen" args="turtle1"/>
    <node pkg="turtle_follow" type="turtle_pose_pub" name="turtle_pose_pub2" output="screen" args="turtle2"/>
</launch>

和教程一样,但是却无法启动,无法发布乌龟的数据,在反复检查了程序后,我用rosrun的指令运行了一下,发现没有问题,于是我就知道是launch文件出现了问题。

具体问题

因为在教程中,会根据argc来进行判断argv的参数数量,并进行报错处理,所以我直接就定位了这个问题,使用了一个for循环输出了argv捕获到的所有参数:

    if(argc !=2 )
    {
        ROS_ERROR("参数输入错误,应输入一个参数,输入了%d个参数",argc);
        for(int i = 0; i < argc; i++)
        {
            ROS_ERROR("第%d个参数是%s",argc,argv[i]);
        }

        return 0;
    }

 可以发现,第一个参数是文件名,这个没有问题,第二个参数是我用launch文件传进去的,也没有问题,但是第三个和第四个参数出现问题了,这两个参数我并没有传入,但是却被argv给捕获到了,导致程序出现异常。

问题原因

这个问题我在百度上找了很久都没有找到原因,最后在google上找到了:问题原因

里面的回答是这样的:

大概就是说:当rosrun运行的时候,只传入特殊声明的参数(也就是后面输入的参数),但是roslaunch总是会加入__name等参数去设置节点名等,话题名的映射也是用这种命令行参数的方式操作的,然后就是要确定节点可以接收ros的特殊参数或者干脆就直接避免命令行参数,大多数情况下用参数服务器是更好的选择。

针对这个问题,我暂时选择了用两个cpp文件的方式将教程的发布乌龟tf坐标变换数据功能实现了,当然也可以把判断中argc改成4,然后读取argv[1]的数据,此外则是可以改用参数服务器来进行操作。

如何使用参数服务器来进行操作,还要后面有时间再看一下。

方案:使用参数服务器中的参数来读入乌龟的名字。

在读取乌龟名字的时候,因为/turtle1/pose/turtle2/pose这个话题名已经固定了,需要读取的乌龟名字就是turtle1turtle2这两个string,如果这个参数是一个私有变量,那么在读取的时候就要读取/节点名/参数名,而节点名字是在launch文件中写入的,在程序中就需要通过__name这个参数来读取,很麻烦,所以我将这个参数设置为了全局变量,保证这两个节点不需要修改程序便能直接复用读取。

使用参数服务器实现程序复用时候遇到了一个问题:由于launch文件不能指定节点的启动顺序,而且在调用第二个节点时需要改变这个string变量,这就需要在第一个节点中将string变量进行修改,来让第二个节点成功调用。

为此,我在launch文件中设置了两个参数,一个是乌龟名字turtlename,用来以后代码复用的时候方便进行修改,另一个是乌龟的编号turtlecnt,用来记录启动次数,以此来改变turtle1turtle2后面这个1/2:

<launch>
    <param name="turtlename" type="string" value="turtle" />
    <param name="turtlecnt" type="int" value="1" />

    <node pkg="turtlesim" type="turtlesim_node" name="turtle1" output="screen"/>
    <node pkg="turtlesim" type="turtle_teleop_key" name="key" output="screen" />
    <node pkg="turtle_follow" type="new_turtle" name="turtle2" output="screen" />
    <node pkg="turtle_follow" type="turtle_pose_pub" name="turtle_pose_pub1" output="screen" />
    <node pkg="turtle_follow" type="turtle_pose_pub" name="turtle_pose_pub2" output="screen" />
</launch>

之后,在节点中对这两个参数进行读取、组合和操作:


    if(flag != true)
    {
        ROS_ERROR("乌龟名读取错误!");
        return 1;
    }
    else
        ROS_INFO("乌龟名读取参数:%s",turtlename.c_str());
    

    flag = n.getParam("turtlecnt",turtlecnt);

    if(flag != true)
    {
        ROS_ERROR("乌龟编号读取错误!");
        return 1;
    }
    else
        ROS_INFO("乌龟编号读取参数:%d",turtlecnt);

    ros::Subscriber sub = n.subscribe(turtlename + std::to_string(turtlecnt) + "/pose",10,func);

    turtlecnt++;

    n.setParam("turtlecnt",turtlecnt);

最终完整程序如下所示:

#include"ros/ros.h"
#include"turtlesim/Pose.h"
#include"tf2_ros/transform_broadcaster.h"
#include"geometry_msgs/TransformStamped.h"
#include"tf2_geometry_msgs/tf2_geometry_msgs.h"
#include"tf2/LinearMath/Quaternion.h"

std::string turtlename;
int turtlecnt;

void func(const turtlesim::Pose::ConstPtr &p)
{
    static tf2_ros::TransformBroadcaster pub;
    static geometry_msgs::TransformStamped tfs;

    tfs.header.frame_id = "world";
    tfs.header.stamp = ros::Time::now();
    tfs.child_frame_id = turtlename+ std::to_string(turtlecnt-1);
    tfs.transform.translation.x = p->x;
    tfs.transform.translation.y = p->y;
    tfs.transform.translation.z = 0.0;

    tf2::Quaternion qtn;

    qtn.setRPY(0,0,p->theta);
    tfs.transform.rotation.x = qtn.getX();
    tfs.transform.rotation.y = qtn.getY();
    tfs.transform.rotation.z = qtn.getZ();
    tfs.transform.rotation.w = qtn.getW();

    pub.sendTransform(tfs);    
}

int main(int argc, char *argv[])
{

    setlocale(LC_ALL,"");

    ros::init(argc,argv,"turtle_pose_pub");
    
    ros::NodeHandle n;

    bool flag = n.getParam("turtlename",turtlename);

    if(flag != true)
    {
        ROS_ERROR("乌龟名读取错误!");
        return 1;
    }
    else
        ROS_INFO("乌龟名读取参数:%s",turtlename.c_str());
    

    flag = n.getParam("turtlecnt",turtlecnt);

    if(flag != true)
    {
        ROS_ERROR("乌龟编号读取错误!");
        return 1;
    }
    else
        ROS_INFO("乌龟编号读取参数:%d",turtlecnt);

    ros::Subscriber sub = n.subscribe(turtlename + std::to_string(turtlecnt) + "/pose",10,func);

    turtlecnt++;

    n.setParam("turtlecnt",turtlecnt);

    ros::spin();

    return 0;
}

运行roslaunch进行测试:

程序成功运行,两个乌龟的坐标已经被两个节点分别订阅了,用rviz看一下:

两只乌龟的tf动态坐标变换都已经发布成功。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值