人形机器人全能赛openmv巡线代码

人形机器人全能赛openmv巡线代码

import sensor, image, time
from pyb import LED, millis, UART
from math import pi, isnan
import lcd


# PID类
class PID:
    _kp = _ki = _kd = _integrator = _imax = 0
    _last_error = _last_derivative = _last_t = 0
    _RC = 1 / (2 * pi * 20)

    def __init__(self, p=0, i=0, d=0, imax=0):
        self._kp = float(p)
        self._ki = float(i)
        self._kd = float(d)
        self._imax = abs(imax)
        self._last_derivative = float('nan')

    def get_pid(self, error, scaler):
        tnow = millis()
        dt = tnow - self._last_t
        output = 0
        if self._last_t == 0 or dt > 1000:
            dt = 0
            self.reset_I()
        self._last_t = tnow
        delta_time = float(dt) / float(1000)
        output += error * self._kp
        if abs(self._kd) > 0 and dt > 0:
            if isnan(self._last_derivative):
                derivative = 0
                self._last_derivative = 0
            else:
                derivative = (error - self._last_error) / delta_time
            derivative = self._last_derivative + \
                         ((delta_time / (self._RC + delta_time)) * \
                          (derivative - self._last_derivative))
            self._last_error = error
            self._last_derivative = derivative
            output += self._kd * derivative
        output *= scaler
        if abs(self._ki) > 0 and dt > 0:
            self._integrator += (error * self._ki) * scaler * delta_time
            if self._integrator < -self._imax:
                self._integrator = -self._imax
            elif self._integrator > self._imax:
                self._integrator = self._imax
            output += self._integrator
        return output

    def reset_I(self):
        self._integrator = 0
        self._last_derivative = float('nan')


