亚博microros小车-原生ubuntu支持系列:15 激光雷达巡逻

一 TF坐标转换

ros2 -5.1 坐标变化工具介绍_ros怎么发布坐标变化-CSDN博客

ros2笔记-5.3 C++中地图坐标系变换_c++变换坐标系-CSDN博客

header:
  stamp:
    sec: 1737893911
    nanosec: 912000000
  frame_id: odom_frame
child_frame_id: base_footprint
pose:
  pose:
    position:
      x: 0.05383127182722092
      y: -0.08320192247629166
      z: 0.0
    orientation:
      x: 0.0
      y: 0.0
      z: -0.4827535152435303
      w: 0.8757562637329102
  covariance:
  - 0.001
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.001
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.0
  - 0.001
twist:
  twist:
    linear:
      x: 0.0
      y: 0.0
      z: 0.0
    angular:
      x: 0.0
      y: 0.0
      z: 0.0
  covariance:
  - 0.0001
  - 0.0
  - 0.0

 src/yahboomcar_base_node/src/base_node_X3.cpp ,代码如下

#include <geometry_msgs/msg/transform_stamped.hpp>
#include "geometry_msgs/msg/twist.hpp"
#include "nav_msgs/msg/odometry.hpp"

#include <rclcpp/rclcpp.hpp>
#include <tf2/LinearMath/Quaternion.h>
#include <tf2_ros/transform_broadcaster.h>

#include <memory>
#include <string>

#include <geometry_msgs/msg/transform_stamped.hpp>

#include <rclcpp/rclcpp.hpp>
#include <tf2/LinearMath/Quaternion.h>
#include <tf2_ros/transform_broadcaster.h>

#include <memory>
#include <string>

#include <chrono>
#include <functional>
#include <memory>
#include <string>

#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"
using std::placeholders::_1;

class OdomPublisher:public rclcpp ::Node
{
   rclcpp::Subscription<nav_msgs::msg::Odometry>::SharedPtr subscription_;
   //rclcpp::Publisher<nav_msgs::msg::Odometry>::SharedPtr odom_publisher_;
   std::unique_ptr<tf2_ros::TransformBroadcaster> tf_broadcaster_;
   double linear_scale_x_ = 0.0 ;
   double linear_scale_y_ = 0.0;
   double vel_dt_ = 0.0;
   double x_pos_ = 0.0;
   double y_pos_ = 0.0;
   double heading_ = 0.0;
   double linear_velocity_x_ = 0.0;
   double linear_velocity_y_ = 0.0;
   double angular_velocity_z_ = 0.0;
   double wheelbase_ = 0.25;
   bool pub_odom_tf_ = false;
   rclcpp::Time last_vel_time_  ;
   std::string odom_frame = "odom";
   std::string base_footprint_frame = "base_footprint";
	public:
	  OdomPublisher()
	  : Node("base_node")
	  {
            this->declare_parameter<double>("wheelbase",0.25);
            this->declare_parameter<std::string>("odom_frame","odom");
            this->declare_parameter<std::string>("base_footprint_frame","base_footprint"); 
            this->declare_parameter<double>("linear_scale_x",1.0);
            this->declare_parameter<double>("linear_scale_y",1.0);
            this->declare_parameter<bool>("pub_odom_tf",false);

            this->get_parameter<double>("linear_scale_x",linear_scale_x_);
            this->get_parameter<double>("linear_scale_y",linear_scale_y_);
            this->get_parameter<double>("wheelbase",wheelbase_);
            this->get_parameter<bool>("pub_odom_tf",pub_odom_tf_);
            this->get_parameter<std::string>("odom_frame",odom_frame);
            this->get_parameter<std::string>("base_footprint_frame",base_footprint_frame);
        tf_broadcaster_ = std::make_unique<tf2_ros::TransformBroadcaster>(*this);//创建智能指针
        //订阅odom
	  	subscription_ = this->create_subscription<nav_msgs::msg::Odometry>("odom_raw",50,std::bind(&OdomPublisher::handle_vel,this,_1));
	  	
	  	}
	  	private:
	  	  void handle_vel(const std::shared_ptr<nav_msgs::msg::Odometry > msg)
	  	  {
                       
	  	  	rclcpp::Time curren_time = rclcpp::Clock().now();

			vel_dt_ = (curren_time - last_vel_time_).seconds();

    		last_vel_time_ = curren_time;


            
            
                geometry_msgs::msg::TransformStamped t;
                rclcpp::Time now = this->get_clock()->now();
                t.header.stamp = now;
                t.header.frame_id = odom_frame;
                t.child_frame_id = base_footprint_frame;
                t.transform.translation.x = msg->pose.pose.position.x;
                t.transform.translation.y = msg->pose.pose.position.y;
                t.transform.translation.z = msg->pose.pose.position.z;
                
                t.transform.rotation.x = msg->pose.pose.orientation.x;
                t.transform.rotation.y = msg->pose.pose.orientation.y;
                t.transform.rotation.z = msg->pose.pose.orientation.z;
                t.transform.rotation.w = msg->pose.pose.orientation.w;
                
                tf_broadcaster_->sendTransform(t);//发布坐标变换,
                //std::cout<<"pos.x: "<<msg->pose.pose.position.x<<std::endl;
                  
            
		  	  }

};


int main(int argc, char * argv[])
{
	rclcpp::init(argc, argv);
	rclcpp::spin(std::make_shared<OdomPublisher>());
	rclcpp::shutdown();
    return 0;
}

