当前位置: 首页 > news >正文

机器人精确移动包

move_near

之前有写过, 将ROS官方的move_basic包改写成了python形式, 同时将它写成了一个完整的action接口

最近测试时发现了问题, odom的数据波动可能会导致机器人陷入正反馈从而一直移动

具体表现为:

  1. 机器人移动精度设置为0.005 [m]

  2. 机器人在移动到接近0.005的位置, odom发生微小的跳变

    本来distRemaining应该是从 1 降到 0.5, 降到 0.006, 然后小于0.005, 机器人停住, 但是里程计波动, 使得distRemaining变成-0.006, 此时机器人还要继续后退, 就会导致distRemaining持续增大, 机器人无法停止

修改

​ 将计算机器人移动距离的distRemaining修改为累加制, 通过odom的逐差来减小odom的累进误差

结果

​ 机器人移动精度可以达到0.0005 [m], 甚至还能降, 但是已经超出了需求, 如果odom更好, 应该能达到更好的效果

调用

# 填充需要前往的位置, 在本例中使用的是base_link, 让机器人相对自身运动
$ rostopic pub /move_near/goal move_base_msgs/MoveBaseActionGoal 

注意事项

​ 在机器人移动过程中没有避障! 没有避障! 这不是move_base的接口! 不会调用costmap, 无避障操作!

