机器人精确移动包
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表示当前节点的父节点࿰…...

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

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式
一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明:假设每台服务器已…...
React 第五十五节 Router 中 useAsyncError的使用详解
前言 useAsyncError 是 React Router v6.4 引入的一个钩子,用于处理异步操作(如数据加载)中的错误。下面我将详细解释其用途并提供代码示例。 一、useAsyncError 用途 处理异步错误:捕获在 loader 或 action 中发生的异步错误替…...
Ubuntu系统下交叉编译openssl
一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机:Ubuntu 20.04.6 LTSHost:ARM32位交叉编译器:arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个生活电费的缴纳和查询小程序
一、项目初始化与配置 1. 创建项目 ohpm init harmony/utility-payment-app 2. 配置权限 // module.json5 {"requestPermissions": [{"name": "ohos.permission.INTERNET"},{"name": "ohos.permission.GET_NETWORK_INFO"…...

Map相关知识
数据结构 二叉树 二叉树,顾名思义,每个节点最多有两个“叉”,也就是两个子节点,分别是左子 节点和右子节点。不过,二叉树并不要求每个节点都有两个子节点,有的节点只 有左子节点,有的节点只有…...

Android 之 kotlin 语言学习笔记三(Kotlin-Java 互操作)
参考官方文档:https://developer.android.google.cn/kotlin/interop?hlzh-cn 一、Java(供 Kotlin 使用) 1、不得使用硬关键字 不要使用 Kotlin 的任何硬关键字作为方法的名称 或字段。允许使用 Kotlin 的软关键字、修饰符关键字和特殊标识…...

RNN避坑指南:从数学推导到LSTM/GRU工业级部署实战流程
本文较长,建议点赞收藏,以免遗失。更多AI大模型应用开发学习视频及资料,尽在聚客AI学院。 本文全面剖析RNN核心原理,深入讲解梯度消失/爆炸问题,并通过LSTM/GRU结构实现解决方案,提供时间序列预测和文本生成…...

html-<abbr> 缩写或首字母缩略词
定义与作用 <abbr> 标签用于表示缩写或首字母缩略词,它可以帮助用户更好地理解缩写的含义,尤其是对于那些不熟悉该缩写的用户。 title 属性的内容提供了缩写的详细说明。当用户将鼠标悬停在缩写上时,会显示一个提示框。 示例&#x…...

Visual Studio Code 扩展
Visual Studio Code 扩展 change-case 大小写转换EmmyLua for VSCode 调试插件Bookmarks 书签 change-case 大小写转换 https://marketplace.visualstudio.com/items?itemNamewmaurer.change-case 选中单词后,命令 changeCase.commands 可预览转换效果 EmmyLua…...
深入浅出WebGL:在浏览器中解锁3D世界的魔法钥匙
WebGL:在浏览器中解锁3D世界的魔法钥匙 引言:网页的边界正在消失 在数字化浪潮的推动下,网页早已不再是静态信息的展示窗口。如今,我们可以在浏览器中体验逼真的3D游戏、交互式数据可视化、虚拟实验室,甚至沉浸式的V…...