百度智能车竞赛丝绸之路1——智能车设计与编程实现控制

news2024/9/27 12:18:24

百度智能车竞赛丝绸之路1——智能车设计与编程实现控制
百度智能车竞赛丝绸之路2——手柄控制

一、项目简介

本项目现已基于鲸鱼机器人开发套件对其整体外形进行设计,并且对应于实习内容——以“丝绸之路”为题,对机器人各个功能与机器人结构部分进行相关设计与调整。主要可以实现“车道线巡检”“音乐交际”、“城堡检测”、“翻山越岭”。

本项目通过 Python的Serial 串口通讯库实现与机器人下位机的RS232通讯;通过Struct二进制解析库完成对于手柄IO数据口数据的解析,从而实现通过Xbox手柄控制机器人各个关节及其相应的功能;通过飞浆团队研发的轻量化深度学习推理框架——PaddleLite,实现对于车道拐弯线与机器人航偏值的预测、不同城堡与友谊交际数据的识别分类、不同地标数据和挡板的识别分类,进而通过前置摄像头作为机器人系统的感知器检测机器人前方的车道曲线、地标和挡板,通过左置摄像头感知器检测机器人左方的不同城堡等数据。进而使得本次实习通过上述三种框架实现了机器人的相关任务的完成。

相关资料
2022智能车百度创意组学习资料
链接:https://pan.baidu.com/s/1GjCP3fz_cikNNPMaSAWANQ
提取码:2022

二、实现原理

2.1RS-232协议

RS-232协议是美国电子工业协会EIA(Electronic IndustryAssociation)制定的一种异步串行通信物理接口标准,RS232协议的最新版本为RS-232-C。RS-232-C总线标准设有25 条信号线,包括一个主通道和一个辅助通道。在多数情况下主要使用主通道,对于一般双工通信,仅需三条信号线就可实现:发送线、接收线、地线。适合于数据传输速率在0~20kbps、传输距离小于20m的异步串行通信。
在异步串行通信中,通信协议重要包括:起始位、数据位、校验位、停止位、波特率。通信线上没有数据时处于逻辑1状态,当准备发送一个字符数据时,首先发送一个逻辑0,这个逻辑0就是起始位;在起始位后紧跟的是数据位,数据位的个数可以是5、6、7或8。校验一般采用奇偶检验,校验位可以不发送。校验位之后为停止位,停止位表示一个字符数据的结束,停止位可以是1位、1.5位或2位高电平。
与传统RS232接口不同的是,本次项目中的RS232采用的特制网口,需要接到MC601控制板,通过板子与上位机连接。
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

2.2 pyserial库

Python的serial库是用于串口通信的库,它提供了一组与串口设备通信的函数和类。在使用serial 库进行RS232通讯时,首先,需要创建一个Serial对象来表示串口连接。创建Serial对象时需要指定串口号、波特率、数据位、停止位等参数。使用bytes的fromhex方法将十六进制的字符串格式协议转换为计算机可以直接读的二进制数据,使用Serial对象的write()方法向串口设备发送数据。使用Serial对象的read()或readline()方法从串口设备接收数据。read()方法可以指定要接收的数据长度,而readline()方法则会读取一行数据。使用Serial对象的close()方法关闭串口连接。使用Serial对象的flush()方法将缓冲区的数据全部发送出去并清空缓冲区。最后在操作完毕后,需要及时关闭串口连接,以释放串口资源。

三、实现过程

3.1基础搭建

参考基础版教程对智能车底盘进行组装,并安装控制板,参考官方文档机械臂、夹爪,独立设计两个相机的安装、举旗结构、击打坏人结构,最终智能车模型如下:
在这里插入图片描述

智能车搭建完成以后,对控制板进行环境搭建,参考文档将paddle_install放到指定文件夹执行.sh文件,安装paddlelite。环境搭建好以后便是通过电脑进行控制,将智能车的网口经过网线转USB接到电脑上,在网络适配器中找到新增加的连接进行更改,选择IPv4,

