rospy 控制小车定点旋转侦察

rospy 控制小车定点旋转侦察

场景:控制小车到达一个指定位置附近后,开始旋转侦察

#!/usr/bin/env python
#coding=utf-8
import PyKDL
import rospy
import actionlib
from actionlib_msgs.msg import *
from move_base_msgs.msg import MoveBaseAction, MoveBaseGoal
from nav_msgs.msg import Path
from geometry_msgs.msg import PoseWithCovarianceStamped,Twist, Point, Quaternion
import tf
from tf_conversions import transformations
from math import radians, copysign, sqrt, pow, pi
import time
from mux.srv import ControlState


class Navigation_around:
    def __init__(self, robot_name="robot1", nearest_r=2, wait_time=600):
        self.robot_name = robot_name
        self.nearest_r = nearest_r
        self.wait_time = wait_time
        self.move_base = actionlib.SimpleActionClient(str(self.robot_name)+"/move_base", MoveBaseAction)
        self.move_base.wait_for_server(rospy.Duration(60))
        rospy.on_shutdown(self.shutdown)
    
    # robot当前位置
    def get_amcl_pose(self):
        msg = rospy.wait_for_message(str(self.robot_name)+"/amcl_pose",PoseWithCovarianceStamped,timeout=None)
        return msg.pose.pose.position, self.quat_to_angle(msg.pose.pose.orientation)

    def _done_cb(self, status, result):
        rospy.loginfo("navigation done! status:%d result:%s"%(status, result))

    def _active_cb(self):
        rospy.loginfo("[Navi] navigation has be actived")

    def _feedback_cb(self, feedback):
        rospy.loginfo("[Navi] navigation feedback\r\n%s"%feedback)

    # 当前位置与目标位置距离  
    def stop_pose_distance(self,pose):
        (position, rotation) = self.get_amcl_pose()
        return sqrt(pow((position.x - pose[0]), 2) + pow((position.y - pose[1]), 2))
    
    # 四位数转欧拉角
    def quat_to_angle(self,quat):
        rot = PyKDL.Rotation.Quaternion(quat.x, quat.y, quat.z, quat.w)
        return rot.GetRPY()[2]
    # 退出关闭
    def shutdown(self):
        rospy.loginfo("Stopping the robot....")
        self.control_client(3,0)
        self.move_base.cancel_goal()
        rospy.sleep(1)

    # 资源的请求与释放 请求返回True False
    def control_client(self, permission, state):
        rospy.wait_for_service(str(self.robot_name)+"/control_server")
        try:
            control_client = rospy.ServiceProxy(str(self.robot_name)+"/control_server", ControlState)
            response = control_client(permission, state)
            return response.control
        except:
            return False

     # 打印启动位置与目标位置
    def print_point(self, pose):
        position = self.get_amcl_pose()[0]
        rospy.loginfo("Start pose: x:%s y:%s    ---------->    Stop pose: x:%s y:%s", position.x, position.y, pose[0], pose[1])

    # 到达指定点
    def get_to(self, pose):
        rospy.loginfo("[Navi] goto %s",pose)
        goal = MoveBaseGoal()
        goal.target_pose.header.frame_id = 'map'
        goal.target_pose.header.stamp = rospy.Time.now()
        goal.target_pose.pose.position.x = pose[0]
        goal.target_pose.pose.position.y = pose[1]
        q = transformations.quaternion_from_euler(0.0, 0.0, pose[2]/180.0*pi)
        goal.target_pose.pose.orientation.x = q[0]
        goal.target_pose.pose.orientation.y = q[1]
        goal.target_pose.pose.orientation.z = q[2]
        goal.target_pose.pose.orientation.w = q[3]

        # 向控制发送 优先级:3 | 请求资源:1(1请求资源,0释放资源)
        if self.control_client(3,1):
            # 休眠两秒等待资源释放
            rospy.sleep(2)

            # 发送打印启动--->目标
            self.print_point(pose)
            self.move_base.send_goal(goal, self._done_cb, self._active_cb, self._feedback_cb)

            # 记录启动时间
            start = time.time()

            # 设定检测频率:检测是否到达目标附近频率、检测是否超时频率、检测是否资源被优先级高抢占频率
            rate = rospy.Rate(1)
            while True:
                if rospy.is_shutdown():
                    rospy.loginfo("Ros is shutdown!")
                    # 取消目标请求
                    self.move_base.cancel_goal()
                    # 释放资源
                    self.control_client(3,0)
                    return False
                elif float(self.stop_pose_distance(pose)) < float(self.nearest_r):
                    rospy.loginfo("The robot reaches the nearest constraint")
                    # 取消目标请求
                    self.move_base.cancel_goal()
                    # 释放资源
                    self.control_client(3,0)
                    return True

                elif int(time.time()-start) > int(self.wait_time):
                    rospy.loginfo("Time out")
                    # 取消目标请求
                    self.move_base.cancel_goal()
                    # 释放资源
                    self.control_client(3,0)

                    return False

                elif self.control_client(3,1) == False:
                    ros.loginfo("Resource occupied")
                    # 取消目标请求
                    self.move_base.cancel_goal()
                    # 释放资源
                    self.control_client(3,0)

                    return False
                rate.sleep()
        else:
            rospy.loginfo("Resource request failed")
            rospy.loginfo("Current location \n <------------> \n %s",pose)
            return False
            
    
