IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 人工智能 -> ROS By Example:python 转 C++ 之 nav_square -> 正文阅读

[人工智能]ROS By Example:python 转 C++ 之 nav_square

1 写在前面

笔者近期学习了《ROS by Example. Do-It-Yourself Guide to the Robot Operating System》,书中的代码全部是用python来编写的,为了保证完全理解其代码的含义及代码背后的相关知识,这里我将其代码用C++实现了一遍,写下此文章用作记录存留。

2 主要内容

本文对应第7.8章节中的内容,实现了 nav_square.pynav_square.cpp 的转换。

开发环境:Ubuntu14.04 + ROS-Indigo

3 原始python脚本

nav_square.py

#!/usr/bin/env python

import rospy
from geometry_msgs.msg import Twist, Point, Quaternion
import tf
from rbx1_nav.transform_utils import quat_to_angle, normalize_angle
from math import radians, copysign, sqrt, pow, pi

class NavSquare():
    def __init__(self):
        # Give the node a name
        rospy.init_node('nav_square', anonymous=False)
        
        # Set rospy to execute a shutdown function when terminating the script
        rospy.on_shutdown(self.shutdown)

        # How fast will we check the odometry values?
        rate = 20
        
        # Set the equivalent ROS rate variable
        r = rospy.Rate(rate)
        
        # Set the parameters for the target square
        goal_distance = rospy.get_param("~goal_distance", 1.0)      # meters
        goal_angle = radians(rospy.get_param("~goal_angle", 90))    # degrees converted to radians
        linear_speed = rospy.get_param("~linear_speed", 0.2)        # meters per second
        angular_speed = rospy.get_param("~angular_speed", 0.7)      # radians per second
        angular_tolerance = radians(rospy.get_param("~angular_tolerance", 2)) # degrees to radians
        
        # Publisher to control the robot's speed
        self.cmd_vel = rospy.Publisher('/cmd_vel', Twist, queue_size=5)
         
        # The base frame is base_footprint for the TurtleBot but base_link for Pi Robot
        self.base_frame = rospy.get_param('~base_frame', '/base_link')

        # The odom frame is usually just /odom
        self.odom_frame = rospy.get_param('~odom_frame', '/odom')

        # Initialize the tf listener
        self.tf_listener = tf.TransformListener()
        
        # Give tf some time to fill its buffer
        rospy.sleep(2)
        
        # Set the odom frame
        self.odom_frame = '/odom'
        
        # Find out if the robot uses /base_link or /base_footprint
        try:
            self.tf_listener.waitForTransform(self.odom_frame, '/base_footprint', rospy.Time(), rospy.Duration(1.0))
            self.base_frame = '/base_footprint'
        except (tf.Exception, tf.ConnectivityException, tf.LookupException):
            try:
                self.tf_listener.waitForTransform(self.odom_frame, '/base_link', rospy.Time(), rospy.Duration(1.0))
                self.base_frame = '/base_link'
            except (tf.Exception, tf.ConnectivityException, tf.LookupException):
                rospy.loginfo("Cannot find transform between /odom and /base_link or /base_footprint")
                rospy.signal_shutdown("tf Exception")  
                
        # Initialize the position variable as a Point type
        position = Point()

        # Cycle through the four sides of the square
        for i in range(4):
            # Initialize the movement command
            move_cmd = Twist()
            
            # Set the movement command to forward motion
            move_cmd.linear.x = linear_speed
            
            # Get the starting position values     
            (position, rotation) = self.get_odom()
                        
            x_start = position.x
            y_start = position.y
            
            # Keep track of the distance traveled
            distance = 0
            
            # Enter the loop to move along a side
            while distance < goal_distance and not rospy.is_shutdown():
                # Publish the Twist message and sleep 1 cycle         
                self.cmd_vel.publish(move_cmd)
                
                r.sleep()
        
                # Get the current position
                (position, rotation) = self.get_odom()
                
                # Compute the Euclidean distance from the start
                distance = sqrt(pow((position.x - x_start), 2) + 
                                pow((position.y - y_start), 2))
                
            # Stop the robot before rotating
            move_cmd = Twist()
            self.cmd_vel.publish(move_cmd)
            rospy.sleep(1.0)
            
            # Set the movement command to a rotation
            move_cmd.angular.z = angular_speed
            
            # Track the last angle measured
            last_angle = rotation
            
            # Track how far we have turned
            turn_angle = 0
            
            # Begin the rotation
            while abs(turn_angle + angular_tolerance) < abs(goal_angle) and not rospy.is_shutdown():
                # Publish the Twist message and sleep 1 cycle         
                self.cmd_vel.publish(move_cmd)
                
                r.sleep()
                
                # Get the current rotation
                (position, rotation) = self.get_odom()
                
                # Compute the amount of rotation since the last lopp
                delta_angle = normalize_angle(rotation - last_angle)
                
                turn_angle += delta_angle
                last_angle = rotation

            move_cmd = Twist()
            self.cmd_vel.publish(move_cmd)
            rospy.sleep(1.0)
            
        # Stop the robot when we are done
        self.cmd_vel.publish(Twist())
        
    def get_odom(self):
        # Get the current transform between the odom and base frames
        try:
            (trans, rot)  = self.tf_listener.lookupTransform(self.odom_frame, self.base_frame, rospy.Time(0))
        except (tf.Exception, tf.ConnectivityException, tf.LookupException):
            rospy.loginfo("TF Exception")
            return

        return (Point(*trans), quat_to_angle(Quaternion(*rot)))
            
    def shutdown(self):
        # Always stop the robot when shutting down the node
        rospy.loginfo("Stopping the robot...")
        self.cmd_vel.publish(Twist())
        rospy.sleep(1)