class RobotControl:
    flag = 0

    def __init__(self):
        # 设置pid的初始值
        self.rho_pid = PID(p=0.4, i=0)
        self.theta_pid = PID(p=0.001, i=0)
        lcd.init()
        # 获取三种颜色的灯
        self.red_led = LED(1)
        self.green_led = LED(2)
        self.blue_led = LED(3)
        # 图像翻转

        #sensor.set_pixformat(sensor.GRAYSCALE)  # 读入灰色图片
        sensor.reset()
        sensor.set_vflip(True)
        sensor.set_hmirror(True)
        sensor.set_pixformat(sensor.RGB565)     # 读入彩色图片
        sensor.set_framesize(sensor.QQVGA)  # 160x120 设置图像大小
        #sensor.set_vflip(True)  #纵向旋转
        #sensor.set_hmirror(True)  # 水平旋转
        #sensor.set_framesize(sensor.CIF)  # 320×240
        # sensor.set_framesize(sensor.HQQQVGA)  # 80x40 设置图像大小
        sensor.skip_frames(time=2000)  # 跳过2000张图片
        # 线的阈值
        #self.THRESHOLD = (35, 100, -47, 75, -28, 87)  # 黑色
        self.THRESHOLD = (29, 0, 61, -86, -69, 55)    # 黑色0
        #self.THRESHOLD = (2, 34, 61, -83, 80, -71)    # 灰度的
        #黑色识别
        #self.THRESHOLD = (43, 100, -48, 127, -54, 127) #黑色
        #self.THRESHOLD = (88,255)
        # 通信初始化
        self.uart = UART(3, 19200)  # 注意波特率
        # 计算差值
        self.middle = 0
        # 每次检测区域 (6块)  (x, y, w, h)
        self.init_roi = [(5, 50, 70, 10), (85, 50, 70, 10),
                         (5, 70, 70, 10), (85, 70, 70, 10),
                         (5, 90, 70, 10), (85, 90, 70, 10), ]
        self.roi = []
        self.py = 5  # 找的正方形的竖向偏差
        self.line_to_middle = 10  # 正常情况下边界到中线的距离  要调的
        self.img = 0  # 每次的图片存在这,方便操作
        self.sleeptime = 0
        self.clocktime = 0
        self.blinblin = 0

    # 关灯
    def close_rgb(self):
        self.red_led.off()
        self.green_led.off()
        self.blue_led.off()

    # 开白灯
    def while_rgb(self):
        self.close_rgb()
        self.red_led.on()
        self.green_led.on()
        self.blue_led.on()

    # 开红灯
    def red_rgb(self):
        self.close_rgb()
        self.red_led.on()

    # 开绿灯
    def green_rgb(self):
        self.close_rgb()
        self.green_led.on()

    # 开蓝灯
    def blue_rgb(self):
        self.close_rgb()
        self.blue_led.on()

    def send_message(self, mes):
        """
        :param mes: 0 小左  1 左  2 右  3 直走
        :param sleeptime:   执行该动作需要睡眠的时间
        :return:
        """
        # 维护一个睡眠池
        sleep_dic = {
            0: 3950,
            1: 3950,
            2: 3950,
            3: 3950,

        }

        self.uart.write(str(mes) + "\n")
        self.blinblin += 1
        #print(self.blinblin)
        if self.blinblin%2 == 1:
            self.green_rgb()   # 闪了绿灯代表发送消息了
        else:
            self.blue_rgb()
        print(mes)
        self.sleeptime = sleep_dic.get(mes, 1000)
        #print(self.sleeptime)
        #time.sleep_ms(sleep_dic.get(mes, 1000))


    def recv_message(self):
        pass

    # 获取偏差(可能用不上)
    def get_output(self, line, img):
        output = 0
        if (line):
            # print(line)
            # 中心位置的差值
            rho_err = abs(line.rho()) - img.width() / 2
            # 计算直线的角度
            if line.theta() > 90:
                theta_err = line.theta() - 180
            else:
                theta_err = line.theta()
            # 把线画出来
            img.draw_line(line.line(), color=127)
            print(rho_err, line.magnitude(), theta_err)
            if line.magnitude() > 8:  # 表示线性回归的效果怎么样
                rho_output = self.rho_pid.get_pid(rho_err, 1)
                theta_output = self.theta_pid.get_pid(theta_err, 1)
                output = rho_output + theta_output
                # 缺运动控制
        return output

    # 获取边界点(6个)
    def get_dot(self, roi):
        most_pixels = 0
        max_x = 0
        if self.img:
            blob0 = self.img.find_blobs([self.THRESHOLD], roi=roi, pixels_threshold=2, area_threshold=2, merge=True)
            if blob0:
                for n in range(len(blob0)):
                    if blob0[n].pixels() > most_pixels:
                        most_pixels = blob0[n].pixels()
                        max_x = n
                # 将矩形标出
                self.img.draw_rectangle(blob0[max_x].x(), blob0[max_x].y(), blob0[max_x].w(), blob0[max_x].h(),
                                        color=(0, 0, 255), thickness=1, fill=False)
                # 将矩形中点标出
                self.img.draw_cross(blob0[max_x].x() + int(blob0[max_x].w() / 2), blob0[max_x].y() + int(
                                    blob0[max_x].h() / 2), color=(0, 0, 255), size=1, thickness=1)
                return blob0[max_x].x() + int(blob0[max_x].w() / 2), \
                       blob0[max_x].y() + int(blob0[max_x].h() / 2)  # 矩形中心
            else:
                return 0
        else:
            return 0

    def get_dx(self):
        left_dot_dic = {}
        right_dot_dic = {}
        middle_dot = []
        if not RobotControl.flag:
            RobotControl.flag = 1
            roi = self.init_roi
        else:
            roi = self.roi
        # 获取边界坐标
        for i in range(6):
            roii = roi[i]
            dot = self.get_dot(roii)
            #print(dot)
            if dot:
                if i % 2 == 0:
                    left_dot_dic[dot[1]] = dot[0]
                else:
                    right_dot_dic[dot[1]] = dot[0]
        # 获取中点坐标
        for y1, x1 in left_dot_dic.items():
            if right_dot_dic.get(y1, -1) != -1:
                x2 = right_dot_dic.get(y1, -1)
                middle_dot.append(((x1 + x2) // 2, y1))
                # 将路中点标出
                self.img.draw_cross((x1 + x2) // 2, y1, color=(0, 255, 0), size=1, thickness=1)
        # 中点排个序
        middle_dot = sorted(middle_dot, key=lambda x: x[1], reverse=True)
        # 清空变动的坐标列表
        self.roi = []
        if len(middle_dot) == 3:
            numy = 3
            for y1, x1 in left_dot_dic.items():
                x2 = right_dot_dic.get(y1, -1)
                if x1 >= 5:
                    x1 -= 5
                else:
                    x1 = 0
                if x2 >= 160 - 70 - 1:
                    x2 = 89
                self.roi.append((x1, y1 - self.py, 60, 10))
                self.roi.append((x2, y1 - self.py, 60, 10))
            dx = middle_dot[0][0] - middle_dot[2][0]
            middle_x = (middle_dot[0][0] + middle_dot[1][0] + middle_dot[2][0])//3
        elif len(middle_dot) == 2:
            numy = 2
            RobotControl.flag = 0
            dx = middle_dot[0][0] - middle_dot[1][0]
            middle_x = (middle_dot[0][0] + middle_dot[1][0])//2
        elif len(middle_dot) == 1:
            numy = 1
            RobotControl.flag = 0
            dx = 0
            try:
                middle_x = middle_dot[0][0]
            except:
                middle_x = 80   # 如果没找到中线的话返回中线值即可
        else:
            RobotControl.flag = 0
            numy = 0
            middle_x = 0
            if not left_dot_dic:
                dx = -1
            else:
                dx = -2

        return dx, middle_x, numy

    def run(self):
        while 1:
            img = sensor.snapshot().binary([self.THRESHOLD], invert=True)
            line1 = img.get_regression([(100, 100)], roi=(0, 0, 80, 120), robust=True)
            line2 = img.get_regression([(100, 100)], roi=(80, 0, 80, 120), robust=True)
            output1 = self.get_output(img, line1)
            output2 = self.get_output(img, line2)
            if line1 and line2:
                img.draw_line(((line1.x1() + line2.x1()) // 2, (line1.y1() + line2.y1()) // 2,
                               (line1.x2() + line2.x2()) // 2, (line1.y2() + line2.y2()) // 2),
                              color=(255, 0, 0))
            elif line1:
                img.draw_line((line1.x1() + self.middle, line1.y1(), line1.x2() + self.middle, line1.y2()),
                              color=(255, 0, 0))
            elif line2:
                img.draw_line((line2.x1() - self.middle, line2.y1(), line2.x2() - self.middle, line2.y2()),
                              color=(255, 0, 0))
            else:
                pass

    def run2(self):
        self.clocktime = time.time_ns()
        #print(self.clocktime)
        while 1:
            self.img = sensor.snapshot()
            #self.img.rotation_corr(x_rotation=45)
            dx, middle_x, numy = self.get_dx()
            #print(dx, middle_x, numy)
            #print("dx:", dx, "middle_x:", middle_x)
            #print(time.time_ns())
            #print(self.clocktime)

            if (time.time_ns() - self.clocktime)*0.000001 >= self.sleeptime - 100:
                print((time.time_ns() - self.clocktime)*0.000001)
                self.clocktime = time.time_ns()
                if numy == 2:
                    dx *= 2
                elif numy == 1 and middle_x <= 80:
                    self.send_message(1)

                elif numy == 1 and middle_x >= 80:
                    self.send_message(3)

                elif numy == 0:
                    if dx == -1:
                        self.send_message(1)
                    else:
                        self.send_message(2)
                else:
                    if dx >= 5: # 小左
                        self.send_message(0)
                    elif dx <= -10:  # 右
                        self.send_message(2)
                    else:   # 直行
                        self.send_message(3)
            lcd.display(self.img)

if __name__ == '__main__':
    robot1 = RobotControl()
    robot1.run2()
posted @ 2022-11-06 18:47  ihuahua1415  阅读(138)  评论(0)    收藏  举报
*/