机器人精确移动包
move_near
之前有写过, 将ROS官方的move_basic包改写成了python形式, 同时将它写成了一个完整的action接口
最近测试时发现了问题, odom的数据波动可能会导致机器人陷入正反馈从而一直移动
具体表现为:
-
机器人移动精度设置为0.005 [m]
-
机器人在移动到接近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…...
强化学习环境报错解决
问题:nameerror: name ‘glpushmatrix‘ is not defined 解决:更换pyglet包的版本。pyglet2.0a4会报这个错误,把版本换成pyglet1.5.27即可。 问题:安装了gym和ale-py但是还是找不到模型,报错ModuleNotFoundError: No…...
Ganache本地测试网如何在远程环境中进行访问和操作
文章目录 前言1. 安装Ganache2. 安装cpolar3. 创建公网地址4. 公网访问连接5. 固定公网地址 前言 Ganache 是DApp的测试网络,提供图形化界面,log日志等;智能合约部署时需要连接测试网络。 Ganache 是一个运行在本地测试的网络,通过结合cpol…...
Kotlin中的函数分类(顶层、成员、局部、递归等)
在 Kotlin 中,函数可以按照不同的方式进行分类。在本篇博客中,我们将介绍以下几种常见的函数分类,并提供示例代码进行演示。 顶层函数: 顶层函数是指定义在文件中的函数,不依赖于任何类或对象。它们可以在文件的任何…...
字符串排序程序
字符串排序程序,对一个字符串中的数值进行从小到大的排序 例如排序前给定的字符串为" 20 78 9 -7 88 36 29" 排序后: -7 9 20 29 36 78 88 要求使用包装类对数值类型的字符串转换成整型进行排序。 public class StringSort {public static vo…...
功率放大器在材料测试中的应用有哪些
功率放大器在材料测试中有广泛的应用,尤其在材料的物理、电子和热学性质等方面的研究中起到了重要的作用。下面Aigtek安泰将详细介绍功率放大器在材料测试中的一些主要应用。 电学特性测试:功率放大器用于材料的电学特性测试,如电导率、介电常…...
汽车屏类产品(一):流媒体后视镜Camera Monitoring System (CMS)
前言: CMS,有叫电子侧视镜,虚拟倒车镜,电子倒车镜, 电子取代镜等,ISO 国际标准组织称其为摄像头监控系统。电子后视镜由“摄像头+屏幕”组成,汽车外后视镜经历了光学镜面从平面镜到曲面镜的迭代进步,CMS也实现从商用车到乘用车的过渡。显示模式为外部摄像头采集图像,…...
三元组(C++ 实现矩阵快速转置)
三元组稀疏矩阵是一种高效存储稀疏矩阵的方法。它通过记录矩阵中非零元素的行、列和值来表示一个稀疏矩阵。我们在三元组里存储的是每个元素的行、列以及值。 题目: 任意输入一个稀疏矩阵M,用三元组顺序表压缩存储该稀疏矩阵M,然后求其转置矩…...
Apriori(关联规则挖掘算法)
关联规则分析 事务库 上表所示的购物篮数据即是一个事务库,该事务库记录的是用户行为的数据。 事务 上表事务库中的每一条记录被称为一笔事务。在购物篮事务中,每一次购物行为即为一笔事务,例如第一行数据“用户1购买商品A,B,C”即为一条事…...
new Object()到底占用几个字节
Java内存模型 对象内存中可以分为三块区域:对象头(Header),实例数据(Instance Data)和对齐填充(Padding),以64位操作系统为例(未开启指针压缩的情况)Java对象布局 如下图所示: 其中对象头中的Mark Word中的详细信息在文章synchr…...
瞬态抑制二极管TVS的工作原理?|深圳比创达电子EMC(上)
TVS二极管具有响应速度快、漏电流小、钳位电压稳以及无寿命衰减的特性,从小到信号线静电防护,大到电力系统抗雷击浪涌,TVS都发挥着至关重要的作用。本章对瞬态抑制二极管TVS工作机理展开分析,供产品选型参考。接下来就跟着深圳比创…...
Nginx 同一端口 同时支持http与https 协议
文章目录 需求分析 需求 通过 nginx ,让同一端口 同时支持http与https 协议 分析 通过使用 Nginx,可以实现同一端口同时支持 HTTP 和 HTTPS 协议。下面是一种可能的配置方式: 配置 HTTP 服务 在 Nginx 配置文件中,添加以下配置…...
【Express】文件上传管理 multer 中间件
Multer是Node.js中用于处理文件上传的中间件。它可以帮助你处理文件上传的相关逻辑,如接收和保存上传的文件、限制文件大小、设置文件类型限制等。只能用于处理 multipart/form-data 类型的表单数据,它主要用于上传文件。 下面是使用Multer中间件的基本…...
性能监控软件是什么?有哪些优势?
在现代科技驱动的世界中,计算机系统的性能对于企业和个人用户都至关重要。性能监控软件是一种不可或缺的工具,可以帮助我们实时跟踪、分析和优化系统的性能。本文将介绍性能监控软件的概念、其重要性以及如何选择和使用这些工具来提高系统效率。 一、性能…...
分布式事务及CAP和BASE顶底
一、分布式事务 单体应用肯定就不存在分布式事务了,只有在分布式微服务系统中,各个服务之间通过RPC调用后,每个微服务有自己和数据库的连接,各个微服务的回滚不影响其他的微服务事务,这几必须使用分布式事务来解决分布…...
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? 3.JSON Web Token(JWT)认证3.1.工作原理3.2.安装3.…...
领域内容第18名
恭喜入榜...
[1024]程序员节 一晃6年过去了
加入开发者大军,一晃已是6年有余,从最初的Andoird开发如火如荼,到现在的秋风萧瑟,宛如被秋风吹得只剩躯干的树木,等待来年的焕发新芽。 我本不是一个科班出身的开发者,但是为了生活,说白了为了钱…...
数据结构 | 构造哈夫曼树
template<class T> void Heap<T>::PercolateUp() //为了向上调整为堆,我们需要比较当前节点和其父节点的值,如果父节点的值比当前节点大,则交换它们的值。 { int p size - 1, c (p - 1) / 2;//c表示当前节点的父节点࿰…...
实验室烧杯可以用超声波清洗机吗
实验室烧杯可以用超声波清洗机吗?答案是可以的!超声波清洗机不仅可以清洗实验烧杯,还可以用于清洗实验室中的试管、培养皿、移液管、载玻片、容量瓶、锥形瓶等各类实验器皿。在实验中,如果烧杯清洁不到位,会使得实验数…...
零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?
一、核心优势:专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发,是一款收费低廉但功能全面的Windows NAS工具,主打“无学习成本部署” 。与其他NAS软件相比,其优势在于: 无需硬件改造:将任意W…...
(十)学生端搭建
本次旨在将之前的已完成的部分功能进行拼装到学生端,同时完善学生端的构建。本次工作主要包括: 1.学生端整体界面布局 2.模拟考场与部分个人画像流程的串联 3.整体学生端逻辑 一、学生端 在主界面可以选择自己的用户角色 选择学生则进入学生登录界面…...
Redis相关知识总结(缓存雪崩,缓存穿透,缓存击穿,Redis实现分布式锁,如何保持数据库和缓存一致)
文章目录 1.什么是Redis?2.为什么要使用redis作为mysql的缓存?3.什么是缓存雪崩、缓存穿透、缓存击穿?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: 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算法中的向量
在人工智能(AI)算法中,向量(Vector)是一种将现实世界中的数据(如图像、文本、音频等)转化为计算机可处理的数值型特征表示的工具。它是连接人类认知(如语义、视觉特征)与…...
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 ,但…...