这个就是接收了odom的数据,转换为TF的数据发布。其中父:odom,子:base_footprint

转换之后日志

transforms:
- header:
    stamp:
      sec: 1737894112
      nanosec: 230489357
    frame_id: odom
  child_frame_id: base_footprint
  transform:
    translation:
      x: 0.05383127182722092
      y: -0.08320192247629166
      z: 0.0
    rotation:
      x: 0.0
      y: 0.0
      z: -0.4827535152435303
      w: 0.8757562637329102

二 激光雷达巡逻

小车连接上代理,运行程序,在动态参数调节器设定需要巡逻的路线,然后点击开始。小车会根据设定的巡逻路线进行运动,同时小车上的雷达会扫描设定的雷达角度和设定障碍检测距离范围内是否有障碍物,有障碍则会停下且蜂鸣器会响,没有障碍物则继续巡逻。

src/yahboomcar_bringup/yahboomcar_bringup/目录下新建文件patrol.py

#for patrol
#math 数学
import math
from math import radians, copysign, sqrt, pow
from math import pi
import numpy as np
import os
import sys
#rclpy ros2的模块
import rclpy
from rclpy.node import Node
#tf 坐标变化
from tf2_ros import TransformException
from tf2_ros.buffer import Buffer
from tf2_ros.transform_listener import TransformListener
from tf2_ros import LookupException, ConnectivityException, ExtrapolationException
#msg 消息
from geometry_msgs.msg import Twist, Point,Quaternion
from sensor_msgs.msg import LaserScan
from std_msgs.msg import Bool,UInt16
#others 工具类
import PyKDL
from time import sleep

print("import finish")

RAD2DEG = 180 / math.pi