if __name__ == '__main__':
    try:
        NavSquare()
    except rospy.ROSInterruptException:
        rospy.loginfo("Navigation terminated.")

4 转换后的C++代码

nav_square.cpp

// sys
#include <math.h>
#include <signal.h>
// ros
#include "ros/ros.h"
#include "geometry_msgs/Twist.h"
#include "geometry_msgs/Point.h"
#include "geometry_msgs/Quaternion.h"
#include "tf/transform_listener.h"

ros::Publisher cmd_vel_pub;

void NodeShutdown(int sig)
{
	ROS_INFO("node \"nav_square\" shutting down!");
    cmd_vel_pub.publish(geometry_msgs::Twist());
    sleep(1);
	ros::shutdown();
    exit(sig);
}

// Get the current transform between the odom and base frames
bool get_odom(const tf::TransformListener &listener, 
              const std::string &target_frame, 
              const std::string &source_frame, 
              tf::StampedTransform &transform)
{
    try
    {
        listener.lookupTransform(target_frame, source_frame, ros::Time(0), transform);
    }
    catch(...)
    {
        ROS_ERROR("TF Exception");
        return false;
    }
    return true;
}

int main(int argc, char **argv)
{
    ros::init(argc, argv, "nav_square", ros::init_options::NoSigintHandler);
    ros::NodeHandle node;
    signal(SIGINT, NodeShutdown);
    cmd_vel_pub = node.advertise<geometry_msgs::Twist>("/cmd_vel", 5);
    int rate = 20;  //Hz
    ros::Rate loop_rate(rate);

    // Set the parameters for the target square
    double goal_distance;       // meters
    double goal_angle;          // degrees converted to radians
    double linear_speed;        // meters per second
    double angular_speed;       // radians per second
    double angular_tolerance;   // degrees to radians
    ros::param::param<double>("~goal_distance",     goal_distance,     1.0 );
    ros::param::param<double>("~goal_angle",        goal_angle,        M_PI_2);
    ros::param::param<double>("~linear_speed",      linear_speed,      0.2 );
    ros::param::param<double>("~angular_speed",     angular_speed,     0.2 );
    ros::param::param<double>("~angular_tolerance", angular_tolerance, M_PI/180.0);

    // The base frame is base_footprint for the TurtleBot but base_link for Pi Robot
    std::string base_frame;
    ros::param::param<std::string>("~base_frame", base_frame, "/base_footprint");

    // The odom frame is usually just /odom
    std::string odom_frame;
    ros::param::param<std::string>("~odom_frame", odom_frame, "/odom");

    // Initialize the tf listener
    tf::TransformListener tf_listener;

    // Give tf some time to fill its buffer
    sleep(2);

    // Initialize the position variable as a Point type
    geometry_msgs::Point position;

    // Cycle through the four sides of the square
    for (int  i = 0; i < 4; ++i)
    {
        // Initialize the movement command
        geometry_msgs::Twist move_cmd;

        // Set the movement command to forward motion
        move_cmd.linear.x = linear_speed;

        // Get the starting position values    
        tf::StampedTransform transform; 
        get_odom(tf_listener, odom_frame, base_frame, transform);
        double x_start = transform.getOrigin().x();
        double y_start = transform.getOrigin().y();

        // Keep track of the distance traveled
        double distance = 0;

        while (distance < goal_distance && node.ok())
        {
            // Publish the Twist message and sleep 1 cycle 
            cmd_vel_pub.publish(move_cmd);
            loop_rate.sleep();

            // Get the current position
            get_odom(tf_listener, odom_frame, base_frame, transform);
            position.x = transform.getOrigin().x();
            position.y = transform.getOrigin().y();

            // Compute the Euclidean distance from the start
            distance = sqrt(pow((position.x - x_start), 2) + 
                            pow((position.y - y_start), 2));
        }

        // Stop the robot before rotating
        move_cmd.linear.x = 0;
        cmd_vel_pub.publish(move_cmd);
        loop_rate.sleep();

        // Set the movement command to a rotation
        move_cmd.angular.z = angular_speed;

        // Track the last angle measured
        double last_angle = fabs(tf::getYaw(transform.getRotation()));

        // Track how far we have turned
        double turn_angle = 0;

        // Begin the rotation
        while(fabs(turn_angle + angular_tolerance) < fabs(goal_angle) && node.ok())
        {
            // Publish the Twist message and sleep 1 cycle
            cmd_vel_pub.publish(move_cmd);
            loop_rate.sleep();

            // Get the current rotation
            get_odom(tf_listener, odom_frame, base_frame, transform);

            // Compute the amount of rotation since the last lopp
            double current_angle = fabs(tf::getYaw(transform.getRotation()));
            double delta_angle = fabs(current_angle - last_angle);

            // Add to the running total
            turn_angle += delta_angle;
            last_angle = current_angle;
        }
        // Stop the robot before the next loop
        move_cmd.angular.z = 0;
        cmd_vel_pub.publish(move_cmd);
        loop_rate.sleep();
        
        // Stop the robot when we are done
        cmd_vel_pub.publish(geometry_msgs::Twist());
    }
    
    return 0;
}

在编译前,还需要在CMakeLists.txt文件中加入以下内容:

add_executable(nav_square src/nav_square.cpp)
target_link_libraries(nav_square ${catkin_LIBRARIES})
  人工智能 最新文章
2022吴恩达机器学习课程——第二课(神经网
第十五章 规则学习
FixMatch: Simplifying Semi-Supervised Le
数据挖掘Java——Kmeans算法的实现
大脑皮层的分割方法
【翻译】GPT-3是如何工作的
论文笔记:TEACHTEXT: CrossModal Generaliz
python从零学(六)
详解Python 3.x 导入(import)
【答读者问27】backtrader不支持最新版本的
上一篇文章      下一篇文章      查看所有文章
加:2021-10-27 12:50:24  更:2021-10-27 12:52:03 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/27 8:22:53-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码