Ejemplo n.º 1
0
 def __init__(self, line_camera='/dev/video1', od_camera='/dev/video0', serial_port='/dev/ttyUSB0'):
     self._line_camera = line_camera
     self._od_camera = od_camera
     self._serial_port = serial_port
     self.line_camera_width = 320
     self.line_camera_height = 240
     self.od_camera_width = 320
     self.od_camera_height = 240
     self.recognition = Recognition(device=od_camera, width=self.od_camera_width, height=self.od_camera_height)
     self._serial = CarSerial(self._serial_port)
     self.car_controller = CarController(self._serial)
     self.line_camera_capture = cv2.VideoCapture(self._line_camera)
     self.video = VideoWriter("video/" + time.strftime("%Y%m%d%H%M%S"), 320, 240)
     # ret, self.original_frame = self.line_camera_capture.read()
     self.available_frame = None
     self.render_frame = None  # cv2.resize(self.original_frame, (320, 240))
     self.frame_rate_timer = CarTimer()
     self.display = ShowImage()
     self.is_open_window = True
     self.is_print_frame_rate = True
     self.is_save_video = False
Ejemplo n.º 2
0
import sys
sys.path.append("..")
from od.recognition import Recognition
from car.car_timer import CarTimer
# from car.generic_serial import GenericSerial
from car.car_serial import CarSerial
import re, sys
import string
import signal

OD_CAMERA = '/dev/video0'  # 物体检测摄像头
OD_CAMERA_WIDTH = 640  # 识别视频高度
OD_CAMERA_HEIGHT = 480  # 识别视频高度
#serial = GenericSerial("/dev/ttyACM0")
serial = CarSerial("/dev/ttyACM0", receive=True)
# 新建一个识别对象,用于识别操作,程序中的识别对象只能有一个
# 指定设备,指定窗口的宽度和高度,是否打开识别显示窗口(默认是打开)
recognition = Recognition(device=OD_CAMERA,
                          width=OD_CAMERA_WIDTH,
                          height=OD_CAMERA_HEIGHT,
                          display_window=True)

# 新建一个计时器对象,用于程序结束的计时,设置时间为60秒
timer = CarTimer(interval=2)
timer2 = CarTimer(interval=1)
timer3 = CarTimer(interval=1)

angle = 90
pre_angle = angle
direct = True
"""
    本例演示了CarController中group方法的使用。CarcCntroller已经提供了基本的马达控制函数,在某些特定的情况下,
    Carcontroller本身提供的基本控制方法无法满足用户的控制需求,group方法向用户提供了一个超级接口,用户可以创建
    一个马达动作组合列表,向列表中添加一系列BaseControl对象,用于实现马达的动作组合。
"""
# 从上一级目录导入模块,必须加入这两行
import sys
sys.path.append('..')
import time
from car.car_controller import CarController
from car.car_timer import CarTimer
from car.car_serial import CarSerial
from car.car_controller import BaseControl

# 新建串口通信对象,除非测试,不要直接调用此类,控制小车应该通过CarController类
serial = CarSerial("/dev/ttyACM0", receive=True)  # 参数为串口文件
# 新建一个CarController,传入串口通信对象,用于控制小车的各种动作
controller = CarController(serial, base_speed=100)

# 新建一个计时器对象,设定他的计时时间为30秒
timer = CarTimer(interval=20)

# 创建一个列表用于存储马达动作组合的列表
control_list = []

# 按需要控制的顺序,添加各种马达速度和执行时间
control_list.append(BaseControl(100, 100, 5))  # 直走5秒
control_list.append(BaseControl(0, 150, 2))  # 左转 2秒
control_list.append(BaseControl(0, 0, 2))  # 暂停2秒
control_list.append(BaseControl(150, 0, 2))  # 右转2秒
control_list.append(BaseControl(-100, -100, 5))  # 后退5秒
Ejemplo n.º 4
0
import sys
import time
sys.path.append("..")
from car.car_serial import CarSerial
from car.car_timer import CarTimer

serial = CarSerial("/dev/ttyACM0", receive=True)
timer = CarTimer(interval=60)
angle = 90
direct = True
while not timer.timeout():
    if angle < 45:
        direct = True
    elif angle > 135:
        direct = False
    if direct:
        angle += 4
    else:
        angle -= 4
    serial.drive_servo(angle)
    time.sleep(0.5)

