树莓派上利用Tensorflow实现小车的自动驾驶(无人驾驶)

 代码地址:https://github.com/Timthony/self_drive

先抛出大家最关心的——代码地址:

github传送门:https://github.com/Timthony/self_drive

基于树莓派的人工智能自动驾驶小车

# 整体流程
电机控制    
摄像头调试    
道路数据采集    
搭建深度学习模型,参数调试    
自动驾驶真实道路模拟    
参数最终调试    

使用方法:    
1. 先将树莓派小车硬件组装好
2. 使用zth_car_control.py来控制小车的前后左右移动,配合zth_collect_data.py来人工操作,使小车在自己制作的跑道进行数据采集。(该过程在树莓派进行)
3. 数据采集完成以后使用zth_process_img.py来对采集的数据进行处理,之前当前先完成一些数据清洗的工作。(电脑上执行)
4. 使用神经网络模型对数据进行训练zth_train.py,得到训练好的模型。(电脑上执行)
5. 在树莓派小车上使用zth_drive和训练好的模型,载入模型,即可实现在原先跑道的自动驾驶。(树莓派上执行)    
注意:只需要使用上述提到的代码即可,别的都是一些初始版本或者正在增加的一些新模块。    

 

树莓派上利用Tensorflow实现小车的自动驾驶(无人驾驶)_第1张图片


# 注意事项:
1. 赛道需要自己制作,很重要,决定了数据质量。(我是在地板上,贴的有色胶带,然后贴成了跑道的形状)。
2. 赛道的宽度大约是车身的两倍。
3. 大约采集了五六万张图像,然后筛选出三四万张。
4. 摄像头角度问题

# 具体制作流程: 
1. 小车原始模型,某宝购买玩具车即可,比如:有电机,有自带电池盒(给电机供电)
2. 树莓派,摄像头,蓄电电池组(用于树莓派供电)
3. 使用一些螺栓,螺柱,亚克力板将树莓派,蓄电电池固定在小车上(具体方法,看手头的工具吧)
4. 组装好以后,树莓派通过VNC连接电脑,登陆树莓派,在树莓派安装keras环境,以便最后调用训练好的模型。
5. 关于小车的控制(电机控制,摄像头采集数据),都在源文件,有注释,大致思路就是通过方向键AWSD来控制方向,使用了pygame的工具包。
6. 通过电脑端的wasd方向键手动控制小车(已经VNC连接好)在制作好的赛道上进行图像采集,直线部分按w,左拐弯按a,右拐弯按d等,建议采集50000张以上。
(采集的图像命名要求为,0_xxxx,1_xxxx,其中首位字母就代表了你按下的是哪个键,比如图像是0开头,那么这张图像就是直行,按下的是w键,这些0,1,2,3,4 数字就相当于数据的标签值)
7. 将图片从树莓派拷贝下来,进行数据清洗,使用电脑端的深度学习环境进行模型训练,使用的模型可以自行定义。
8. 将训练好的模型文件.h5拷贝到树莓派,然后通过树莓派调用载入模型,即可处理实时的图像,并且根据图像预测出是0,1,2,3,4等数字,也就表示了树莓派该怎么移动,通过树莓派控制电机即可。


# 正在进行一些改进:    
1.使用迁移学习进行fine-tuning是否可以提高精度    
2.处理光照问题    
3.处理数据类别不平衡的问题    
欢迎交流讨论    

# 收集数据,赛道照片和对应的前、后、左、右、4停
# 对应图片和相应的标签值
import io
import zth_car_control
import os
os.environ['SDL_VIDEODRIVE'] = 'x11'
import pygame     # 检测模块
from time import ctime,sleep,time
import threading
import numpy as np
import picamera
import picamera.array

global train_labels, train_img, is_capture_running, key

class SplitFrames(object):
    
    def __init__(self):
        self.frame_num = 0
        self.output = None