class YahboomCarPatrol(Node):
    def __init__(self,name):
        super().__init__(name)
        self.moving = True
        self.Joy_active = False
        self.command_src = "finish"
        self.warning = 1
        self.SetLoop = False
        self.Linear = 0.5
        self.Angular = 1.0
        self.Length = 1.0 #1.0
        self.Angle = 360.0
        self.LineScaling = 1.0
        self.RotationScaling = 1.0
        self.LineTolerance = 0.1
        self.RotationTolerance = 0.05
        #self.ResponseDist = 0.6
        #self.LaserAngle = 20
        self.warning = 1
        #self.Command = "LengthTest"
        #self.Switch = False
        self.position = Point()
        self.x_start = self.position.x
        self.y_start = self.position.y
        self.error = 0.0
        self.distance = 0.0 
        self.last_angle = 0.0 
        self.delta_angle = 0.0
        self.turn_angle = 0.0
        #create publisher 发布话题,控制与蜂鸣器
        self.pub_cmdVel = self.create_publisher(Twist,"cmd_vel",5)
        self.pub_Buzzer = self.create_publisher(UInt16,'/beep',1)
        #create subscriber
        self.sub_scan = self.create_subscription(LaserScan,"/scan",self.LaserScanCallback,1)
        self.sub_joy = self.create_subscription(Bool,"/JoyState",self.JoyStateCallback,1)
        #create TF tf2 监听器
        self.tf_buffer = Buffer()
        self.tf_listener = TransformListener(self.tf_buffer,self)
        #declare param 声明了一堆参数
        self.declare_parameter('odom_frame',"odom")
        self.odom_frame = self.get_parameter('odom_frame').get_parameter_value().string_value
        self.declare_parameter('base_frame',"base_footprint")
        self.base_frame = self.get_parameter('base_frame').get_parameter_value().string_value
        self.declare_parameter("circle_adjust",2.0)
        self.circle_adjust = self.get_parameter("circle_adjust").get_parameter_value().double_value
        self.declare_parameter('Switch',False)
        self.Switch = self.get_parameter('Switch').get_parameter_value().bool_value
        self.declare_parameter('Command',"Square")
        self.Command = self.get_parameter('Command').get_parameter_value().string_value
        self.declare_parameter('Set_loop',False)
        self.Set_loop = self.get_parameter('Set_loop').get_parameter_value().bool_value
        self.declare_parameter('ResponseDist',0.6)
        self.ResponseDist = self.get_parameter('ResponseDist').get_parameter_value().double_value
        self.declare_parameter('LaserAngle',20.0)
        self.LaserAngle = self.get_parameter('LaserAngle').get_parameter_value().double_value
        self.declare_parameter('Linear',0.2)
        self.Linear = self.get_parameter('Linear').get_parameter_value().double_value
        self.declare_parameter('Angular',0.9)
        self.Angular = self.get_parameter('Angular').get_parameter_value().double_value
        self.declare_parameter('Length',0.5)
        self.Length = self.get_parameter('Length').get_parameter_value().double_value
        self.declare_parameter('RotationTolerance',0.25)
        self.RotationTolerance = self.get_parameter('RotationTolerance').get_parameter_value().double_value
        self.declare_parameter('RotationScaling',1.0)
        self.RotationScaling = self.get_parameter('RotationScaling').get_parameter_value().double_value
        self.declare_parameter('LineTolerance',0.05)
        self.LineTolerance = self.get_parameter('LineTolerance').get_parameter_value().double_value
        self.declare_parameter('LineScaling',1.0)
        self.LineScaling = self.get_parameter('LineScaling').get_parameter_value().double_value
        
        
        #create a timer 定时器,每0.05秒调用on_timer
        self.timer = self.create_timer(0.05,self.on_timer)
        self.index = 0
        
        
    def on_timer(self):
        #print("self.error: ",self.error)
        self.Switch = self.get_parameter('Switch').get_parameter_value().bool_value
        self.Command = self.get_parameter('Command').get_parameter_value().string_value
        self.Set_loop = self.get_parameter('Set_loop').get_parameter_value().bool_value
        self.ResponseDist = self.get_parameter('ResponseDist').get_parameter_value().double_value
        self.Linear = self.get_parameter('Linear').get_parameter_value().double_value
        self.Angular = self.get_parameter('Angular').get_parameter_value().double_value
        self.Length = self.get_parameter('Length').get_parameter_value().double_value
        self.LaserAngle = self.get_parameter('LaserAngle').get_parameter_value().double_value
        self.RotationTolerance = self.get_parameter('RotationTolerance').get_parameter_value().double_value
        self.RotationScaling = self.get_parameter('RotationScaling').get_parameter_value().double_value
        self.LineTolerance = self.get_parameter('LineTolerance').get_parameter_value().double_value
        self.LineScaling = self.get_parameter('LineScaling').get_parameter_value().double_value
        self.circle_adjust = self.get_parameter('circle_adjust').get_parameter_value().double_value
        
        
        index = 0
        #self.position.x = self.get_position().transform.translation.x
        #self.position.y = self.get_position().transform.translation.y
        
        if self.Switch==True:
            #self.position.x = self.get_position().transform.translation.x
            #self.position.y = self.get_position().transform.translation.y     
            index = 0
            #print("Switch True")
            if self.Command == "LengthTest":
                self.command_src = "LengthTest"
                #print("LengthTest")
                advancing = self.advancing(self.Length)
                if advancing ==True:
                    self.pub_cmdVel.publish(Twist())
                    '''self.Switch  = rclpy.parameter.Parameter('Switch',rclpy.Parameter.Type.BOOL,False)
                    all_new_parameters = [self.Switch]
                    self.set_parameters(all_new_parameters)'''
                    '''self.Command  = rclpy.parameter.Parameter('Command',rclpy.Parameter.Type.STRING,"finish")
                    all_new_parameters = [self.Command]
                    self.set_parameters(all_new_parameters)'''
                    print("ok")

                    self.Switch  = rclpy.parameter.Parameter('Switch',rclpy.Parameter.Type.BOOL,False)
                    all_new_parameters = [self.Switch]
                    self.set_parameters(all_new_parameters)
                    #advancing = False
            
            elif self.Command == "Circle":
                self.command_src = "Circle"
                spin = self.Spin(360)
                if spin == True:
                    print("spin done")
                    #self.Command = "finish"
                    self.Switch  = rclpy.parameter.Parameter('Switch',rclpy.Parameter.Type.BOOL,False)
                    all_new_parameters = [self.Switch]
                    self.set_parameters(all_new_parameters)


            elif self.Command == "Square":
                self.command_src = "Square"
                square = self.Square()
                if square == True:
                    '''self.Command  = rclpy.parameter.Parameter('Command',rclpy.Parameter.Type.STRING,"finish")
                    all_new_parameters = [self.Command]
                    self.set_parameters(all_new_parameters)'''
                    self.Switch  = rclpy.parameter.Parameter('Switch',rclpy.Parameter.Type.BOOL,False)
                    all_new_parameters = [self.Switch]
                    self.set_parameters(all_new_parameters)
                    
            elif self.Command == "Triangle":
                self.command_src = "Triangle"
                triangle = self.Triangle()
                if triangle == True:
                    '''self.Command  = rclpy.parameter.Parameter('Command',rclpy.Parameter.Type.STRING,"finish")
                    all_new_parameters = [self.Command]
                    self.set_parameters(all_new_parameters)'''
                    self.Switch  = rclpy.parameter.Parameter('Switch',rclpy.Parameter.Type.BOOL,False)
                    all_new_parameters = [self.Switch]
                    self.set_parameters(all_new_parameters)
                    
        else:
            #self.position.x = self.get_position().transform.translation.x
            #self.position.y = self.get_position().transform.translation.y
            self.pub_cmdVel.publish(Twist())
            #print("Switch False")
            if self.Command == "finish":
                #print("finish")
                if self.Set_loop == True:
                    print("Continute")
                    self.Command  = rclpy.parameter.Parameter('Command',rclpy.Parameter.Type.STRING,self.command_src)
                    all_new_parameters = [self.Command]
                    self.set_parameters(all_new_parameters)
                    self.Switch  = rclpy.parameter.Parameter('Switch',rclpy.Parameter.Type.BOOL,True)
                    all_new_parameters = [self.Switch]
                    self.set_parameters(all_new_parameters)
                else:
                    #print("Not loop")
                    self.Switch  = rclpy.parameter.Parameter('Switch',rclpy.Parameter.Type.BOOL,False)
                    all_new_parameters = [self.Switch]
                    self.set_parameters(all_new_parameters)
                

                
    #走直线
    def advancing(self,target_distance):  
        #获取位置    
        self.position.x = self.get_position().transform.translation.x
        self.position.y = self.get_position().transform.translation.y
        '''print("self.x: ",self.position.x)
        print("self.y: ",self.position.y)
        print("x_start: ",self.x_start)
        print("y_start: ",self.y_start)'''
        move_cmd = Twist()#计算距离
        self.distance = sqrt(pow((self.position.x - self.x_start), 2) +
                            pow((self.position.y - self.y_start), 2))
        self.distance *= self.LineScaling#*线速度参数
        #print("distance: ",self.distance)
        self.error = self.distance - target_distance #误差计算
        #print("error: ",self.error)
        move_cmd.linear.x = self.Linear
        if abs(self.error) < self.LineTolerance : #到达目标位置
            print("stop")
            self.distance = 0.0
            self.error = 0.0
            #self.pub_cmdVel.publish(Twist())
            #self.x_start = self.position.x
            #self.y_start = self.position.y
            #print("x_start: ",self.x_start)
            #print("y_start: ",self.y_start)
            self.x_start = self.get_position().transform.translation.x;
            self.y_start = self.get_position().transform.translation.y;
            '''self.x_start = 0.0
            self.y_start = 0.0
            self.position.x = 0.0
            self.position.y = 0.0'''
            #print("x_start: ",self.x_start)
            #print("y_start: ",self.y_start)
            '''self.Switch  = rclpy.parameter.Parameter('Switch',rclpy.Parameter.Type.BOOL,False)
            all_new_parameters = [self.Switch]
            self.set_parameters(all_new_parameters)'''
            return True
        else:
            if self.Joy_active or self.warning > 10:#存在障碍物
                if self.moving == True:
                    self.pub_cmdVel.publish(Twist())
                    self.moving = False
                    b = UInt16()
                    b.data = 1
                    self.pub_Buzzer.publish(b)
                    print("obstacles")
            else:
                #print("Go")
                b = UInt16()
                b.data = 0
                self.pub_Buzzer.publish(UInt16())
                self.pub_cmdVel.publish(move_cmd)#继续前行
            self.moving = True
            return False

    #旋转    
    def Spin(self,angle):
        #self.position.x = self.get_position().transform.translation.x
        #self.position.y = self.get_position().transform.translation.y
        '''print("self.x: ",self.position.x)
        print("self.y: ",self.position.y)
        print("x_start: ",self.x_start)
        print("y_start: ",self.y_start)  ''' 
        #self.last_angle = self.get_odom_angle() 
    
        #角度转换为弧度
        self.target_angle = radians(angle)
        self.odom_angle = self.get_odom_angle()#调用get_odom_angle获取角度
        self.delta_angle = self.RotationScaling * self.normalize_angle(self.odom_angle - self.last_angle)
        self.turn_angle += self.delta_angle
        print("turn_angle: ",self.turn_angle)
        self.error =  self.target_angle - self.turn_angle #误差
        print("error: ",self.error)
        self.last_angle = self.odom_angle
        move_cmd = Twist()
        if abs(self.error) < self.RotationTolerance or self.Switch==False : #已经旋转到角度
            #self.pub_cmdVel.publish(Twist())
            self.turn_angle = 0.0
            self.last_angle = self.get_odom_angle()
            return True # 表示小车已经旋转到目标角度
        if self.Joy_active or self.warning > 10:#有障碍物,停下
            if self.moving == True:
                self.pub_cmdVel.publish(Twist()) 
                self.moving = False
                b = UInt16()
                b.data = 1
                self.pub_Buzzer.publish(b)
                
                print("obstacles")
        else:
            b = UInt16()
            b.data = 0
            self.pub_Buzzer.publish(UInt16())
            if self.Command == "Square" or self.Command == "Triangle": 
                #move_cmd.linear.x = 0.2
                #move_cmd.angular.z = copysign(self.Angular, self.error)
                length = self.Linear * self.circle_adjust / self.Length
                move_cmd.linear.x = self.Linear * 0.8
                #copysign(x,y)其中数值来自x,符号来自y.这里是符号与误差保持一致
                move_cmd.angular.z = copysign(length, self.error)
            elif self.Command == "Circle":
                length = self.Linear * self.circle_adjust / self.Length
                #print("length: ",length)
                move_cmd.linear.x = self.Linear
                move_cmd.angular.z = copysign(length, self.error)
                #print("angular: ",move_cmd.angular.z)
                '''move_cmd.linear.x = 0.2
                move_cmd.angular.z = copysign(2, self.error)'''
            self.pub_cmdVel.publish(move_cmd)
        self.moving = True
        
        #走长方形,分成了8步,就是走直线+90度旋转这样重复。
    def Square(self):
        if self.index == 0:
            print("Length")
            step1 = self.advancing(self.Length)
            #sleep(0.5)
            if step1 == True:
                #self.distance = 0.0
                self.index = self.index + 1;
                self.x_start = self.get_position().transform.translation.x;
                self.y_start = self.get_position().transform.translation.y;
                self.Switch  = rclpy.parameter.Parameter('Switch',rclpy.Parameter.Type.BOOL,True)
                all_new_parameters = [self.Switch]
                self.set_parameters(all_new_parameters)
                return False
        elif self.index == 1:
            print("Spin")
            step2 = self.Spin(90)
            #sleep(0.5)
            if step2 == True:
                self.index = self.index + 1;
                self.last_angle = self.get_odom_angle()
                self.x_start = self.get_position().transform.translation.x;
                self.y_start = self.get_position().transform.translation.y;
                print("x_start: ",self.x_start)
                print("y_start: ",self.y_start)
                print("last_angle: ",self.last_angle)
                '''self.Switch  = rclpy.parameter.Parameter('Switch',rclpy.Parameter.Type.BOOL,True)
                all_new_parameters = [self.Switch]
                self.set_parameters(all_new_parameters)'''
                self.pub_cmdVel.publish(Twist())
                return False
        elif self.index == 2:
            print("Length")
            step3 = self.advancing(self.Length)
            #sleep(0.5)
            if step3 == True:
                self.index = self.index + 1;
                self.last_angle = self.get_odom_angle()
                self.x_start = self.get_position().transform.translation.x;
                self.y_start = self.get_position().transform.translation.y;
                print("x_start: ",self.x_start)
                print("y_start: ",self.y_start)
                print("last_angle: ",self.last_angle)
                '''self.Switch  = rclpy.parameter.Parameter('Switch',rclpy.Parameter.Type.BOOL,True)
                all_new_parameters = [self.Switch]
                self.set_parameters(all_new_parameters)'''
                self.pub_cmdVel.publish(Twist())
                return False          
        elif self.index == 3:
            print("Spin")
            step4 = self.Spin(90)
            #sleep(0.5)
            if step4 == True:
                self.index = self.index + 1;
                self.last_angle = self.get_odom_angle()
                self.x_start = self.get_position().transform.translation.x;
                self.y_start = self.get_position().transform.translation.y;
                print("x_start: ",self.x_start)
                print("y_start: ",self.y_start)
                print("last_angle: ",self.last_angle)
                '''self.Switch  = rclpy.parameter.Parameter('Switch',rclpy.Parameter.Type.BOOL,True)
                all_new_parameters = [self.Switch]
                self.set_parameters(all_new_parameters)'''
                self.pub_cmdVel.publish(Twist())
                return False
        elif self.index == 4:
            print("Length")
            step5 = self.advancing(self.Length)
            #sleep(0.5)
            if step5 == True:
                self.index = self.index + 1;
                self.last_angle = self.get_odom_angle()
                self.x_start = self.get_position().transform.translation.x;
                self.y_start = self.get_position().transform.translation.y;
                print("x_start: ",self.x_start)
                print("y_start: ",self.y_start)
                print("last_angle: ",self.last_angle)
                '''self.Switch  = rclpy.parameter.Parameter('Switch',rclpy.Parameter.Type.BOOL,True)
                all_new_parameters = [self.Switch]
                self.set_parameters(all_new_parameters)'''
                self.pub_cmdVel.publish(Twist())
                return False
        elif self.index == 5:
            print("Spin")
            step6 = self.Spin(90)
            #sleep(0.5)
            if step6 == True:
                self.index = self.index + 1;
                self.last_angle = self.get_odom_angle()
                self.x_start = self.get_position().transform.translation.x;
                self.y_start = self.get_position().transform.translation.y;
                print("x_start: ",self.x_start)
                print("y_start: ",self.y_start)
                print("last_angle: ",self.last_angle)
                '''self.Switch  = rclpy.parameter.Parameter('Switch',rclpy.Parameter.Type.BOOL,True)
                all_new_parameters = [self.Switch]
                self.set_parameters(all_new_parameters)'''
                self.pub_cmdVel.publish(Twist())
                return False
        elif self.index == 6:
            print("Length")
            step7 = self.advancing(self.Length)
            #sleep(0.5)
            if step7 == True:
                self.index = self.index + 1;
                self.x_start = self.get_position().transform.translation.x;
                self.y_start = self.get_position().transform.translation.y;
                self.last_angle = self.get_odom_angle()
                print("x_start: ",self.x_start)
                print("y_start: ",self.y_start)
                print("last_angle: ",self.last_angle)
                '''self.Switch  = rclpy.parameter.Parameter('Switch',rclpy.Parameter.Type.BOOL,True)
                all_new_parameters = [self.Switch]
                self.set_parameters(all_new_parameters)'''
                self.pub_cmdVel.publish(Twist())
                return False
        elif self.index == 7:
            print("Spin")
            step8 = self.Spin(90)
            #sleep(0.5)
            if step8 == True:
                self.index = self.index + 1;
                self.last_angle = self.get_odom_angle()
                self.x_start = self.get_position().transform.translation.x;
                self.y_start = self.get_position().transform.translation.y;
                print("x_start: ",self.x_start)
                print("y_start: ",self.y_start)
                print("last_angle: ",self.last_angle)
                '''self.Switch  = rclpy.parameter.Parameter('Switch',rclpy.Parameter.Type.BOOL,True)
                all_new_parameters = [self.Switch]
                self.set_parameters(all_new_parameters)'''
                self.pub_cmdVel.publish(Twist())
                return False
        elif self.index == 8:
            self.index = 0
            self.Switch  = rclpy.parameter.Parameter('Switch',rclpy.Parameter.Type.BOOL,False)
            all_new_parameters = [self.Switch]
            self.set_parameters(all_new_parameters)
            #self.Command == "finish"
            print("Done!")
            self.x_start = self.get_position().transform.translation.x;
            self.y_start = self.get_position().transform.translation.y;
            self.last_angle = self.get_odom_angle()
            return True
             
        
      #三角形,分成走直线+旋转120度,5步      
    def Triangle(self):
        if self.index == 0:
            print("Length")
            step1 = self.advancing(self.Length)
            #sleep(0.5)
            if step1 == True:
                #self.distance = 0.0
                self.index = self.index + 1; 
                self.x_start = self.get_position().transform.translation.x;
                self.y_start = self.get_position().transform.translation.y;
                print("x_start: ",self.x_start)
                print("y_start: ",self.y_start)
                #print("last_angle: ",self.last_angle)
                return False
        elif self.index == 1:
            print("Spin")
            step2 = self.Spin(120)
            #sleep(0.5)
            if step2 == True:
                self.index = self.index + 1;
                self.x_start = self.get_position().transform.translation.x;
                self.y_start = self.get_position().transform.translation.y;
                self.last_angle = self.get_odom_angle()
                print("x_start: ",self.x_start)
                print("y_start: ",self.y_start)
                print("last_angle: ",self.last_angle)
                return False
        elif self.index == 2:
            print("Length")
            step1 = self.advancing(self.Length)
            #sleep(0.5)
            if step1 == True:
                self.index = self.index + 1;
                self.x_start = self.get_position().transform.translation.x;
                self.y_start = self.get_position().transform.translation.y;
                self.last_angle = self.get_odom_angle()
                print("x_start: ",self.x_start)
                print("y_start: ",self.y_start)
                print("last_angle: ",self.last_angle)
                return False
        elif self.index == 3:
            print("Spin")
            step4 = self.Spin(120)
            #sleep(0.5)
            if step4 == True:
                self.index = self.index + 1;
                self.x_start = self.get_position().transform.translation.x;
                self.y_start = self.get_position().transform.translation.y;
                self.last_angle = self.get_odom_angle()
                print("x_start: ",self.x_start)
                print("y_start: ",self.y_start)
                print("last_angle: ",self.last_angle)
                return False
        elif self.index == 4:
            print("Length")
            step5 = self.advancing(self.Length)
            #sleep(0.5)
            if step5 == True:
                #self.distance = 0.0
                self.index = self.index + 1; 
                self.x_start = self.get_position().transform.translation.x;
                self.y_start = self.get_position().transform.translation.y;
                self.last_angle = self.get_odom_angle()
                print("x_start: ",self.x_start)
                print("y_start: ",self.y_start)
                print("last_angle: ",self.last_angle)
                return False
                
        elif self.index == 5:
            print("Spin")
            step6 = self.Spin(120)
            #sleep(0.5)
            if step6 == True:
                self.index = self.index + 1;
                self.x_start = self.get_position().transform.translation.x;
                self.y_start = self.get_position().transform.translation.y;
                self.last_angle = self.get_odom_angle()
                print("x_start: ",self.x_start)
                print("y_start: ",self.y_start)
                print("last_angle: ",self.last_angle)
                return False
        else:
            self.index = 0
            self.Switch  = rclpy.parameter.Parameter('Switch',rclpy.Parameter.Type.BOOL,False)
            all_new_parameters = [self.Switch]
            self.set_parameters(all_new_parameters)
            print("Done!")
            return True
            
            
    #旋转角度
    def get_odom_angle(self):
         try:
            now = rclpy.time.Time()
            #使用TF2 lookup_transform获取小车的角度信息
            rot = self.tf_buffer.lookup_transform(self.odom_frame,self.base_frame,now)   
            #print("oring_rot: ",rot.transform.rotation) 
            #四元组转为Quaternion
            cacl_rot = PyKDL.Rotation.Quaternion(rot.transform.rotation.x, rot.transform.rotation.y, rot.transform.rotation.z, rot.transform.rotation.w)
            #print("cacl_rot: ",cacl_rot)
            angle_rot = cacl_rot.GetRPY()[2]
            return angle_rot
            
            
            
    
         except (LookupException, ConnectivityException, ExtrapolationException):
            self.get_logger().info('transform not ready')
            raise
            return
        
               
        
     #获取xy坐标   
    def get_position(self):
        try:
            now = rclpy.time.Time()
            trans = self.tf_buffer.lookup_transform(self.odom_frame,self.base_frame,now)
            return trans
        except (LookupException, ConnectivityException, ExtrapolationException):
            self.get_logger().info('transform not ready')
            raise
            return
    #角度规范化, 目的使角度值规范化到[-π, π]范围内
    def normalize_angle(self,angle):
        res = angle
        #print("res: ",res)
        while res > pi:
            res -= 2.0 * pi
        while res < -pi:
            res += 2.0 * pi
        return res
    #退出停止指令    
    def exit_pro(self):
        cmd1 = "ros2 topic pub --once /cmd_vel geometry_msgs/msg/Twist "
        cmd2 = '''"{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"'''
        cmd = cmd1 +cmd2
        os.system(cmd)
        cmd3 = "ros2 topic pub --once /beep std_msgs/msg/UInt16 "
        cmd4 = '''"data: 0"'''
        cmd = cmd1 +cmd2
        os.system(cmd)
    #激光雷达回调
    def LaserScanCallback(self,scan_data):
        if self.ResponseDist == 0: return
        ranges = np.array(scan_data.ranges)
        sortedIndices = np.argsort(ranges)
        self.warning = 1
        for i in range(len(ranges)):
            angle = (scan_data.angle_min + scan_data.angle_increment * i) * RAD2DEG
            if angle > 180: angle = angle - 360
            if ranges[i] < self.ResponseDist and abs(angle) < self.LaserAngle:
                if ranges[i] < self.ResponseDist: self.warning += 1
    #手柄回调
    def JoyStateCallback(self, msg):
        if not isinstance(msg, Bool): return
        self.Joy_active = msg.data
        #print(msg.data)
        #if not self.Joy_active: self.pub_cmdVel.publish(Twist())     
    