#! /usr/bin/env python3import rospy
import actionlib
from sensor_msgs.msg import Imu
from nav_msgs.msg import Odometry
from geometry_msgs.msg import Pose, Twist, PoseStamped
from move_base_msgs.msg import MoveBaseAction, MoveBaseGoalimport math
import tf2_ros
from tf.transformations import euler_from_quaternion, quaternion_from_eulerclass MoveNear(object):def __init__(self, name):self.now_imu = Imu()self.now_odom = Odometry()self.current_goal = PoseStamped()rospy.Subscriber("/imu", Imu, self.imu_cb)rospy.Subscriber("/odom", Odometry, self.odom_cb)self.cmd_pub = rospy.Publisher('/cmd_vel', Twist, queue_size=5)self.current_goal_pub = rospy.Publisher('current_goal', PoseStamped, queue_size=1)self.minAngularVelocity = rospy.get_param("~min_angular_velocity",0.02)self.maxAngularVelocity = rospy.get_param("~max_angular_velocity",0.2)self.angularAcceleration = rospy.get_param("~angular_acceleration",0.2)self.angularTolerance = rospy.get_param("~angularTolerance",0.01)self.minSpeedDistance = rospy.get_param("~minSpeedDistance", 0.03)self.minLinearVelocity = rospy.get_param("~min_linear_velocity",0.01)self.maxLinearVelocity = rospy.get_param("~max_linear_velocity",0.2)self.linearAcceleration = rospy.get_param("~linear_acceleration",0.2)self.linearTolerance = rospy.get_param("~linearTolerance",0.0005)self.minSpeedDistance = rospy.get_param("~minSpeedDistance",0.05)self._action_name = "move_near"self._as = actionlib.SimpleActionServer(self._action_name, MoveBaseAction, execute_cb=self.execute_cb, auto_start = False)self._as.start()self.initialPose = {'x':0.0, 'y':0.0, 'yaw':0.0}self.goalPose = {'x':0.0, 'y':0.0, 'yaw':0.0}self.oscillation = 0self.prevAngleRemaining = 0def imu_cb(self, msg):self.now_imu = msgdef odom_cb(self, msg):self.now_odom = msgdef normalizeAngle(self,angle):if angle < -math.pi:angle += 2* math.piif angle > math.pi:angle -= 2*math.pireturn angledef rad2deg(self,rad):return rad * 180 / math.pidef sign(self,n):if n < 0:return -1else:return 1def getCurrentYaw(self):orientation_list = [self.now_imu.orientation.x,self.now_imu.orientation.y,self.now_imu.orientation.z,self.now_imu.orientation.w](_,_,current_yaw) = euler_from_quaternion(orientation_list)return current_yawdef rotate(self,yaw):rospy.loginfo("Requested rotation: {} degrees".format(self.rad2deg(yaw)))r = rospy.Rate(20)initial_yaw = self.getCurrentYaw()done = Falsewhile(not done and not rospy.is_shutdown()):rotated_yaw = self.getCurrentYaw() - initial_yawangleRemaining = yaw - rotated_yawangleRemaining = self.normalizeAngle(angleRemaining)rospy.logdebug("angleRemaining: {} degrees".format(self.rad2deg(angleRemaining)))vel = Twist()speed = max(self.minAngularVelocity,min(self.maxAngularVelocity,math.sqrt(max(2.0 * self.angularAcceleration *(abs(angleRemaining) - self.angularTolerance),0))))if angleRemaining < 0:vel.angular.z = -speedelse:vel.angular.z = speedif (abs(angleRemaining) < self.angularTolerance):vel.angular.z = 0done = Truer.sleep()rotated_yaw = self.getCurrentYaw() - initial_yawangleRemaining = yaw - rotated_yawrospy.loginfo("Rotate finished! error: {} degrees".format(self.rad2deg(angleRemaining)))self.cmd_pub.publish(vel)r.sleep()return Truedef moveLinear(self,dist):done = Falser = rospy.Rate(20)initial_odom = self.now_odomdistRemaining = distwhile(not done and not rospy.is_shutdown()):travelledDist = math.hypot(self.now_odom.pose.pose.position.x - initial_odom.pose.pose.position.x,self.now_odom.pose.pose.position.y - initial_odom.pose.pose.position.y)# 保持了之前的命名, 在这里更新odom的值initial_odom = self.now_odomrospy.logdebug("travelledDist: {}".format(travelledDist))# for speed direction judgementif dist <= 0:distRemaining += travelledDistdist += travelledDistelse:distRemaining -= travelledDistdist -= travelledDistrospy.logdebug("distRemaining: {}".format(distRemaining))vel = Twist()speed = max(self.minLinearVelocity, min(self.maxLinearVelocity, 2.5* abs(distRemaining)))if abs(distRemaining) < self.linearTolerance:speed = 0done = Truerospy.loginfo("Linear movement finished! error: {} meters".format(distRemaining))rospy.loginfo("finished, breaking!")break# 在即将到达目的地时用最小速度跑, 提高精度if abs(distRemaining) < self.minSpeedDistance:rospy.loginfo_once("disRemaining is less than minSpeedDistance, slow down!")speed = self.minLinearVelocity# 这里可以控制机器人即使移动超过了距离, 则将速度反向# 避免之前移动越界导致的正反馈, 避免越走离目的地越远的行为if distRemaining < 0 :speed = -speedvel.linear.x = speedtry:self.cmd_pub.publish(vel)except Exception as e:rospy.logerr("Error while publishing: {}".format(e))r.sleep()return Truedef execute_cb(self, goal):success = Truebehind = Falseself.current_goal_pub.publish(goal.target_pose)orientation_list = [goal.target_pose.pose.orientation.x,goal.target_pose.pose.orientation.y,goal.target_pose.pose.orientation.z,goal.target_pose.pose.orientation.w](_,_,self.goalPose['yaw']) = euler_from_quaternion (orientation_list)face2goalYaw = math.atan2(goal.target_pose.pose.position.y, goal.target_pose.pose.position.x)# Check if the goal is behind the robotif face2goalYaw > math.pi/2 or face2goalYaw < -math.pi/2:behind = Trueface2goalYaw = self.normalizeAngle(face2goalYaw + math.pi)# face2goalYaw = self.normalizeAngle(face2goalYaw)# face to goalif self.rotate(face2goalYaw):passelse:rospy.logwarn("Trun to goal failed!")# Move to goaldist2goal = math.hypot(goal.target_pose.pose.position.x, goal.target_pose.pose.position.y)# if the goal is behind the robot, move backwardif behind:dist2goal = -dist2goalelse:dist2goal = dist2goalif self.moveLinear(dist2goal):passelse:success = Falserospy.logwarn("Move to goal failed!")# Turn to  goal yawrelative_yaw = self.goalPose['yaw'] - face2goalYawrelative_yaw = self.normalizeAngle(relative_yaw)if self.rotate(relative_yaw):passelse:success = Falserospy.loginfo("Trun to goal failed!")if success:result = PoseStamped()rospy.loginfo('%s: Succeeded' % self._action_name)self._as.set_succeeded(result)else:rospy.logerr("CHECK MOVE_NEAR!!!!")if __name__ == '__main__':rospy.init_node('move_near')server = MoveNear(rospy.get_name())rospy.spin()