改成下图所示:

在这里插入图片描述

然后便可以通过安装的软件对智能车进行控制

在这里插入图片描述

Xftp和winscp可以进行文件传输,shell可以进行终端指令控制,鲸鱼编程软件可以单独控制硬件和传感器,MobaXterm_Personal既可以进行文件传输又可以进行终端控制。
以MobaXterm_Personal软件为例,点击sesson,选择SFTP,输入IP192.168.1.254,username为root,进入后输入密码root。如下图

在这里插入图片描述

连接后将官方提供的功能包src上传到板子,进入到workspace下,再通过ssh连接,执行python3 walk_lane.py,即可使用官方模型进行巡线,加前缀nohup可以断开网线进行巡线,按2开始,按4结束。将手柄接收器接到EdgeBoard板子USB口上,进入collect文件夹下,执nohup python3 collect_road_data.py,按手柄上的select后,蜂鸣笛响一下,即可手柄控制智能车跑巡线采集数据集,跑完之后按select键退出。之后将EdgeBoard板子collect下的train文件夹传到电脑,将训练数据集程序train_lane在pycharm新建项目,将train文件夹放到train_lane/train_data下,安装paddlepaddle_gpu执行cnn_trainer.py进行模型训练,如下图

在这里插入图片描述

3.2 各硬件传感器控制

3.2.1 简单程序实例

ser = serial.Serial("com3",380400, timeout=0.5)
data= '77 68 06 00 02 0C 01 02 20 0a'
cmd_data = bytes.fromhex(data)
ser.write(cmd_data)

通过python的serial库控制传感器,com3是传感器端口号,380400为波特率,06表示数据长度,00协议版本,02设置动作,0C为编码电机的编号,即10进制的12,01为版号,02为端口,表示电机接在拨号为01的电机控制板的M2口,20表示速度为32。

3.2.2 底盘控制

ChassisController类中move()方法需要传入一个含四个参数的列表与底层进行协议通讯控制四个电机的速度,run()和stop()方法用于识别到友谊时停车到指定位置,turn_left()方法,以指定速度左转,左右边轮速度互为相反数,turn_left()方法同理。steer()方法用于巡线,angle为识别到的线路阈值,将angle乘0.85,在delta正负不同时以1为基准进行左右轮差速实现转弯。

class ChassisController:
    def __init__(self, _serial: serial.Serial):
        self.serial = _serial
        self.speed = 25
        self.kx = 0.85
        self.min_speed = 20
        self.comma_head_all_motor = bytes.fromhex('77 68 0c 00 02 7a 01')
        self.comma_trail = bytes.fromhex('0A')
    def steer(self, angle):
        # print(angle)
        speed = int(self.speed)
        delta = angle * self.kx
        left_wheel = speed
        right_wheel = speed

        if delta < 0:
            left_wheel = int((1 + delta) * speed)
        elif delta > 0:
            right_wheel = int((1 - delta) * speed)
        # print("left_speed:", left_wheel, "  right_speed:", right_wheel)
        self.Move([left_wheel, right_wheel, left_wheel, right_wheel])

    def run(self, l_speed, r_speed):
        self.Move([l_speed, r_speed, l_speed, r_speed])

    def stop(self):
        self.move([0, 0, 0, 0])

    def move(self, speeds):
        left_front = int(speeds[0])
        right_front = -int(speeds[1])
        left_rear = int(speeds[2])
        right_rear = -int(speeds[3])
        self.min_speed = int(min(speeds))
        # print(speeds)
        left_front_kl = bytes.fromhex('01') + left_front.to_bytes(1, byteorder='big', signed=True)
        right_front_kl = bytes.fromhex('02') + right_front.to_bytes(1, byteorder='big', signed=True)
        left_rear_kl = bytes.fromhex('03') + left_rear.to_bytes(1, byteorder='big', signed=True)
        right_rear_kl = bytes.fromhex('04') + right_rear.to_bytes(1, byteorder='big', signed=True)
        send_data_all_motor = (self.comma_head_all_motor + left_front_kl + right_front_kl + left_rear_kl + right_rear_kl
                               + self.comma_trail)
        self.serial.write(send_data_all_motor)
        time.sleep(0.01)

    def turn_left(self):
        speed = self.speed
        left_wheel = -speed
        right_wheel = speed
        self.move([left_wheel, right_wheel, left_wheel, right_wheel])

    def turn_right(self):
        speed = self.speed
        left_wheel = speed
        right_wheel = -speed

        self.move([left_wheel, right_wheel, left_wheel, right_wheel])

    def reverse(self):
        speed = self.speed
        self.move([-speed, -speed, -speed, -speed])