def main():
    rclpy.init()
    class_patrol = YahboomCarPatrol("YahboomCarPatrol")
    print("create done")
    try:
        rclpy.spin(class_patrol)
    except KeyboardInterrupt:
        pass
    finally:
        class_patrol.exit_pro()
        class_patrol.pub_cmdVel.publish(Twist())
        rclpy.shutdown()


感觉这是这一系列代码最长的一次,主要的函数是直线advancing和旋转Spin,其他的命令就是使用组合,我尽量加了注释。

运行

启动代理。启动坐标变换

ros2 run yahboomcar_base_node base_node_X3

启动巡逻:

 ros2 run yahboomcar_bringup patrol

此时小车开关关闭,小车不动

打开参数调节器,给定巡逻路线,终端输入,

ros2 run rqt_reconfigure rqt_reconfigure

rqt界面其它参数说明如下:

  • odom_frame:里程计的坐标系名称

  • base_frame:基坐标系的名称

  • circle_adjust:巡逻路线为圆形时,该值可以作为调整圆大小的系数,详细见代码

  • Switch:玩法开关

  • Command:巡逻路线,有以下几种路线:【LengthTest】-直线巡逻、【Circle】-圆圈巡逻、【Square】-正方形巡逻、【Triangle】-三角形巡逻。

  • Set_loop:重新巡逻的开发,设置后将会更具设定的路线继续循环巡逻下去

  • ResponseDist:障碍物检测的距离

  • LaserAngle:雷达检测的角度

  • Linear:线速度大小

  • Angular:角速度大小

  • Length:直线运动的距离

  • RotationTolerance:旋转误差允许的容忍值

  • RotationScaling:旋转的比例系数