class OutAndBack():
    def __init__(self,robot_name="robot1", rotation_angle=360, pause_angle=30, angular_speed=0.2, slip_offset=5, pause_time=2):
        '''
        robot_name: 
        rotation_angle: 旋转角度默认360
        pause_angle: 停顿角度默认30
        angular_speed :默认角速度0.3
        pause_time: 停顿时间默认2
        '''
        self.robot_name = robot_name
        self.rotation_angle = radians(rotation_angle)
        self.pause_angle = radians(pause_angle)
        self.angular_speed = angular_speed
        self.slip_offset = radians(slip_offset)
        self.pause_time = pause_time
        
        # 移动指令订阅
        self.mobile_base_velocity = rospy.Publisher(str(self.robot_name)+'/mobile_base/commands/velocity', Twist, queue_size=1)
        # 关闭时执行
        rospy.on_shutdown(self.shutdown)
        rate = rospy.Rate(10)
        rospy.sleep(2)
        

        self.empty_cmd()
        rospy.sleep(1)
        for i in range(int(self.rotation_angle/self.pause_angle)):

            # 旋转操作设置 角速度
            move_cmd = Twist()
            move_cmd.angular.z = self.angular_speed

            # 记录当前位置
            (position, rotation) = self.get_amcl_pose()
            # 检查旋转是否到达停顿角 | 是否关闭
            while True:
                if abs(self.normalize_angle(rotation - self.get_amcl_pose()[1]))+self.slip_offset >= abs(self.pause_angle):
                    rospy.loginfo("Around degrees %s",self.pause_angle*(i+1)*180/3.14)
                    self.empty_cmd()
                    break
                elif rospy.is_shutdown():
                    rospy.loginfo("Ros is shutdown !")
                    break
                self.mobile_base_velocity.publish(move_cmd)
                rate.sleep()
            
            # 清空cmd 停顿等待
            self.empty_cmd()
            rospy.sleep(self.pause_time)
        
    
    # 清空指令控制 | 感觉休息会好点
    def empty_cmd(self):
        rospy.sleep(0.5)
        self.mobile_base_velocity.publish(Twist())
        rospy.sleep(0.5)

    # 获取当前位置
    def get_amcl_pose(self):
        msg = rospy.wait_for_message(str(self.robot_name)+"/amcl_pose",PoseWithCovarianceStamped,timeout=None)
        return msg.pose.pose.position, self.quat_to_angle(msg.pose.pose.orientation)
    
    # 关闭时处理
    def shutdown(self):
        # Always stop the robot when shutting down the node.
        rospy.loginfo("Stopping the robot...")
        self.mobile_base_velocity.publish(Twist())
        rospy.sleep(1)

    # 四位数转欧拉角
    def quat_to_angle(self,quat):
        rot = PyKDL.Rotation.Quaternion(quat.x, quat.y, quat.z, quat.w)
        return rot.GetRPY()[2]
    
    # 表示角度转换[-pi,pi]
    def normalize_angle(self,angle):
        res = angle
        while res > pi:
            res -= 2.0*pi
        while res < -pi:
            res += 2.0*pi
        return res

if __name__ == "__main__":

    robot_id = rospy.get_param('~robot_num','3')
    robot_name = 'robot'+ str(robot_id)
    rospy.init_node('Navigation_around',anonymous=True)
    pose = [3.0,3.0,90.0]

    try:
        navi = Navigation_around(robot_name=robot_name, nearest_r=2, wait_time=600)
        if navi.get_to(pose):
            OutAndBack(robot_name=robot_name, rotation_angle=360, pause_angle=60, angular_speed=0.2, pause_time=2)
            rospy.loginfo("OK")
        else:
            rospy.loginfo("Get to fail")
    except:
        rospy.loginfo("Get to fail.")

注意

在控制旋转时,旋转速度过快根据硬件情况会出现一定偏差

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值