3.2.3 RGB灯光闪烁

rgb_light类定义了2维列表light_num,分别向第一个灯、第二个灯、第三个灯、第四个灯,写入白,红、绿、蓝灯光,实现四个灯依次亮,转完一圈后变颜色继续转的闪烁效果。之后定义线程,使程序运行时灯光一直闪烁。

class rgb_light:
    def __init__(self, ser: serial.Serial):
        self.stop_event = threading.Event()  # 初始化 stop_event 属性
        self.ser = ser

    def light_control(self):
        light_num =[['01 ff ff ff','02 ff ff ff','03 ff ff ff','04 ff ff ff'],
                    ['01 00 ff ff','02 00 ff ff','03 00 ff ff','04 00 ff ff'],
                    ['01 ff 00 ff','02 ff 00 ff','03 ff 00 ff','04 ff 00 ff'],
                    ['01 ff ff 00','02 ff ff 00','03 ff ff 00','04 ff ff 00'],]
        while not self.stop_event.is_set():
            for j in range(len(light_num)):
                for i in range(len(light_num[0])):
                    cmd_data = bytes.fromhex(data) + bytes.fromhex(light_num[j][i]) + bytes.fromhex('0A')
                    self.ser.write(cmd_data)
                    time.sleep(0.5)
            self.ser.write(bytes.fromhex(data1))

if __name__ == '__main__':
    ser = serial.Serial("com5", 380400, timeout=0.5)
    data = '77 68 08 00 02 3B 04'  # 灯光 04 00 00 00
    rgb_light = rgb_light(ser)
    thread = threading.Thread(target=rgb_light.light_control)
    thread.start()
    time.sleep(20)
    rgb_light.stop_event.set()  # 调用 stop_event 对象的 set 方法来停止线程

3.2.4 举旗

向RaiseFlag类的servo_control方法传入角度和速度两个参数,即可控制智能舵机转动的角度和速度,self.angle里面定义了几个常用角度。

class RaiseFlag:

    def __init__(self, _serial: serial.Serial):
        self.serial = _serial
        self.raise_flag = bytes.fromhex('77 68 08 00 02 36 02')
        self.comma_trail = bytes.fromhex('0A')
        self.angle = [225, 135, 45, -45]

    def servo_control(self, angle, speed):
        angle = int(angle)
        cmd_servo_data = self.raise_flag + speed.to_bytes(1, byteorder='big',
                                                          signed=True) + angle.to_bytes(3, byteorder='little',
                                                                                        signed=True) + bytes.fromhex(
            '0A')

        self.serial.write(cmd_servo_data)
        self.serial.flush()
        time.sleep(0.01)

3.2.5 数码管显示陀螺仪角度、蜂鸣器唱歌

