python机器人编程——基于单目视觉、固定场景下的自动泊车(下)

2024-02-11 12:30

本文主要是介绍python机器人编程——基于单目视觉、固定场景下的自动泊车(下),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

  • 一、前言
  • 二、主要思路
    • step0 设定一个中间位置
    • step1 掉转马头
    • step2 直线匀速前进
    • step3 调整姿态
    • step4 视觉匹配
  • 三、效果
  • 四、全篇总结

一、前言

本篇来讨论一下在固定场景下,如何仅通过单目视觉,实现差速小车的自动停靠,这种方式实现成本比较低,可适应的范围比较广,比如可以应用于小车的自动充电桩寻找、工位的最准等应用场景。我们还是尝试应用有限、浅显的数学对固定场景下,通过坐标的变换、几何的分析、结合单目摄像头获取的图像,进行相机位置(或者小车的位置)的估计,并控制差速小车行驶至我们预设的位置停靠。本篇根据上篇已经识别的位置,进一步实现小车的控制部分。
在这里插入图片描述

二、主要思路

由于我们讨论的是简单场景,在知道了当前小车位置和方向角后,要行驶至固定点位,最直接粗暴的方法是走直线了,我们可以这样进行路线的控制:

step0 设定一个中间位置

由于视觉判断出来的位置毕竟准确的不高,我们有必要设立一个在目标停车区前面设置一个中间位置,用于最后停进去前进行缓冲,稍微精确的进行位置调整,类似两个空间站对接的场景。如上图绿色点,例如这个坐标如设为(0,-2500)单位mm,目标点坐标为(0,-1500)。

step1 掉转马头

这一步是直接原地转向,根据视觉计算的位置和中间点位置,将当前方向角原地旋转调整至朝向中间点的位置。如下图:
在这里插入图片描述
应该调整的角度dtheta=theta_t1-theta_t0,其中,theta_t1是根据向量Pt0---->Pt1计算获取,向量的旋转角度计算程序如下:

def single_vangle(v1):"""计算单个向量夹角,返回弧度和角度"""dx1 = v1[2] - v1[0]    dy1 = v1[3] - v1[1]    fangle1 = math.atan2(dy1, dx1)    angle1 = round(fangle1 * 180/math.pi,2)    return fangle1,angle1

用程序计算小车在Pt0点应该旋转的角度如下:

def move2ready(location,theta,clientID,TTHandle,speed=0.15,tspeed=0.05,main_local=(0,-2500),r=0.16):"""r:小车中心到轮子的距离"""p0x=location[0]p0y=location[1]p1x=main_local[0]p1y=main_local[1]orders=[]angle1=theta+90print("当前小车角度:",angle1)print("当前小车坐标:",p0x,p0y)f,angle0=single_vangle([p0x,p0y,p1x,p1y])print("当前中间点角度:",angle0)dangle=angle0-angle1print("转角角度:",dangle)if dangle>=0:#顺时针转rv>0>lvdangle=dangle/180*math.pi#转弧度vr=tspeedvl=-tspeed#旋转时间=角度/角速度,角速度=线速度/rtita=abs(dangle/(vr*10*0.164))orders.append([tita,(vl,vr),clientID,TTHandle])else:dangle=-dangle/180*math.pi#转弧度vr=-tspeedvl=tspeed#旋转时间=角度/角速度,角速度=线速度/rtita=abs(dangle/(vr*10*0.164))orders.append([tita,(vl,vr),clientID,TTHandle])######part1------接下部分###############

PS:如何控制小车按照既定的指令前进,比如:先让小车左转30度,再匀速直行1米,再右转20度…
这里我们可以通过设置一个独立的线程,将需要的一些先后顺序的控制指令封装在一个list里面,命名为orders,其结构如下:
orders=[[执行时间t,(执行的左右轮速度),小车的ID号,小车的反馈状态句柄],…]
然后编制一个顺序指令函数,来解释这个orders,并按一定的先后顺序根据计时时间下发到小车,这样就形成了一个顺序控制(CCS)过程:

def tick_tack(orders,circle=True):"""按时间执行控制,orders=[[tita,(leftspeed,rightpeed),clientID]]"""x,y,xe,ye,ang0,ang1=0,0,0,0,0,0start_time=time.time()for i in range(len(orders)):          tita=orders[i][0]lv=orders[i][1][0]rv=orders[i][1][1]clientID=orders[i][2]TTHandle=orders[i][3]if circle:ret, arr = sim.simxGetObjectOrientation(clientID, TTHandle, -1, sim.simx_opmode_blocking)if ret==sim.simx_return_ok:x=round(arr[0]*1000,2)y=round(arr[1]*1000,2)  ang0=round(arr[2],2) print("角度:",arr)if ang0<0:ang0=math.pi*2+ang0else:ret, arr = sim.simxGetObjectPosition(clientID, TTHandle, -1, sim.simx_opmode_blocking)if ret==sim.simx_return_ok:x=round(arr[0]*1000,2)y=round(arr[1]*1000,2)  ang0=round(arr[2],2)  send_LR(clientID,lv,rv)            time.sleep(tita)if circle:ret, arr = sim.simxGetObjectOrientation(clientID, TTHandle, -1, sim.simx_opmode_blocking)if ret==sim.simx_return_ok:xe=round(arr[0]*1000,2)ye=round(arr[1]*1000,2)ang1=round(arr[2],2)  if ang1<0:ang1=math.pi*2+ang1if ang1<ang0:aspeed=(ang1+math.pi*2-ang0)/tita                    #speed=math.sqrt((xe-x)**2+(ye-y)**2)/tita#print("线速度(mm):",speed)else:aspeed=(ang1-ang0)/titaprint("角速度(mm):",aspeed)print("角度:",arr)else:ret, arr = sim.simxGetObjectPosition(clientID, TTHandle, -1, sim.simx_opmode_blocking)if ret==sim.simx_return_ok:xe=round(arr[0]*1000,2)ye=round(arr[1]*1000,2)                     speed=math.sqrt((xe-x)**2+(ye-y)**2)/titaprint("线速度(mm):",speed)send_LR(clientID,0,0)send_LR(clientID,0,0)time.sleep(0.01)end_time=time.time()   print("用时:",end_time-start_time)return True,end_time-start_time

step2 直线匀速前进

掉转朝向完成后,我们就控制小车左右轮速为相等,计算好直线移动至中间位置的时间,利用计算机监控时间,倒计时停止后,即为中间位置。
此处比较好理解,只要计算一下当前点Pt0到中间点Pt1的距离,并且设定好合适的速度,就可以计算小车应该行进的时间,于是生成指令加入orders序列:

######part2------接part1部分################计算前进时间distance=math.sqrt((p0x-p1x)**2+(p0y-p1y)**2)vl=speedvr=speedtita=distance/(vl*10*24)orders.append([tita,(vl,vr),clientID,TTHandle])######part2------接下部分###############

step3 调整姿态

在中间位置附近了,就可以根据当前的朝向,原地旋转小车,将小车朝向调整至垂直面向目的区域,并且下车的控制由模型计算控制转为视觉导航为主的位置精调控制。
这一步跟第一步是一样的只要调整好小车方向至中间点至原点向量的角度就可以:

######part3------接part2部分###############
#计算中间点位置旋转dangle=90-angle0if dangle>=0:#顺时针转rv>0>lvdangle=dangle/180*math.pi#转弧度vr=tspeedvl=-tspeed#旋转时间=角度/角速度,角速度=线速度/rtita=abs(dangle/(vr*10*0.164))orders.append([tita,(vl,vr),clientID,TTHandle])else:dangle=-dangle/180*math.pi#转弧度vr=-tspeedvl=tspeed#旋转时间=角度/角速度,角速度=线速度/rtita=abs(dangle/(vr*10*0.164))orders.append([tita,(vl,vr),clientID,TTHandle])print("bigen move:",i,orders) t=threading.Thread(target=tick_tack,args=(orders,))t.setDaemon(True)t.start()return t

最后创建一个新的线程,将生成的顺序控制指令orders用我们的顺序控制函数tick_tack执行。小车就会执行一些列的动作,移动到中间点附近了!
在这里插入图片描述

step4 视觉匹配

类似于导弹的地形匹配,我们利用单目视觉获得的图像,在小车前进中进行位置角度的调整,原则上是使得固定二维码中心始终在图像的中心位置,且其它参考点P1、P2相对中心点位置距离比例是相等的,垂直、横向二维码点不产生比例偏移。直至小车运动至目标位置停止。
这个问题其实就是一个阶跃的响应控制问题:
在这里插入图片描述
这里我们还是利用之前博文中所用到的预测控制思想去控制小车至目标设定值,上图红线所示。这里也可以通过PID等其它控制手段,实现小车位置的精调回正。

三、效果

移动到中间点:
在这里插入图片描述

最后精细控制至目标点:
在这里插入图片描述

四、全篇总结