相关文章:

机器人精确移动包

move_near 之前有写过, 将ROS官方的move_basic包改写成了python形式, 同时将它写成了一个完整的action接口 最近测试时发现了问题, odom的数据波动可能会导致机器人陷入正反馈从而一直移动 具体表现为: 机器人移动精度设置为0.005 [m] 机器人在移动到接近0.005的位置, odom…...

强化学习环境报错解决

问题&#xff1a;nameerror: name ‘glpushmatrix‘ is not defined 解决&#xff1a;更换pyglet包的版本。pyglet2.0a4会报这个错误&#xff0c;把版本换成pyglet1.5.27即可。 问题&#xff1a;安装了gym和ale-py但是还是找不到模型&#xff0c;报错ModuleNotFoundError: No…...

Ganache本地测试网如何在远程环境中进行访问和操作

文章目录 前言1. 安装Ganache2. 安装cpolar3. 创建公网地址4. 公网访问连接5. 固定公网地址 前言 Ganache 是DApp的测试网络&#xff0c;提供图形化界面&#xff0c;log日志等&#xff1b;智能合约部署时需要连接测试网络。 Ganache 是一个运行在本地测试的网络,通过结合cpol…...

Kotlin中的函数分类(顶层、成员、局部、递归等)

在 Kotlin 中&#xff0c;函数可以按照不同的方式进行分类。在本篇博客中&#xff0c;我们将介绍以下几种常见的函数分类&#xff0c;并提供示例代码进行演示。 顶层函数&#xff1a; 顶层函数是指定义在文件中的函数&#xff0c;不依赖于任何类或对象。它们可以在文件的任何…...

字符串排序程序

字符串排序程序&#xff0c;对一个字符串中的数值进行从小到大的排序 例如排序前给定的字符串为" 20 78 9 -7 88 36 29" 排序后&#xff1a; -7 9 20 29 36 78 88 要求使用包装类对数值类型的字符串转换成整型进行排序。 public class StringSort {public static vo…...

功率放大器在材料测试中的应用有哪些

功率放大器在材料测试中有广泛的应用&#xff0c;尤其在材料的物理、电子和热学性质等方面的研究中起到了重要的作用。下面Aigtek安泰将详细介绍功率放大器在材料测试中的一些主要应用。 电学特性测试&#xff1a;功率放大器用于材料的电学特性测试&#xff0c;如电导率、介电常…...

汽车屏类产品(一):流媒体后视镜Camera Monitoring System (CMS)

前言: CMS,有叫电子侧视镜,虚拟倒车镜,电子倒车镜, 电子取代镜等,ISO 国际标准组织称其为摄像头监控系统。电子后视镜由“摄像头+屏幕”组成,汽车外后视镜经历了光学镜面从平面镜到曲面镜的迭代进步,CMS也实现从商用车到乘用车的过渡。显示模式为外部摄像头采集图像,…...

三元组(C++ 实现矩阵快速转置)

三元组稀疏矩阵是一种高效存储稀疏矩阵的方法。它通过记录矩阵中非零元素的行、列和值来表示一个稀疏矩阵。我们在三元组里存储的是每个元素的行、列以及值。 题目&#xff1a; 任意输入一个稀疏矩阵M&#xff0c;用三元组顺序表压缩存储该稀疏矩阵M&#xff0c;然后求其转置矩…...

Apriori(关联规则挖掘算法)