Ejemplo n.º 5
0
# 对象用于对输入的图形进行二值化(或者灰度),同时对图形进行腐蚀,以去除部分图像噪声。
# 具体的参数的意义请参考类说明
# 这里要特别注意,bitwise_not为True时图像颜色进行了反转,对于灰度图,也就是黑变白,白变黑,适合于引导线是黑色的地图。
init = ImageInit(width=320,
                 height=240,
                 convert_type="BINARY",
                 threshold=120,
                 bitwise_not=True)

# fl对象用于寻找引导线偏离图像中心的位置,threshold是控制连续白色的的阈值,也就是只有连续多少个白色像素点才认为已经找到引导线
# direction是开始寻找的方向,True是从左边开始寻找,False是右边。当顺时针绕圈时,引导线大概率出现在右边,所以可以选择False。
fl = FollowLine(width=320, height=240, threshold=15, direction=False)

# 串口类,此类最好不要直接使用,而是通过CarController来对车子进行控制
serial = CarSerial(SERIAL, receive=True)
# 此类并没有实现PID控制,而是简单的使用了比例这个参数。(现在这么简单的地图还无需用到PID)
# 如果需要使用PID可以直接调用car目录下的pid类,同时把此类的比例参数设置为1
ctrl = CarController(serial, proportional=0.4)
p_offset = 0
while True:
    ret, frame = camera.read()  # 读取每一帧
    frame = init.resize(frame)  # 把图像缩小,尺寸有ImageInit在初始化时指定
    display.show(frame, "original")
    image = init.processing(frame)  # 对帧进行处理

    # 偏置就是白色线的中心点距离图片中心点的距离,比如320*240的图像,中心点在160
    offset, render_image = fl.get_offset(image,
                                         frame)  # 第一个参数是需要处理的图像,第二个参数是需要渲染的图像

    # 直接把Offset赋值给CarController,对于一般的线没有问题。
Ejemplo n.º 6
0
# 对象用于对输入的图形进行二值化(或者灰度),同时对图形进行腐蚀,以去除部分图像噪声。
# 具体的参数的意义请参考类说明
# 这里要特别注意,bitwise_not为True时图像颜色进行了反转,对于灰度图,也就是黑变白,白变黑,适合于引导线是黑色的地图。
init = ImageInit(width=320,
                 height=240,
                 convert_type="BINARY",
                 threshold=120,
                 bitwise_not=True)

# fl对象用于寻找引导线偏离图像中心的位置,threshold是控制连续白色的的阈值,也就是只有连续多少个白色像素点才认为已经找到引导线
# direction是开始寻找的方向,True是从左边开始寻找,False是右边。当顺时针绕圈时,引导线大概率出现在右边,所以可以选择False。
fl = FollowLine(width=320, height=240, threshold=15, direction=False)

# 串口类,此类最好不要直接使用,而是通过CarController来对车子进行控制
serial = CarSerial(SERIAL, receive=False)
# 此类并没有实现PID控制,而是简单的使用了比例这个参数。(现在这么简单的地图还无需用到PID)
# 如果需要使用PID可以直接调用car目录下的pid类,同时把此类的比例参数设置为1
ctrl = CarController(serial, base_speed=150, proportional=0.4)
p_offset = 0

findRoadblock = FindRoadblock(h_low=0,
                              h_high=100,
                              s_low=0,
                              s_high=159,
                              v_low=80,
                              v_high=255,
                              threshold=0.2)

while True:
    ret, frame = camera.read()  # 读取每一帧
Ejemplo n.º 7
0
import sys
import time
sys.path.append("..")
from car.car_serial import CarSerial
from car.car_timer import CarTimer
serial = CarSerial("/dev/ttyACM0", receive=True)
timer = CarTimer(interval=30)
while not timer.timeout():
    serial.drive_motor(100, -100)
    time.sleep(0.05)
    print(timer.duration())
Ejemplo n.º 8
0
"""
    本例演示了定时器的使用,定时器简单的封装了计时,设定时长,并判断是否超时两个功能。
    下面例子演示了怎样在30秒内,循环控制车子直线行走5 秒,然后左转1 秒,最后停车。
"""
# 从上一级目录导入模块,必须加入这两行
import time
import sys
sys.path.append('..')

from car.car_controller import CarController
from car.car_timer import CarTimer
from car.car_serial import CarSerial

# 新建串口通信对象,除非测试,不要直接调用此类,控制小车应该通过CarController类
# 查看串口实际的串口文件可以使用 ls /dev/tty* 命令。通常 Arduino的串口文件都是 "/dev/ttyACM0" 或者"/dev/ttyUSB0"
serial = CarSerial("/dev/ttyUSB0", receive=True)  # 参数为串口文件 receive为True,可以接收到Arduino的串口反馈信息
# 新建一个CarController,传入串口通信对象,用于控制小车的各种动作
controller = CarController(serial, base_speed=100)