SensorController类中Buzzers()方法向蜂鸣器写入列表buzzer_list中的每一组包含音高和音长的参数,根据1-9个等级的音高结合音长粗略模仿D0、Re、Mi、Fa、So、La、Ti七个基本音符实现小星星歌曲音律效果。Groy_Sensor()方法传入板号和陀螺仪连接端口号即可控制陀螺仪,获取当前机械臂倾斜角度值,并用if,else语句排除了有时可能出现的异常。Nixie_Tube()方法需要传入陀螺仪的检测角度值,对值进行处理实现机器人学坐标系下的机械臂倾斜角度显示,即机械臂水平向上角度从360递减,机械臂水平向下角度从0递增。最后析构函数调用Nixie_clear()方法清除数码管显示。

class SensorController:

    def __init__(self, _serial: serial.Serial):
        self.serial = _serial
        self.nixie_tube = bytes.fromhex('77 68 06 00 02 38 02')
        self.nixie_clear = bytes.fromhex('77 68 06 00 02 39 02')
        self.buzzer = bytes.fromhex('77 68 06 00 02 3D 00 01 0A')
        self.buzzer_list = [[1, 2], [1, 2], [5, 2], [5, 2], [6, 2], [6, 2], [4, 4], [4, 2], [4, 2], [3, 2], [3, 2],
                            [2, 2],
                            [2, 2], [1, 4]]
        self.buzzer_thread = threading.Thread(target=self.Buzzers, daemon=True, name='Buzzer')
        self.comma_trail = bytes.fromhex('0A')
        self.done = True
    def Buzzers(self):
        for say in self.buzzer_list:
            say_str = '{:02x}'.format(say[0])
            tm_str = '{:02x}'.format(say[1])
            # print(say_str, '--', tm_str)
            cmd_data = bytes.fromhex('77 68 06 00 02 3D {} {} 0A'.format(say_str, tm_str))
            lock.acquire()
            self.serial.write(cmd_data)
            self.serial.flush()
            lock.release()
            time.sleep(say[1] / 4)

    def Groy_Sensor(self, value, port):
        value_str = '{:02x}'.format(value)
        port_str = '{:02x}'.format(port)
        cmd_data = bytes.fromhex('77 68 06 00 01 DC {} {} 0A'.format(port_str, value_str))
        self.serial.write(cmd_data)
        self.serial.flush()
        time.sleep(0.01)
        read_data = self.serial.readline()
        if len(read_data) < 11 or read_data[-3] != port or read_data[-4] != 0xDC:
            return None
        else:
            data = read_data[3: (3 + 4)]
            sensor = struct.unpack('<i', struct.pack('4B', *data))[0]
            return sensor
    def Nixie_Tube(self, value):
        try:
            if value < 0:
                value = 360 + value
            else:
                value = value
            value = (value & 0xff).to_bytes(1, byteorder='big', signed=True) + (value >> 8).to_bytes(1, byteorder='big',
                                                                                                     signed=True)
        except Exception as err:
            print(err)
            value = 0
            value = (value & 0xff).to_bytes(1, byteorder='big', signed=True) + (value >> 8).to_bytes(1, byteorder='big',
                                                                                                     signed=True)

        cmd_data = self.nixie_tube + value + self.comma_trail
        self.serial.write(cmd_data)
        self.serial.flush()
        time.sleep(0.01)

    def Nixie_clear(self):
        cmd_data = self.nixie_clear + bytes.fromhex('00 00') + self.comma_trail
        self.serial.write(cmd_data)
        self.serial.flush()
        time.sleep(0.01)

    def __del__(self):
        self.Nixie_clear()

四、实现结果

最终巡航完成了“车道线巡检”、“翻山越岭”,举旗,在检测到friendship 播放歌曲小星星完成“音乐交际”,巡航依然有问题尚未解决。
手柄控制效果视频链接

点赞+收藏+关注后私信博主获取完整代码

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/709630.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【几何数学】【Python】【C++】判断两条线段是否相交,若相交则求出交点坐标

判断线段是否相交的办法&#xff08;使用了向量叉积的方法&#xff09;&#xff1a; 首先&#xff0c;通过给定的线段端点坐标p1、p2、p3和p4构建了四个向量v1、v2、v3和v4&#xff1a; v1表示从p1指向p2的向量&#xff0c;其分量为[p2[0] - p1[0], p2[1] - p1[1]]。 v2表示从…