运行日志:

Length
Length
Length
Length
Length
Length
Length
Length
Length
Length
Length
stop
x_start:  0.5807050466537476
y_start:  -0.4547373950481415
Spin
turn_angle:  0.12999536812928347
error:  1.9643997342639117
Spin
turn_angle:  0.1270322899494371
error:  1.967362812443758
Spin
turn_angle:  0.1270322899494371
error:  1.967362812443758
Spin
turn_angle:  0.13289548931121825
error:  1.961499613081977
Spin
turn_angle:  0.13831713700843054
error:  1.9560779653847646
Spin
turn_angle:  0.13831713700843054
error:  1.9560779653847646
Spin
turn_angle:  0.16882994269260154
error:  1.9255651597005938
Spin
turn_angle:  0.16882994269260154
error:  1.9255651597005938
Spin

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/962032.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C++并发编程指南06

文章目录 4.4 简化代码与同步工具同步工具作为构建块 4.4.1 使用Future的函数化编程函数化编程简介C支持函数化编程 快速排序 - FP模式快速排序串行版快速排序并行版 spawn_task函数结论快速排序 - 串行版快速排序 - 并行版spawn_task函数使用 spawn_task 实现并行快速排序详细…

ios swift画中画技术尝试

继上篇&#xff1a;iOS swift 后台运行应用尝试失败-CSDN博客 为什么想到画中画&#xff0c;起初是看到后台模式里有一个picture in picture&#xff0c;去了解了后发现这个就是小窗口视频播放&#xff0c;方便用户执行多任务。看小窗口视频的同时&#xff0c;可以作其他的事情…