# 新建一个计时器对象,设定他的计时时间为30秒
timer = CarTimer(interval=30)
timer2 = CarTimer(interval=5)
controller.go_straight(delay_time=5)   # 直走5秒
# 当时间未到时循环
while not timer.timeout():
    print("time2.duration:{}".format(timer2.duration()))
    if timer2.timeout():
        # CarController 根据动作的优先级来选择需要执行的动作,我们同时输入5秒的直行和1秒转弯,它将优先执行转弯1秒
        # 当转弯一秒时间到后,转弯任务结束,这时直走还剩下4秒,所以第二秒开始就执行直走任务。
        controller.turn(direction=True, delay_time=1)  # 左转1秒
        controller.go_straight(delay_time=5)           # 直走5秒
Ejemplo n.º 9
0
from discards.line_base import *
import io
from car.car_serial import CarSerial
from cv.video_writer import videoWriter
#from objcet_detection import object_detection
ser = CarSerial("/dev/ttyACM0", 115200)
#obd = object_detection("tmp.jpg")
IM_WIDTH = 240
IM_HEIGHT = 180

count = 5
frequency = 5

#test
camera = cv2.VideoCapture(1)
ret = camera.set(3, IM_WIDTH)
ret = camera.set(4, IM_HEIGHT)
ret, frame = camera.read()

frame_rate_calc = 1
freq = cv2.getTickFrequency()
exit_flag = False
#fps = 15
#fourcc = cv2.VideoWriter_fourcc('h', '2', '6', '4')
#sz = (int(camera.get(cv2.CAP_PROP_FRAME_WIDTH)), int(camera.get(cv2.CAP_PROP_FRAME_WIDTH)))
#vout = cv2.VideoWriter()
#vout.open('sample.avi', fourcc, fps, sz)
vw = videoWriter('test_one', 240, 180)

# Create the in-memory stream
stream = io.BytesIO()
Ejemplo n.º 10
0
LINE_CAMERA = '/dev/video0'  # 巡线摄像头
OD_CAMERA = '/dev/video1'  # 物体检测摄像头
SERIAL = "/dev/ttyACM0"  # 串口

LINE_CAMERA_WIDTH = 320  # 巡线视频高度
LINE_CAMERA_HEIGHT = 240  # 巡线视频宽度
OD_CAMERA_WIDTH = 320  # 识别视频高度
OD_CAMERA_HEIGHT = 240  # 识别视频高度

section = 0  # 分段标识
p_offset = 0
# endregion

# region 新立需要的各种对象
# 串口通信对象
serial = CarSerial(port=SERIAL, receive=True)
# 小车控制器
ctrl = CarController(car_serial=serial, base_speed=80)
# 识别对象
rc = Recognition(device=OD_CAMERA,
                 width=OD_CAMERA_WIDTH,
                 height=OD_CAMERA_HEIGHT,
                 frequency=20)

# cv巡线对象
camera = cv2.VideoCapture(LINE_CAMERA)
ret, frame = camera.read()