关联规则分析 事务库 上表所示的购物篮数据即是一个事务库&#xff0c;该事务库记录的是用户行为的数据。 事务 上表事务库中的每一条记录被称为一笔事务。在购物篮事务中&#xff0c;每一次购物行为即为一笔事务&#xff0c;例如第一行数据“用户1购买商品A,B,C”即为一条事…...

new Object()到底占用几个字节

Java内存模型 对象内存中可以分为三块区域&#xff1a;对象头(Header)&#xff0c;实例数据(Instance Data)和对齐填充(Padding)&#xff0c;以64位操作系统为例(未开启指针压缩的情况)Java对象布局 如下图所示&#xff1a; 其中对象头中的Mark Word中的详细信息在文章synchr…...

瞬态抑制二极管TVS的工作原理?|深圳比创达电子EMC(上)

TVS二极管具有响应速度快、漏电流小、钳位电压稳以及无寿命衰减的特性&#xff0c;从小到信号线静电防护&#xff0c;大到电力系统抗雷击浪涌&#xff0c;TVS都发挥着至关重要的作用。本章对瞬态抑制二极管TVS工作机理展开分析&#xff0c;供产品选型参考。接下来就跟着深圳比创…...

Nginx 同一端口 同时支持http与https 协议

文章目录 需求分析 需求 通过 nginx &#xff0c;让同一端口 同时支持http与https 协议 分析 通过使用 Nginx&#xff0c;可以实现同一端口同时支持 HTTP 和 HTTPS 协议。下面是一种可能的配置方式&#xff1a; 配置 HTTP 服务 在 Nginx 配置文件中&#xff0c;添加以下配置…...

【Express】文件上传管理 multer 中间件

Multer是Node.js中用于处理文件上传的中间件。它可以帮助你处理文件上传的相关逻辑&#xff0c;如接收和保存上传的文件、限制文件大小、设置文件类型限制等。只能用于处理 multipart/form-data 类型的表单数据&#xff0c;它主要用于上传文件。 下面是使用Multer中间件的基本…...

性能监控软件是什么?有哪些优势?

在现代科技驱动的世界中&#xff0c;计算机系统的性能对于企业和个人用户都至关重要。性能监控软件是一种不可或缺的工具&#xff0c;可以帮助我们实时跟踪、分析和优化系统的性能。本文将介绍性能监控软件的概念、其重要性以及如何选择和使用这些工具来提高系统效率。 一、性能…...

分布式事务及CAP和BASE顶底

一、分布式事务 单体应用肯定就不存在分布式事务了&#xff0c;只有在分布式微服务系统中&#xff0c;各个服务之间通过RPC调用后&#xff0c;每个微服务有自己和数据库的连接&#xff0c;各个微服务的回滚不影响其他的微服务事务&#xff0c;这几必须使用分布式事务来解决分布…...

Django REST Framework完整教程-认证与权限-JWT的使用

文章目录 1.认证(Authentication)与权限(Permission)1.1.视图添加权限1.2.登录验证1.3.常用DRF自带权限类1.4.自定义权限类1.5.全局权限1.6.函数视图权限 2.认证详解2.1.认证方案2.2.如何使用TokenAuthentication&#xff1f; 3.JSON Web Token(JWT)认证3.1.工作原理3.2.安装3.…...

领域内容第18名

恭喜入榜...

[1024]程序员节 一晃6年过去了

加入开发者大军&#xff0c;一晃已是6年有余&#xff0c;从最初的Andoird开发如火如荼&#xff0c;到现在的秋风萧瑟&#xff0c;宛如被秋风吹得只剩躯干的树木&#xff0c;等待来年的焕发新芽。 我本不是一个科班出身的开发者&#xff0c;但是为了生活&#xff0c;说白了为了钱…...

数据结构 | 构造哈夫曼树

template<class T> void Heap<T>::PercolateUp() //为了向上调整为堆&#xff0c;我们需要比较当前节点和其父节点的值&#xff0c;如果父节点的值比当前节点大&#xff0c;则交换它们的值。 { int p size - 1, c (p - 1) / 2;//c表示当前节点的父节点&#xff0…...