C++,STL 六大组件:容器、迭代器、算法、函数对象、适配器、分配器

文章目录 引言一、容器&#xff08;Containers&#xff09;主要分类 二、迭代器&#xff08;Iterators&#xff09;三、算法&#xff08;Algorithms&#xff09;四、函数对象&#xff08;Functors&#xff09;五、适配器&#xff08;Adapters&#xff09;六、分配器&#xff08…

STM32项目分享:智能鱼缸

目录 一、前言 二、项目简介 1.功能详解 2.主要器件 三、原理图设计 四、PCB硬件设计 PCB图 五、程序设计 六、实验效果 七、包含内容 项目分享 一、前言 项目成品图片&#xff1a; 哔哩哔哩视频链接&#xff1a; STM32智能鱼缸/水族箱 &#xff08;资料分享见文末…

基于MinIO的对象存储增删改查

MinIO是一个高性能的分布式对象存储服务。Python的minio库可操作MinIO&#xff0c;包括创建/列出存储桶、上传/下载/删除文件及列出文件。 查看帮助信息 minio.exe --help minio.exe server --help …

14-6-1C++STL的list

(一&#xff09;list容器的基本概念 list容器简介&#xff1a; 1.list是一个双向链表容器&#xff0c;可高效地进行插入删除元素 2.list不可以随机存取元素&#xff0c;所以不支持at.(pos)函数与[ ]操作符 &#xff08;二&#xff09;list容器头部和尾部的操作 list对象的默…

汽车网络信息安全-ISO/SAE 21434解析(中)

目录 第七章-分布式网络安全活动 1. 供应商能力评估 2. 报价 3. 网络安全职责界定 第八章-持续的网络安全活动 1. 网路安全监控 2. 网络安全事件评估 3. 漏洞分析 4. 漏洞管理 第九章-概念阶段 1. 对象定义 2. 网路安全目标 3. 网络安全概念 第十章 - 产品开发 第十…

C#分页思路:双列表数据组合返回设计思路

一、应用场景 需要分页查询&#xff08;并非全表查载入物理内存再筛选&#xff09;&#xff0c;返回列表1和列表2叠加的数据时 二、实现方式 列表1必查&#xff0c;列表2根据列表1的查询结果决定列表2的分页查询参数 三、示意图及其实现代码 1.示意图 黄色代表list1的数据&a…

YOLOv8源码修改(4)- 实现YOLOv8模型剪枝(任意YOLO模型的简单剪枝)

目录 前言 1. 需修改的源码文件 1.1添加C2f_v2模块 1.2 修改模型读取方式 1.3 增加 L1 正则约束化训练 1.4 在tensorboard上增加BN层权重和偏置参数分布的可视化 1.5 增加剪枝处理文件 2. 工程目录结构 3. 源码文件修改 3.1 添加C2f_v2模块和模型读取 3.2 添加L1正则…

【Block总结】DynamicFilter,动态滤波器降低计算复杂度,替换传统的MHSA|即插即用

论文信息 标题: FFT-based Dynamic Token Mixer for Vision 论文链接: https://arxiv.org/pdf/2303.03932 关键词: 深度学习、计算机视觉、对象检测、分割 GitHub链接: https://github.com/okojoalg/dfformer 创新点 本论文提出了一种新的标记混合器&#xff08;token mix…

设计模式Python版 原型模式

文章目录 前言一、原型模式二、原型模式示例三、原型管理器 前言 GOF设计模式分三大类&#xff1a; 创建型模式&#xff1a;关注对象的创建过程&#xff0c;包括单例模式、简单工厂模式、工厂方法模式、抽象工厂模式、原型模式和建造者模式。结构型模式&#xff1a;关注类和对…

一文讲解Java中的BIO、NIO、AIO之间的区别

BIO、NIO、AIO是Java中常见的三种IO模型 BIO&#xff1a;采用阻塞式I/O模型&#xff0c;线程在执行I/O操作时被阻塞&#xff0c;无法处理其他任务&#xff0c;适用于连接数比较少的场景&#xff1b;NIO&#xff1a;采用非阻塞 I/O 模型&#xff0c;线程在等待 I/O 时可执行其…

使用 postman 测试思源笔记接口

思源笔记 API 权鉴 官方文档-中文&#xff1a;https://github.com/siyuan-note/siyuan/blob/master/API_zh_CN.md 权鉴相关介绍截图&#xff1a; 对应的xxx&#xff0c;在软件中查看 如上图&#xff1a;在每次发送 API 请求时&#xff0c;需要在 Header 中添加 以下键值对&a…

AWTK 骨骼动画控件发布

Spine 是一款广泛使用的 2D 骨骼动画工具&#xff0c;专为游戏开发和动态图形设计设计。它通过基于骨骼的动画系统&#xff0c;帮助开发者创建流畅、高效的角色动画。本项目是基于 Spine 实现的 AWTK 骨骼动画控件。 代码&#xff1a;https://gitee.com/zlgopen/awtk-widget-s…

新年手搓--本地化部署DeepSeek-R1,全程实测

1.环境准备安装ollma ollma官网链接: Download Ollama on Linux ubuntu命令行安装: curl -fsSL https://ollama.com/install.sh | sh 选择运行模型,用7b模型试一下(模型也差不多5G): ollama run deepseek-r1:7b 运行qwen: ollama run qwen2.5:7b 2.为方便运行…

STM32使用VScode开发

文章目录 Makefile形式创建项目新建stm项目下载stm32cubemx新建项目IED makefile保存到本地arm gcc是编译的工具链G++配置编译Cmake +vscode +MSYS2方式bilibiliMSYS2 统一环境配置mingw32-make -> makewindows环境变量Cmake CmakeListnijia 编译输出elfCMAKE_GENERATOR查询…

【Numpy核心编程攻略:Python数据处理、分析详解与科学计算】1.21 索引宗师:布尔索引的七重境界

1.21 索引宗师&#xff1a;布尔索引的七重境界 目录 #mermaid-svg-Iojpgw5hl0Ptb9Ti {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-Iojpgw5hl0Ptb9Ti .error-icon{fill:#552222;}#mermaid-svg-Iojpgw5hl0Ptb9Ti .…

毕业设计--具有车流量检测功能的智能交通灯设计

摘要&#xff1a; 随着21世纪机动车保有量的持续增加&#xff0c;城市交通拥堵已成为一个日益严重的问题。传统的固定绿灯时长方案导致了大量的时间浪费和交通拥堵。为解决这一问题&#xff0c;本文设计了一款智能交通灯系统&#xff0c;利用车流量检测功能和先进的算法实现了…

课题推荐:基于matlab,适用于自适应粒子滤波的应用

自适应粒子滤波&#xff08;Adaptive Particle Filter, APF&#xff09;是一种用于状态估计的有效方法&#xff0c;特别适用于非线性和非高斯系统。 文章目录 应用场景MATLAB 代码示例代码说明结果扩展说明 以下是一个基于自适应粒子滤波的简单应用示例&#xff0c;模拟一个一维…

Redis(5,jedis和spring)

在前面的学习中&#xff0c;只是学习了各种redis的操作&#xff0c;都是在redis命令行客户端操作的&#xff0c;手动执行的&#xff0c;更多的时候就是使用redis的api&#xff08;&#xff09;&#xff0c;进一步操作redis程序。 在java中实现的redis客户端有很多&#xff0c;…