# 基本图像处理对象
img_init = ImageInit(LINE_CAMERA_WIDTH,
                     LINE_CAMERA_HEIGHT,
Ejemplo n.º 11
0
OD_CAMERA_HEIGHT = 240  # 识别视频高度

section = 0  # 分段标识
p_offset = 0
# endregion

# region 新立需要的各种对象

# 识别对象
rc = Recognition(device=OD_CAMERA,
                 width=OD_CAMERA_WIDTH,
                 height=OD_CAMERA_HEIGHT,
                 frequency=20)

# 串口通信对象
serial = CarSerial(port=SERIAL, receive=False)
# 小车控制器
ctrl = CarController(car_serial=serial, base_speed=80)

# cv巡线对象
camera = cv2.VideoCapture(LINE_CAMERA)
ret, frame = camera.read()

# 基本图像处理对象
img_init = ImageInit(LINE_CAMERA_WIDTH,
                     LINE_CAMERA_HEIGHT,
                     threshold=250,
                     kernel_type=(3, 3),
                     iterations=4,
                     bitwise_not=False)
# 巡线对象
Ejemplo n.º 12
0
class CarBase:
    """
        为车子的控制提供一个基类,把一些重复的变量和函数写在基类
        继承本类的子类只需要关注于具体的操作
        类变量task_list用于存储子类的操作任务,并由基类的mail_loop负责执行
    """
    task_list = []

    def __init__(self, line_camera='/dev/video1', od_camera='/dev/video0', serial_port='/dev/ttyUSB0'):
        self._line_camera = line_camera
        self._od_camera = od_camera
        self._serial_port = serial_port
        self.line_camera_width = 320
        self.line_camera_height = 240
        self.od_camera_width = 320
        self.od_camera_height = 240
        self.recognition = Recognition(device=od_camera, width=self.od_camera_width, height=self.od_camera_height)
        self._serial = CarSerial(self._serial_port)
        self.car_controller = CarController(self._serial)
        self.line_camera_capture = cv2.VideoCapture(self._line_camera)
        self.video = VideoWriter("video/" + time.strftime("%Y%m%d%H%M%S"), 320, 240)
        # ret, self.original_frame = self.line_camera_capture.read()
        self.available_frame = None
        self.render_frame = None  # cv2.resize(self.original_frame, (320, 240))
        self.frame_rate_timer = CarTimer()
        self.display = ShowImage()
        self.is_open_window = True
        self.is_print_frame_rate = True
        self.is_save_video = False

    def main_loop(self):
        """
            整个程序的主循环,子类的各个操作模块,建立后,把它加入task_lisk列表,由本函数负责循环执行
            子类不用再写循环。
        """
        # 通过摄像头读入一帧
        while True:
            ret, self.original_frame = self.line_camera_capture.read()  # 读取一帧
            size = (self.line_camera_width, self.line_camera_height)    # 改变大小
            self.render_frame = cv2.resize(self.original_frame, size)
            self.original_frame = self.render_frame

            # 循环任务列表,按顺序执行,ImageInit需要先于其他cv下面的对象执行
            for task in CarBase.task_list:
                tmp = []
                if isinstance(task, ImageInit):     # 没办法弄成一样,所以写了两个if
                    self.available_frame = task.execute(self.original_frame)
                elif isinstance(task, FindRoadblock):
                    task.execute(self.original_frame, None)
                else:
                    tmp.append(self.render_frame)
                    task.execute(self.available_frame, tmp)
            # 实际的小车控制操作由update控制
            self.car_controller.update()

            if self.is_open_window:     # 其实如果不开窗口,必定无法退出
                self.display_window()
            if self.is_print_frame_rate:    # 这个可以取消
                self.display_frame_rate()
            if self.is_save_video:          # 保存视频
                self.video.write(self.render_frame)

            # 检测键盘,发现按下 q 键 退出循环
            if cv2.waitKey(1) == ord('q'):
                break

    def display_window(self):
        """
            显示三个窗口,大多数情况下都是需要三个窗口,所以干脆用一个函数建立把它显示出来。
        :return:
        """
        self.display.show(self.original_frame, '原始')
        self.display.show(self.available_frame, '实际')
        self.display.show(self.render_frame, '渲染')

    def display_frame_rate(self):
        """
            打印帧速率
        """
        print("帧速度:{} 帧/秒".format(1.0/self.frame_rate_timer.duration()))
        self.frame_rate_timer.restart()

    def close(self):
        """
            一些需要手动释放的对象
        """
        self._serial.drive_motor(0, 0)  # 停车
        self._serial.drive_servo(90)    # 把舵机调到90度
        self.line_camera_capture.release()  # 释放巡线摄像头
        cv2.destroyAllWindows()     # 关闭窗口
        self.recognition.close()    # 关闭对象检测
        self._serial.close()        # 关闭窗口
        self.video.release()        # 关闭录像对象
本例演示了jetson nano 通过 Arduino 驱动小车的马达和舵机。
注意:在测试马达和舵机时,可以调用car_serial。在小车运行过程中,不要直接调用CarSerial类,
应该通过Car_controller类的函数来对小车进行控制。如果直接使用CarSerial类,可能会出现不可
预知的效果。
本例为了简单演示马达的控制,使用了sleep函数,在实际使用中,尽量不要使用sleep函数,
它会暂停程序的执行,这在一个多进程的程序中容易出现不可预知的错误。
建议使用car模块中的car_timer来控制时间的延迟。car_timer的使用可以参考use_timer.py.
"""
import time
import sys
sys.path.append("..")  # 添加模块路径
from car.car_serial import CarSerial

SERIAL = "/dev/ttyACM0"  # USB 串口
# 新建一个串口类,此类最好不要直接使用,而是通过CarController来对车子进行控制
serial = CarSerial(SERIAL, receive=True)

print("start")
time.sleep(1)  # 等待一秒

print("马达开始转动:")
time.sleep(1)

print("两个马达正向转动:")
for i in range(20, 255, 5):
    serial.drive_motor(i, i)
    time.sleep(0.3)

print("右马达正向转动,左马达停止:")

for i in range(20, 255, 5):