ROS初学者编写小乌龟以一定速度旋转一定角度的server

编写server.cpp让小乌龟以一定速度旋转一定角度

在src文件夹下新建srv文件夹

添加rotate_angle.srv文件

float64 angle //输入的弧度
float64 angular_velocity//输入的角速度(rad/s)
float64 time//设定超时时间,超过这个时间退出循环

---
bool success//返回一个bool型的参数
string message//返回信息

编译.srv文件后,会在工作空间/devel/include中响应的包内产生相应的头文件
在这里插入图片描述

在src文件夹下新建server.cpp文件

//该例程将执行/rotate_angle服务,服务数据类型为service_demo/rotate_angle

#include <ros/ros.h>
#include <geometry_msgs/Twist.h>
#include <turtlesim/Pose.h>
#include <service_demo/rotate_angle.h>
#include <cmath>

ros::Publisher turtle_angular_velocity_pub; //定义角速度的发布者
ros::Subscriber turtle_angle_sub;//定义小乌龟角度的接收者,接收的话题为/turtle1/pose

geometry_msgs::Twist vel_msg;//定义type为geometry_msgs::Twist的vel_msg,用来接收传入的速度信息(弧度每秒)
turtlesim::Pose nowps,addps;//定义type为turtlesim::Pose的nowps,addps,用来表示现在的弧度,以及用来接收增加的弧度
bool pubCommand = false;
float time_out; //定义一个time_out来接收设定超时时间大小

//service 回调函数,输入参数req,输出参数res
bool angleCallback(service_demo::rotate_angle::Request &req, 
                                         service_demo::rotate_angle::Response &res)
{
    pubCommand = !pubCommand; //取反

    vel_msg.angular.z = req.angular_velocity; //传入的角速度赋值给前面定义的vel_msg,.angular.z表示为绕z轴旋转的角速度

    addps.theta = req.angle;//传入的角度赋值给前面定义的addps,.theta表示角度

    time_out = req.time;//传入的时间赋值给前面定义的time_out
    //至此可以发现一共接收三个信息:旋转的角速度,旋转的弧度,以及超时时间(超过这个时间退出循环)

    //显示请求数据
    ROS_INFO("Publish angle [%f] , angle_velocity [%f] ",req.angle,req.angular_velocity);

    //显示现在时间
    ros::Time begin =ros::Time::now();
    ROS_INFO_STREAM("The beginning of time :"<<begin);

    //设置反馈数据
    res.success = true;
    res.message = "Change state!";

    return true;

}
//subscriber回调函数
void poseCallback(const turtlesim::Pose pose)
{
    //小乌龟现在的位姿theta赋值给前面定义的nowps
    nowps.theta = pose.theta;
}

//主函数
int main(int argc ,char **argv)
{
   //ROS节点初始化 
    ros::init(argc,argv,"rotate_angle_server");

    ros::NodeHandle n;//创建节点句柄

    //创建一个名为/rotate_angle的server,注册回调函数angleCallback
    ros::ServiceServer angle_service = n.advertiseService("/rotate_angle",angleCallback);

    //创建一个Publisher,发布名为/turtle1/cmd_vel的topic ,消息类型为geometry_msgs::Twist,队列长度为10
    turtle_angular_velocity_pub = n.advertise<geometry_msgs::Twist>("/turtle1/cmd_vel",10);

    //创建一个Subscriber,接收名为/turtle1/pose的topic,消息类型为tuetlesim/Pose,队列长度为1000
    turtle_angle_sub = n.subscribe<turtlesim::Pose>("/turtle1/pose",1000,poseCallback);

    int count = 0;
    
    turtlesim::Pose firstps,finalps;//定义初始时刻小乌龟的位姿firstps,终止时刻的位姿finalps

    ROS_INFO("Ready to receive command");//循环等待回调函数

    ros::Rate loop_rate(10);//设置循环频率

    //ros::spin();

    while(ros::ok())
   {
       //查看一次回调函数队列
        ros::spinOnce();

        if(pubCommand)
        {
            if(count == 0)
            {
                firstps.theta = nowps.theta;//记录初始时刻的theta
                ROS_INFO_STREAM("The first pose theta is "<<firstps.theta); 
            }
            if(fabs(nowps.theta-firstps.theta) <= 3.1415926) //因为是弧度制,变化范围为-3.1415~+3.1415,所以需要分情况来进行讨论
            {
                if(fabs(nowps.theta-firstps.theta)<addps.theta)//当现在位置与初始位置的绝对值小于用户要求旋转的角度
                {
                turtle_angular_velocity_pub.publish(vel_msg);//发布前面定义的vel_msg,其中绕z轴的速度是用户自行设定然后赋值的
                count++;
                if(count > 11*time_out)//因为频率为10,所以一秒钟执行10次循环,用户输入时间*10也就是最大循环次数,当超过当前这个次数时也就可以视为超时,这里我们取的大一些,乘上11,超时后直接退出循环
                {
                    ROS_INFO("False");
                    break;
                }
                }
                else
                {
                    finalps.theta=nowps.theta;//如果没有超过用户设定的时间,旋转完成最后输出最终的theta
                    ROS_INFO_STREAM("The first pose theta "<<firstps.theta<<"; The final pose theta "<<finalps.theta); 
                    break;
                     //ros::shutdown();
                }
            }
            if(fabs(nowps.theta-firstps.theta) > 3.1415926)
            {
                if(6.2831852-fabs(nowps.theta-firstps.theta)<addps.theta)
                {
                turtle_angular_velocity_pub.publish(vel_msg);//同上
                count++;
                if(count > 11*time_out)
                {
                    ROS_INFO("False");
                    break;
                }
                }
                else
                {
                    finalps.theta=nowps.theta;
                    ROS_INFO_STREAM("The first pose theta "<<firstps.theta<<"; The final pose theta "<<finalps.theta); 
                    break;
                    //ros::shutdown();
                }
            }
            
        }
        //按照循环频率延时
        loop_rate.sleep();
   }

    ros::Time end = ros::Time::now(); //输出结束的时间
    ROS_INFO_STREAM("The end of time :"<<end); 


    return 0;

}