实验室烧杯可以用超声波清洗机吗

实验室烧杯可以用超声波清洗机吗&#xff1f;答案是可以的&#xff01;超声波清洗机不仅可以清洗实验烧杯&#xff0c;还可以用于清洗实验室中的试管、培养皿、移液管、载玻片、容量瓶、锥形瓶等各类实验器皿。在实验中&#xff0c;如果烧杯清洁不到位&#xff0c;会使得实验数…...

零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?

一、核心优势&#xff1a;专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发&#xff0c;是一款收费低廉但功能全面的Windows NAS工具&#xff0c;主打“无学习成本部署” 。与其他NAS软件相比&#xff0c;其优势在于&#xff1a; 无需硬件改造&#xff1a;将任意W…...

(十)学生端搭建

本次旨在将之前的已完成的部分功能进行拼装到学生端&#xff0c;同时完善学生端的构建。本次工作主要包括&#xff1a; 1.学生端整体界面布局 2.模拟考场与部分个人画像流程的串联 3.整体学生端逻辑 一、学生端 在主界面可以选择自己的用户角色 选择学生则进入学生登录界面…...

Redis相关知识总结(缓存雪崩,缓存穿透,缓存击穿,Redis实现分布式锁,如何保持数据库和缓存一致)

文章目录 1.什么是Redis&#xff1f;2.为什么要使用redis作为mysql的缓存&#xff1f;3.什么是缓存雪崩、缓存穿透、缓存击穿&#xff1f;3.1缓存雪崩3.1.1 大量缓存同时过期3.1.2 Redis宕机 3.2 缓存击穿3.3 缓存穿透3.4 总结 4. 数据库和缓存如何保持一致性5. Redis实现分布式…...

渗透实战PortSwigger靶场-XSS Lab 14:大多数标签和属性被阻止

<script>标签被拦截 我们需要把全部可用的 tag 和 event 进行暴力破解 XSS cheat sheet&#xff1a; https://portswigger.net/web-security/cross-site-scripting/cheat-sheet 通过爆破发现body可以用 再把全部 events 放进去爆破 这些 event 全部可用 <body onres…...

前端导出带有合并单元格的列表

// 导出async function exportExcel(fileName "共识调整.xlsx") {// 所有数据const exportData await getAllMainData();// 表头内容let fitstTitleList [];const secondTitleList [];allColumns.value.forEach(column > {if (!column.children) {fitstTitleL…...

【第二十一章 SDIO接口(SDIO)】

第二十一章 SDIO接口 目录 第二十一章 SDIO接口(SDIO) 1 SDIO 主要功能 2 SDIO 总线拓扑 3 SDIO 功能描述 3.1 SDIO 适配器 3.2 SDIOAHB 接口 4 卡功能描述 4.1 卡识别模式 4.2 卡复位 4.3 操作电压范围确认 4.4 卡识别过程 4.5 写数据块 4.6 读数据块 4.7 数据流…...

el-switch文字内置

el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...

【AI学习】三、AI算法中的向量

在人工智能&#xff08;AI&#xff09;算法中&#xff0c;向量&#xff08;Vector&#xff09;是一种将现实世界中的数据&#xff08;如图像、文本、音频等&#xff09;转化为计算机可处理的数值型特征表示的工具。它是连接人类认知&#xff08;如语义、视觉特征&#xff09;与…...

OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别

OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别 直接训练提示词嵌入向量的核心区别 您提到的代码: prompt_embedding = initial_embedding.clone().requires_grad_(True) optimizer = torch.optim.Adam([prompt_embedding...

SQL慢可能是触发了ring buffer

简介 最近在进行 postgresql 性能排查的时候,发现 PG 在某一个时间并行执行的 SQL 变得特别慢。最后通过监控监观察到并行发起得时间 buffers_alloc 就急速上升,且低水位伴随在整个慢 SQL,一直是 buferIO 的等待事件,此时也没有其他会话的争抢。SQL 虽然不是高效 SQL ,但…...