Camtasia Studio2023标准版屏幕录制和视频剪辑软件

Camtasia Studio2023提供了强大的屏幕录像、视频的剪辑和编辑、视频菜单制作、视频剧场和视频播放功能等。它能在任何颜色模式下轻松地记录屏幕动作&#xff0c;包括影像、音效、鼠标移动的轨迹&#xff0c;解说声音等等&#xff0c;另外&#xff0c;它还具有及时播放和编辑压缩…

[前端]JS——join()与split()的使用

Array.join():数组转换为字符串,"()"里元素指定数组转为字符串用什么串联&#xff0c;默认为空。 Array.join()的使用&#xff1a; <script>let arr[1,2,3,4]console.log("arr未转换前:",arr,typeof(arr));console.log("arr使用join():"…

Netty核心技术八--Netty编解码器和handler的调用机制

1.基本说明 netty的组件设计&#xff1a;Netty的主要组件有Channel、EventLoop、ChannelFuture、 ChannelHandler、ChannelPipe等 ChannelHandler充当了处理入站和出站数据的应用程序逻辑的容器。 例如&#xff0c;实现ChannelInboundHandler接口&#xff08;或ChannelInbound…

Typora图床配置-OSS对象存储

Typora图床配置-OSS对象存储 1.PicGo下载 下载地址&#xff1a; Release 2.3.0 Molunerfinn/PicGo GitHub https://github.com/Molunerfinn/PicGo/releases/tag/v2.3.1 下载如下&#xff1a; 2.安装和配置 进入阿里云创建OSS对象存储服务。 设置为公共读才能被别人访问到。…

树与图的深度优先遍历

树的重心 本题的本质是树的dfs&#xff0c; 每次dfs可以确定以u为重心的最大连通块的节点数&#xff0c;并且更新一下ans。 也就是说&#xff0c;dfs并不直接返回答案&#xff0c;而是在每次更新中迭代一次答案。 这样的套路会经常用到&#xff0c;在 树的dfs 题目中 #includ…

IMU 互补滤波

IMU学名惯性测量单元&#xff0c;所有的运动都可以分解为一个直线运动和一个旋转运动&#xff0c;故这个惯性测量单元就是测量这两种运动&#xff0c;直线运动通过加速度计可以测量&#xff0c;旋转运动则通过陀螺。 void IMUupdate(float gx, float gy, float gz, float ax,fl…

Go 语言 context 都能做什么?

原文链接&#xff1a; Go 语言 context 都能做什么&#xff1f; 很多 Go 项目的源码&#xff0c;在读的过程中会发现一个很常见的参数 ctx&#xff0c;而且基本都是作为函数的第一个参数。 为什么要这么写呢&#xff1f;这个参数到底有什么用呢&#xff1f;带着这样的疑问&am…

postgresql数据库登录代理解析(包含登录协议包解析)

文章目录 postgresql数据库登录代理解析&#xff08;包含登录协议包解析&#xff09;背景描述版本不同对应的账号密码加密目标解析方法相关代码位置断点关键位置及相关重要变量 登录通信流程&#xff08;SCRAM-SHA-256方式&#xff09;代码实现相关参考资料 postgresql数据库登…

Python count()函数详解

「作者主页」&#xff1a;士别三日wyx 「作者简介」&#xff1a;CSDN top100、阿里云博客专家、华为云享专家、网络安全领域优质创作者 「推荐专栏」&#xff1a;对网络安全感兴趣的小伙伴可以关注专栏《网络安全入门到精通》 count 1、指定搜索位置2、参数为负数3、列表的coun…

以太网OSI参考模型(四)