运行server

rosservice call /rotate_angle 双击tab键补全,输入角速度为0.25,旋转弧度为1.0,要求时间为2.0秒,显然旋转这1弧度需要4秒,而我们设定了最大时间2秒,乌龟还没有旋转完成就返回False。
在这里插入图片描述
修改时间,把要求时间改为5.0秒,可以看到没有返回false,最后输出了 final pose theta
在这里插入图片描述

结语

刚开始尝试自己写一点代码,感觉写的比较乱,有问题还望大家指正~

  • 3
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是ROS小乌龟画五角星的C++代码实现: ```cpp #include <ros/ros.h> #include <geometry_msgs/Twist.h> #include <turtlesim/Pose.h> #include <math.h> // 订阅小乌龟的位置信息 void poseCallback(const turtlesim::PoseConstPtr& pose_msg); // 移动函数 void move(double speed, double distance, bool is_forward, ros::Publisher vel_pub); // 旋转函数 void rotate(double angle, ros::Publisher vel_pub); int main(int argc, char** argv) { // 初始化节点 ros::init(argc, argv, "draw_star"); // 创建节点句柄 ros::NodeHandle nh; // 创建Publisher,用于发布小乌龟的移动指令 ros::Publisher vel_pub = nh.advertise<geometry_msgs::Twist>("/turtle1/cmd_vel", 10); // 创建Subscriber,用于订阅小乌龟的位置信息 ros::Subscriber pose_sub = nh.subscribe("/turtle1/pose", 10, poseCallback); // 等待小乌龟的初始位置 while(!ros::ok() || !pose_sub.getNumPublishers()) { ROS_INFO("Waiting for pose subscriber..."); ros::Duration(0.1).sleep(); } // 移动到五角星起点 move(2.0, 5.0, true, vel_pub); rotate(-1.256, vel_pub); // -72度 // 绘制五角星 for(int i = 0; i < 5; i++) { move(2.0, 5.0, true, vel_pub); rotate(-2.513, vel_pub); // -144度 } // 停止节点 ros::spin(); return 0; } void poseCallback(const turtlesim::PoseConstPtr& pose_msg) { // do nothing } void move(double speed, double distance, bool is_forward, ros::Publisher vel_pub) { // 创建Twist消息 geometry_msgs::Twist vel_msg; // 设置线速度 vel_msg.linear.x = fabs(speed) * (is_forward ? 1 : -1); // 设置移动距离 double distance_moved = 0.0; ros::Rate rate(10); while(distance_moved < distance) { // 发布移动指令 vel_pub.publish(vel_msg); // 计算移动距离 distance_moved += fabs(0.5 * speed * 0.1); // 等待0.1秒 rate.sleep(); } // 停止移动 vel_msg.linear.x = 0; vel_pub.publish(vel_msg); } void rotate(double angle, ros::Publisher vel_pub) { // 创建Twist消息 geometry_msgs::Twist vel_msg; // 设置角速度 vel_msg.angular.z = angle; // 设置旋转时间 double time_sec = fabs(angle) / 1.0; // 发布旋转指令 ros::Time t0 = ros::Time::now(); while((ros::Time::now() - t0).toSec() < time_sec) { vel_pub.publish(vel_msg); } // 停止旋转 vel_msg.angular.z = 0; vel_pub.publish(vel_msg); } ``` 运行以上代码后,小乌龟就会在窗口中绘制出一个五角星了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值