至此,初步完成了在简单固定场景仿真环境下,基于单目视觉的自动停靠控制,通过测试,即使在理想的仿真环境下面,基于单目视觉简单的定位也存在着一定的误差,需要反复的进行调整参数,由此可见应用于实际场景,相对情况要复杂很多,单单利用单目视觉和简单的特征识别处理在实际应用场景还是不够的,要引入更多的信息源(如激光传感、深度传感)、使用优化算法来提高系统的可靠性和准确性。
后续还有很多改进的地方,让我们继续深入研究吧!

这篇关于python机器人编程——基于单目视觉、固定场景下的自动泊车(下)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/699774

相关文章

Python的Darts库实现时间序列预测

《Python的Darts库实现时间序列预测》Darts一个集统计、机器学习与深度学习模型于一体的Python时间序列预测库,本文主要介绍了Python的Darts库实现时间序列预测,感兴趣的可以了解... 目录目录一、什么是 Darts?二、安装与基本配置安装 Darts导入基础模块三、时间序列数据结构与

Python正则表达式匹配和替换的操作指南

《Python正则表达式匹配和替换的操作指南》正则表达式是处理文本的强大工具,Python通过re模块提供了完整的正则表达式功能,本文将通过代码示例详细介绍Python中的正则匹配和替换操作,需要的朋... 目录基础语法导入re模块基本元字符常用匹配方法1. re.match() - 从字符串开头匹配2.

Python使用FastAPI实现大文件分片上传与断点续传功能

《Python使用FastAPI实现大文件分片上传与断点续传功能》大文件直传常遇到超时、网络抖动失败、失败后只能重传的问题,分片上传+断点续传可以把大文件拆成若干小块逐个上传,并在中断后从已完成分片继... 目录一、接口设计二、服务端实现(FastAPI)2.1 运行环境2.2 目录结构建议2.3 serv

通过Docker容器部署Python环境的全流程

《通过Docker容器部署Python环境的全流程》在现代化开发流程中,Docker因其轻量化、环境隔离和跨平台一致性的特性,已成为部署Python应用的标准工具,本文将详细演示如何通过Docker容... 目录引言一、docker与python的协同优势二、核心步骤详解三、进阶配置技巧四、生产环境最佳实践

Python一次性将指定版本所有包上传PyPI镜像解决方案

《Python一次性将指定版本所有包上传PyPI镜像解决方案》本文主要介绍了一个安全、完整、可离线部署的解决方案,用于一次性准备指定Python版本的所有包,然后导出到内网环境,感兴趣的小伙伴可以跟随... 目录为什么需要这个方案完整解决方案1. 项目目录结构2. 创建智能下载脚本3. 创建包清单生成脚本4

MySQL的JDBC编程详解

《MySQL的JDBC编程详解》:本文主要介绍MySQL的JDBC编程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录前言一、前置知识1. 引入依赖2. 认识 url二、JDBC 操作流程1. JDBC 的写操作2. JDBC 的读操作总结前言本文介绍了mysq

MyBatis Plus实现时间字段自动填充的完整方案

《MyBatisPlus实现时间字段自动填充的完整方案》在日常开发中,我们经常需要记录数据的创建时间和更新时间,传统的做法是在每次插入或更新操作时手动设置这些时间字段,这种方式不仅繁琐,还容易遗漏,... 目录前言解决目标技术栈实现步骤1. 实体类注解配置2. 创建元数据处理器3. 服务层代码优化填充机制详

Python实现Excel批量样式修改器(附完整代码)

《Python实现Excel批量样式修改器(附完整代码)》这篇文章主要为大家详细介绍了如何使用Python实现一个Excel批量样式修改器,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一... 目录前言功能特性核心功能界面特性系统要求安装说明使用指南基本操作流程高级功能技术实现核心技术栈关键函

防止Linux rm命令误操作的多场景防护方案与实践

《防止Linuxrm命令误操作的多场景防护方案与实践》在Linux系统中,rm命令是删除文件和目录的高效工具,但一旦误操作,如执行rm-rf/或rm-rf/*,极易导致系统数据灾难,本文针对不同场景... 目录引言理解 rm 命令及误操作风险rm 命令基础常见误操作案例防护方案使用 rm编程 别名及安全删除

python获取指定名字的程序的文件路径的两种方法

《python获取指定名字的程序的文件路径的两种方法》本文主要介绍了python获取指定名字的程序的文件路径的两种方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要... 最近在做项目,需要用到给定一个程序名字就可以自动获取到这个程序在Windows系统下的绝对路径,以下