目录 OSI模型 一、物理层 二、数据链路层 三、网络层 四、传输层 五、会话层 六、表示层 七、应用层 OSI模型 OSI七层模型&#xff0c;是国际标准化组织(ISO)和国际电报电话咨询委员会(CCITT)1984年联合制定的开放系统互联参考模型&#xff0c;为开放式互联信息系统提供…

06-C++学习笔记-指针的定义与使用

指针是C中非常重要的概念&#xff0c;它允许直接访问内存地址&#xff0c;并通过地址操作变量。本篇笔记将介绍指针的定义与使用方法&#xff0c;以及指针与数组的关系。 1️⃣ 指针的引入 指针的引入是为了解决需要直接访问内存地址的情况。通过指针&#xff0c;可以间接访问…

Android TextView 展示特殊字符高度变高问题解决

背景 #在我们的项目中&#xff0c;展示文字是很常见的需求&#xff0c;但是在线上展示中发现&#xff0c;有些信息是特殊字符展示的&#xff0c;而且这些字符的高度会导致TextView的高度变高&#xff08;与正常字符比&#xff09;。 效果如下&#xff1a; 很明显&#xff0…

森云+优控配置摄像头进行录像和拍照测试

森云和优控配置摄像头进行录像和拍照测试 现在其实已经基本上明确自己的环境了&#xff0c;就是在ubuntu下的pycharm和vscode&#xff0c;然后下载conda&#xff08;但是不要默认的base环境&#xff0c;只要conda create -n xxx 这样的基本功能就好了&#xff09; 显示opencv…

AI绘画StableDiffusion:云端在线版使用笔记分享(Kaggle版)

玩AI绘画&#xff08;SD&#xff09;&#xff0c;自己电脑配置不够&#xff1f;今天给大家介绍一下如何baipiao在线版AI绘画StableDiffusion。 Kaggle 是世界上最大的数据科学社区&#xff0c;拥有强大的工具和资源&#xff0c;可帮助您实现数据科学目标。&#xff08;每周可以…

【MySQL学习笔记】(六)MySQL基本查询

表的增删查改 1 create1.1 单行数据全列插入1.2 多行数据 指定列插入1.3 插入否则更新1.4 替换 2 retrieve2.1 select列2.1.1 全列查询2.2.2 指定列查询2.2.3 查询字段为表达式2.2.4 为查询结果指定别名2.2.5 结果去重 2.2 where 条件2.2.1 null的查询 2.3 结果排序2.4 筛选分…

如何搭建一个实时对话转录应用(类似zoom中的文本转录功能)并部署到 Heroku

文章目录 应用搭建Assembly AI文件夹结构前端搭建HTMLindex.js 后端搭建server.jspackage.json Heroku 部署创建账号创建Heroku应用上传仓库 应用搭建 应用基于 html javascript使用的第三方 API 是 Assembly AI 提供的 Assembly AI 要使用 real-time transcript 功能&…

ChatGPT:为教育创新提供五大机遇

随着智能技术的不断发展&#xff0c;ChatGPT在教育场景中的创新价值可能比我们能够意识到的还要多。比如它可以自动处理作业、在线答疑&#xff0c;可以辅助语言学习、实时沟通&#xff0c;甚至还可以用于评估诊断、科学研究。国内外关于利用ChatGPT实现教育创新的场景描绘已经…

【Matplotlib】多级雷达图绘制

一、实例1&#xff1a;个人能力画像雷达图 # -*- coding: utf-8 -*- """ Created on Sat Jul 1 20:52:54 2023author: zcq """import numpy as np import matplotlib.pyplot as plt import matplotlibmatplotlib.rcParams[font.family]SimHei …

灯夹三角架

2个卡箍1个无头螺丝拼1个灯夹 还需要1个三脚架固定 difference(){union(){translate([18,-7,0])cube([14,14,1]);translate([-7,18,40])cube([14,14,1]);translate([-7,-32,40])cube([14,14,1]);points [[7,-32,40], //0[18,-7,0], //1[18,7,0], //2[7,-18,40], //3[7,…