# 处理图像的函数write
# 对视频拍摄的每一帧进行处理,构造一个自定义输出类,每拍摄一帧都会进来write处理
    def write(self, buf):
        global key
        if buf.startswith(b'\xff\xd8'):                            # 代表一个JPG图片的开始,新照片的开头
            # Start of new frame; close the old one (if any) and
            # open a new output
            if self.output:
                self.output.close()
            self.frame_num += 1
            self.output = io.open('%s_image%s.jpg' % (key,time()), 'wb')           # 改变格式为jpg
        self.output.write(buf)
    
 
def pi_capture():
    global train_img, is_capture_running,train_labels,key
    
    #init the train_label array
    print("Start capture")        
    is_capture_running = True

    with picamera.PiCamera(resolution=(160, 120), framerate=30) as camera:
        # 根据摄像头实际情况判断是否要加这句上下翻转
        # camera.vflip = True
        # Give the camera some warm-up time
        sleep(2)
        output = SplitFrames()
        start = time()
        camera.start_recording(output, format='mjpeg')
        camera.wait_recording(120)
        camera.stop_recording()
        finish = time()
    print('Captured %d frames at %.2ffps' % (
        output.frame_num,
        output.frame_num / (finish - start)))
    
    print("quit pi capture")
    is_capture_running = False

def my_car_control(): 
    global is_capture_running, key
    key = 4
    pygame.init()
    pygame.display.set_mode((1,1))            # 窗口
    zth_car_control.car_stop()
    sleep(0.1)
    print("Start control!")
 
    while is_capture_running:
        # get input from human driver
        # 
        for event in pygame.event.get():
            # 判断事件是不是按键按下的事件
            if event.type == pygame.KEYDOWN:  
                key_input = pygame.key.get_pressed()     # 可以同时检测多个按键
                print(key_input[pygame.K_w], key_input[pygame.K_a], key_input[pygame.K_d])
                # 按下前进,保存图片以2开头
                if key_input[pygame.K_w] and not key_input[pygame.K_a] and not key_input[pygame.K_d]:
                    print("Forward")
                    key = 2 
                    zth_car_control.car_move_forward()
                # 按下左键,保存图片以0开头
                elif key_input[pygame.K_a]:
                    print("Left")
                    zth_car_control.car_turn_left()
                    sleep(0.1)
                    key = 0
                # 按下d右键,保存图片以1开头
                elif key_input[pygame.K_d]:
                    print("Right")
                    zth_car_control.car_turn_right()
                    sleep(0.1)
                    key = 1
                # 按下s后退键,保存图片为3开头
                elif key_input[pygame.K_s]:
                    print("Backward")
                    zth_car_control.car_move_backward()
                    key = 3
                # 按下k停止键,停止
                elif key_input[pygame.K_k]:
                    zth_car_control.car_stop()
            # 检测按键是不是抬起
            elif event.type == pygame.KEYUP:
                key_input = pygame.key.get_pressed()
                # w键抬起,轮子回正
                if key_input[pygame.K_w] and not key_input[pygame.K_a] and not key_input[pygame.K_d]:
                    print("Forward")
                    key = 2
                    zth_car_control.car_turn_straight()
                    zth_car_control.car_move_forward()
                # s键抬起
                elif key_input[pygame.K_s] and not key_input[pygame.K_a] and not key_input[pygame.K_d]:
                    print("Backward")
                    key = 3
                    zth_car_control.car_move_backward()
                else:
                    print("Stop")
                    zth_car_control.car_stop()
                #car_control.cleanGPIO()
    zth_car_control.clean_GPIO()

if __name__ == '__main__':
    global train_labels, train_img, key

    print("capture thread")
    print ('-' * 50)
    capture_thread = threading.Thread(target=pi_capture,args=())   # 开启线程
    capture_thread.setDaemon(True)
    capture_thread.start()
    
    my_car_control()

    while is_capture_running:
        pass

    print("Done!")
    zth_car_control.car_stop()
    zth_car_control.clean_GPIO()

你可能感兴趣的:(项目)