[Киберспорт 2022] Кто-то едет, кто-то бегает, а кто-то не умеет считать 5 секунд

Предисловие: Эта работа является первым призом Конкурса электронных дизайнеров провинции Сычуань 2022. Она может стабильно решать все четыре задачи, но есть проблема с точностью парковочного расстояния. Эта статья познакомит вас с общей дизайнерской идеей работы, ключевыми алгоритмами управления и другими техническими моментами, а также даст ссылку на скачивание проекта. В то же время я участвовал в соревнованиях по электромобилям 2021 г., 17-м конкурсе умных автомобилей и конкурсе электромобилей 2022. В конце статьи я расскажу о своем личном опыте. Конечно, вы также можете написать мне личное сообщение (звуковая станция с тем же именем), и я обязательно отвечу, когда у меня будет время.

Оглавление

1. Общий дизайн мышления

1.1 Структура проектирования главного и подчиненного автомобилей

1.2 Дизайнерская идея всей работы

2. Конкретная реализация каждого функционального блока

2.1 Межмодульная связь

2.2 Структура программы автомобиля

2.3 Скорость работы в замкнутом контуре

2.4 Распознавание элементов площадки openMV

2.5 Проведение проверки линии

3. Идеи реализации задачи

4. Личный опыт

1. Общий дизайн мышления

1.1 Структура проектирования главного и подчиненного автомобилей

        вот изображение. Закругленный прямоугольник на рисунке указывает на модуль, а стрелка указывает направление сигнала (включая питание) Соответствующие значения стрелок каждого цвета показаны на рисунке Все цифры являются одиночными стрелками, то есть сигнал направление потока однонаправленное. Звуковой сигнал и светодиодный индикатор на рисунке не показаны.

 Рис. 1. Блок-схема основного транспортного средства.

        На рисунке 1 показана блок-схема конструкции основного транспортного средства с использованием msp430f5529 в качестве основного контроллера, openMV используется для распознавания элементов поля, он упаковывает данные после обработки изображения и отправляет их на основной контроллер, а основной контроллер будет обрабатывать полученные данные openMV, затем измените рабочий цикл ШИМ и выведите его на модуль привода двигателя tb6612. Модуль привода усиливает мощность управляющего сигнала, чтобы заставить двигатель вращаться. В то же время главный контроллер отправляет соответствующие сигналы подчиненному транспортных средств через Bluetooth. Батарея представляет собой батарею 3S\1100 мАч, а импульсный модуль питания используется для обеспечения стабильного питания 5 В.

Рис. 2 Блок-схема конструкции ведомого вагона

        На рис. 2 показана блок-схема ведомой машины, которая аналогична ведущей машине, за исключением того, что ведомая машина пассивно получает данные, отправленные ведущей машиной из модуля Bluetooth, и добавляет модуль лазерного дальномера для соответствия требованиям расстояния. между двумя автомобилями.

        Примечание:В этой блок-схеме не рассматривается напряжение связи между модулями.Во-первых, потому, что многие модули имеют свои собственные микросхемы регулятора напряжения, а во-вторых, потому что между модулями существуют различия в рабочем напряжении.Конструкция должна учитываться в соответствии с фактическими ситуация. В то же время плату ti особенно легко сжечь.Рекомендуется добавлять резисторы от нескольких до десятка кОм (я использовал резистор 4,7 кОм) между выводами и модулем для ограничения тока при проектировании схемы.

        С точки зрения механической конструкции оба транспортных средства являются трехколесными, а рулевое управление тележки управляется с помощью дифференциальной скорости.

Рисунок 3 Принципиальная схема шасси тележки

 

Рисунок 4 Физическая карта автомобиля

        Не беспокойтесь о неряшливом внешнем виде машины.Я умная машина, и я не готовлюсь к гонкам на электротяге.Компоненты этих двух машин в основном подобраны и проституированы другими. 

1.2 Дизайнерская идея всей работы

        Общая конструктивная идея работы очень проста. Две машины патрулируют линию независимо друг от друга. Ведущая машина только отправляет инструкции ведомой машине в определенный момент, и все задачи могут быть выполнены с соответствующей логикой управления два авто. Чтобы быть более конкретным, во-первых, ведущий и ведомый транспортные средства имеют замкнутый цикл на каждой скорости , так что два транспортных средства могут двигаться с одинаковой и точно контролируемой скоростью, а затем идентифицировать элементы поля через openMV и отправлять обработанные данные. данные на главный контроллер.Два автомобиля могут выполнять основную задачу патрулирования линии , и следующим шагом является объединение двух автомобилей, то есть главный автомобиль отправляет информацию на подчиненный автомобиль в определенный момент , так что они могут сотрудничать, чтобы патрулировать линию, а затем комбинировать конкретную логику управления для выполнения каждой задачи.

2. Конкретная реализация каждого функционального блока

        Структура аппаратного проектирования работы и идея дизайна всей работы были представлены ранее, затем детали реализации будут постепенно улучшаться, включая связь между модулями, программную структуру автомобиля, работу с обратной связью. скорость, распознавание элементов сайта openMV и реализация линейной инспекции. Контента много, и вы можете перейти к интересующей области через оглавление в верхней части статьи.

2.1 Межмодульная связь

        Зачем сначала вводить коммуникацию между модулями, потому что это очень важно, можно сказать, что коммуникация между модулями может дать вдвое больший результат с половиной усилий. Важным моментом этой работы является то, что все сигналы являются односторонними.openMV только отправляет данные на главный контроллер, а главный контроллер не отправляет данные в openMV.Мастер-автомобиль отправляет данные только в подчиненный автомобиль, а подчиненный автомобиль не отправляет данные. отправить данные мастер-автомобилю.данные. Что касается причины, то она, конечно, такая простая. Некоторые люди могут подумать, что будут ошибки данных. Можете не сомневаться в этой проблеме. Не стоит так недоверчиво относиться к протоколу связи.

Рисунок 5 Связь между основными модулями

        Ссылаясь на рисунок выше, я кратко представлю, что делает связь между модулями.Основных четыре (на самом деле их всего два, а последние два просто используются для зарядки):

        1. Связь между ведущим автомобилем и подчиненным автомобилем использует протокол связи последовательного порта (сопряжение последовательного порта Bluetooth), главный автомобиль каждый раз отправляет один байт данных в подчиненный автомобиль, включая восемь инструкций, 1-4 означает, что он должна быть выполнена следующая задача (четыре задачи), 5 означает запуск ведомой машины, 6 означает остановку ведомой машины, 7 означает паузу ведомой машины (для четвертой задачи), 8 означает запуск после приостановки ведомой машины (также для первое задание).

например:

    USCI_A_UART_transmitData(USCI_A0_BASE,work);//向从机发送work,work是任务序号
    delay_ms(500);
    USCI_A_UART_transmitData(USCI_A0_BASE,5);//向从机发送开始信号
    delay_ms(100);

        2. Связь между openMV и главным контроллером использует протокол связи через последовательный порт.openMV отправляет данные только на главный контроллер, пять байт каждый раз, формат 0x2c 0x12 data1 data2 data3, 0x2c и 0x12 являются заголовками кадров для синхронной передачи данных , data1 представляет элементы сайта, включая шесть типов: 0 обычная линия патрулирования, 1 обычная парковка, 2 въезд на развилке, 3 выезд на развилке, 4 нештатная парковка, 5 поворот, data2 и data3 представляют собой центральное значение черной линии , Почему их две?Обычно есть только одна, но будет две черные линии, когда автомобиль входит и выходит из трехразвилки.В это время абсцисса центра двух черных линий должна быть направлена ​​на главную контроллер.

Функция отправки данных openMV:

# 通信协议
def send_data_packet(x1,y1,z1):
    data =struct.pack("<bbbbb",                #格式为五个字符
                   0x2C,                       #帧头1
                   0x12,                       #帧头2
                   int(x1), # up sample by 4   #数据1,道路元素
                   int(y1), # up sample by 4   #数据2,黑线横坐标
                   int(z1),                    #数据3,另一条黑线横坐标,只有一条线时为0
                   )
    uart.write(data)

Также прикрепите программу приема микроконтроллера:

/************************************openMV数据接收程序*****************************************/
unsigned char openmv_data[3]={0,0,0};
#pragma vector=USCI_A1_VECTOR
__interrupt void USCI_A1_ISR (void)
{
    uint8_t receivedData = 0;//接收原始数据
    static char state=0;//因为要进行帧同步,所以需要记录字节顺序
    switch (__even_in_range(UCA1IV,4))
    {
        case 2:
            receivedData = USCI_A_UART_receiveData(USCI_A1_BASE);//接收字节数据
            if(receivedData==0x2c&&state==0)//判断是不是第一个帧头
                state++;
            else if(receivedData==0x12&&state==1)//判断是不是第二个帧头
                state++;
            else if(state>1)//帧头判断无误就开始接收数据
            {
                openmv_data[state-2]=receivedData;
                if(state==4)//只有三个数据,加上帧头共五个字节,所以state就到4
                    state=0;
                state++;
            }
            break;
        default:
            break;
    }
}

       Как упоминалось ранее, протоколу связи следует доверять.На самом деле, частота однобайтовых битовых ошибок последовательного порта очень низкая при скорости 115200 бод, что практически незначительно.Но когда нам нужно отправить несколько данных в одних и тех же данных , нам нужно использовать Frame Synchronization, то есть добавить два заголовка кадра, почему их два? Поскольку частота ошибок синхронизации одного заголовка кадра составляет 1/256 (без учета ошибки в процессе передачи), вероятность ошибок все же выше, а частота ошибок синхронизации двух заголовков кадров составляет 1/65536, что практически невозможно. делать ошибки Насчет трех и более Да, но не обязательно.

        3. Связь между ведомой машиной и модулем лазерной дальнометрии использует IIC.Здесь главный контроллер только считывает исходные данные с модуля лазерной локации, и я не знаю, как написать код решения.Я скопировал его с магазин сокровищ. Вы можете спросить, почему бы не использовать ультразвуковой модуль, почему бы не использовать связь через последовательный порт, ну я слишком хорош, код ультразвукового модуля не будет трансплантирован, что касается последовательного порта, эммм, у msp430f5529 всего два последовательных порта. . . . .

        4. Связь между контроллером и tb6612, ШИМ, что такое ШИМ, как его использовать для управления двигателем, вы можете прочитать в этом блоге http://t.csdn.cn/rkT8p

        Позвольте мне сказать еще несколько слов: для электронных игр или для одночиповых микрокомпьютеров есть три широко используемых протокола связи: последовательный порт, IIC и SPI, Он имеет соответствующую физическую схему, программная реализация не относится к физической схеме, но могут быть смоделированы с помощью кода), а последние два обычно представляют собой программные реализации с учетом гибкости. Достаточно понимать эти три типа, знать принцип и уметь трансплантировать код.Что касается CAN-порта (протокол связи, используемый DJI M2006), RS485 и т.д., то достаточно его понять, и мы будем говорить об этом, когда будем использовать его.

2.2 Структура программы автомобиля

 Рис. 6 Структурная схема программы автомобиля

        Схема структуры программы показана на рисунке 4, где дана только основная структура программы, без рассмотрения программы и функции openMV. Для следующей автомобильной системы после подключения Bluetooth вы можете использовать кнопку, чтобы выбрать задачу и отобразить ее через oled.После подтверждения задачи главная машина отправит выбранную задачу и команду запуска подчиненной машине. через Bluetooth.После того, как ведущий автомобиль отправляет команду запуска, а подчиненный автомобиль получает команду запуска После инструкции скорость будет выбрана в соответствии с задачей (скорость здесь относится к целевой скорости после замкнутого контура скорости, который будет введен подробно позже), а затем будет выполняться соответствующая программа в соответствии с выбранной задачей, и, наконец, оба транспортных средства остановятся после того, как основное транспортное средство распознает остановку (период управления составляет 20 мс).

Ниже приведен программный код двух транспортных средств:

Основные рамки автомобильной программы:

#include "driverlib.h"
char work=1;//选择第几题
unsigned int diatance=0;
int main(void)
{
/**************************************初始化部分*************************************/
    char txt[30];
    WDT_A_hold(WDT_A_BASE);
    SystemClock_Init();//时钟初始化
    led_init();//led初始化
    key_init();//按键初始化
    OLED_Init();//oled初始化
    OLED_Clear();//清屏
    UART_Init(USCI_A0_BASE,115200);//蓝牙初始化
    UART_Init(USCI_A1_BASE,115200);//openMV初始化
    motor_init();//电机初始化
    encoder_init();//编码器初始化
    Timer_A_Init(1);//定时器中断初始化
    __bis_SR_register(GIE);
/**************************************按键选择题目部分*************************************/
    while(1)//选择题目并显示参数
    {
        if(!GPIO_getInputPinValue(GPIO_PORT_P1, GPIO_PIN1))//按下开始运行
            break;
        if(!GPIO_getInputPinValue(GPIO_PORT_P2, GPIO_PIN1))//按下选择题目
        {
            delay_ms(15);//消抖
            if(!GPIO_getInputPinValue(GPIO_PORT_P2, GPIO_PIN1))
                work++;
        }
        if(work==5)//循环选择
            work=1;
        sprintf(txt,"work:%d    ",(int)work);//显示题目
        OLED_ShowString(0,0, (unsigned char *)txt,8);
        sprintf(txt,"middle:%d    ",(int)openmv_data[0]);//显示openMV中线数据
        OLED_ShowString(0,2, (unsigned char *)txt,8);
    }
/**************************************发送题目与发车指令部分*************************************/
    USCI_A_UART_transmitData(USCI_A0_BASE,work);//向从机发送work
    delay_ms(500);
    USCI_A_UART_transmitData(USCI_A0_BASE,5);//向从机发送开始信号
    delay_ms(100);
/**************************************根据题目选择速度部分*************************************/
    switch(work)//根据题目选择速度选择
    {
    case 1:aim_speed=11.05;break;//题目一
    case 2:aim_speed=18.35;break;//题目二
    case 3:aim_speed=20;break;//题目三
    case 4:aim_speed=18.35*2;break;//题目四
    default:while(1);
    }
    OLED_Clear();
/**************************************根据题目选择执行代码部分*************************************/
    while(1)
    {
        if(timer_20ms)//主控制函数,定时器中断20ms
        {
            switch(work)//题目选择
            {
            case 1:control_1();break;//题目一
            case 2:control_2();break;//题目二
            case 3:control_3();break;//题目三
            case 4:control_4();break;//题目四
            }
            GPIO_toggleOutputOnPin(GPIO_PORT_P4, GPIO_PIN7);//指示灯,程序正常运行可以看到灯闪烁
            timer_20ms=0;//清空标志位
        }
    }
}

Из рамок автомобильной программы:

#include "driverlib.h"
char work=1;//从机工作程序
unsigned int diss=0;//激光测距显示距离
int main(void)
{
/**************************************初始化*************************************/
    char txt[30];
    WDT_A_hold(WDT_A_BASE);
    SystemClock_Init();//时钟初始化
    led_init();//led初始化
    key_init();//按键初始化
    I2C_GPIO_Config();//激光测距
    OLED_Init();//oled初始化
    OLED_Clear();//清屏
    UART_Init(USCI_A0_BASE,115200);//蓝牙初始化
    UART_Init(USCI_A1_BASE,115200);//openMV初始化
    motor_init();//电机初始化
    encoder_init();//编码器初始化
    Timer_A_Init(1);//定时器中断初始化
    __bis_SR_register(GIE);
/**************************************获取题目和发车指令*************************************/
    while(1)
    {
        if(co_data<=4) work=co_data;//获取工作模式
        else if(co_data==5) break;//跳出循环车跑
        takeRangeReading(0Xe0);//读取前方物体距离
        requestRange((0Xe0+1),&diss);
        sprintf(txt,"work:%d    ",work);
        OLED_ShowString(0,0, (unsigned char *)txt,8);
        sprintf(txt,"middle:%d    ",openmv_data[0]);
        OLED_ShowString(0,2, (unsigned char *)txt,8);
        sprintf(txt,"dis:%d    ",diss);
        OLED_ShowString(0,4, (unsigned char *)txt,8);
    }
/**************************************根据题目选择速度*************************************/
    switch(work)//根据题目选择速度选择
     {
         case 1:aim_speed=11.05;break;//题目一
         case 2:aim_speed=26;break;//题目二,追上前26,追上后18.35
         case 3:aim_speed=20;break;//题目三
         case 4:
             {
                 aim_speed=18.35*2-1;//跑快了速度不准,需要校正
                 turn_.kp=0.25;//电机比较辣鸡,1m速度时要重调参数
                 turn_.kd=0.4;
                 break;//题目四
             }
         default:while(1);
     }
    OLED_Clear();
/**************************************根据题目选择执行代码部分*************************************/
    while(1)
    {
        if(timer_20ms)//控制周期20ms
        {
            switch(work)//选择题目
            {
            case 1:control_1();break;//题目一
            case 2:control_2();break;//题目二
            case 3:control_3();break;//题目三
            case 4:control_4();break;//题目四
            }
            GPIO_toggleOutputOnPin(GPIO_PORT_P4, GPIO_PIN7);//指示灯
            timer_20ms=0;//清空标志位
        }
    }
}

        Еще несколько слов: При выполнении алгоритмов управления и алгоритмов фильтрации цикл управления очень важен, что конкретно отражается в длине цикла управления и инвариантности цикла.Теоретически, чем короче цикл управления, тем лучше, но это на практике это не так, потому что цикл управления ограничен частотой механического отклика, датчиком, производительностью контроллера и т. д., поэтому цикл управления можно контролировать только в определенном диапазоне как можно короче.

        Что касается того, почему цикл управления должен оставаться неизменным, то, говоря простым языком, параметры отлаживаются под определенный цикл управления, и если цикл изменится, то выходной эффект не оправдает ожиданий. Это особенно заметно в цифровых фильтрах.При проектировании цифровых фильтров следует учитывать частоту среза.Аналоговая частота f1 фильтра = частота дискретизации f*цифровая частота f2.Частота дискретизации представляет собой период управления, который изменяет аналоговую частоту среза. , Частота также изменяется, и эффект фильтра напрямую изменяется.

2.3 Скорость работы в замкнутом контуре

        Замкнутая петля скорости уже упоминалась ранее, а почему, грубо говоря, после того, как замкнутая петля скорости выполнена, машина может ехать сколь угодно быстро, таким образом, вы обнаружите, что первый вопрос не имеет значения. вообще нужно измерение расстояния, просто используя замкнутый контур скорости Это можно сделать.Конечно, это также связано с точностью замкнутого контура скорости, которую вы делаете.Если вы делаете это достаточно хорошо, вам не нужно измерение расстояния для 1, 3 и 4 вопросы. Вы даже можете добавить гироскоп (не в этой работе) и использовать его угол рыскания и замкнутый контур скорости (непосредственно использовать энкодер) для выполнения векторного интегрирования, чтобы вы могли получить текущие координаты относительно начальной точки, которая называется «Глобальное позиционирование».

        Поговорив о функции замкнутого контура скорости, давайте подробно поговорим о ее реализации.

        Прежде чем говорить о замкнутом контуре скорости, вам необходимо иметь определенные базовые знания, в основном знания, связанные с PID, если вы не понимаете, пожалуйста, Baidu это самостоятельно. Когда дело доходит до скорости, две вещи, которые нельзя замкнуть и закрыть, это двигатель и энкодер.Мотор - это управляемый объект, вход - эквивалентное напряжение ШИМ, а выход - скорость (не путайте с меня, это нормально, если вы говорите, что это крутящий момент), нам нужно Есть два способа заставить скорость достичь желаемого значения, например, 200 об / мин. Один состоит в том, чтобы установить точную динамическую модель двигателя, а затем дать ШИМ-эквивалент напряжение в соответствии с динамической моделью и нагрузкой.Эммм, я все равно не могу этого сделать; Другой очень простой и практичный, напрямую используйте датчик для измерения скорости и получите ошибку после того, как сделаете разницу между ней и целевой скоростью , введите ошибку в инкрементальный ПИ-регулятор, и выход контроллера воздействует на модуль привода двигателя tb6612, tb6612. Мощность управляющего сигнала усиливается для привода двигателя, и параметры контроллера могут быть скорректированы для реализации замкнутого контура скорости .

Рис. 7 Блок-схема замкнутого контура скорости

         Процесс управления известен, так как же измерить скорость? Здесь используется квадратурный энкодер Холла, и его выходные сигналы представляют собой два сигнала прямоугольной формы с разностью фаз 90°, которые мы называем фазой A и фазой B. Если фаза A опережает фазу B, она будет вращаться вперед, в противном случае, он будет реверсировать, частота которого пропорциональна скорости.

Рис. 8. Диаграмма сигнала квадратурного энкодера 

        Итак, как читать квадратурный сигнал с помощью MCU? Существует два надежных метода.Первый – аппаратный метод чтения, который поставляется с некоторыми однокристальными микрокомпьютерами.Преимущество заключается в том, что он реализуется аппаратно, не потребляет программных ресурсов, имеет высокую точность и имеет широкий диапазон скоростей. Измерение. Недостаток в том, что он требует таймера, и многие микрокомпьютеры с одним чипом не имеют этого метода. Функция, вторая заключается в использовании внешнего прерывания для чтения, наблюдения за формой волны, мы можем знать, что когда вращение вперед и Фаза A находится на переднем фронте, фаза B находится на высоком уровне, и когда инверсия реверсирована и фаза A находится на переднем фронте, фаза B находится на низком уровне, так что нарастающий фронт фазы A может быть установлен в качестве внешнего источника триггера прерывания, а после триггера может быть прочитан уровень фазы B. Если он высокий, счетчик будет увеличен на 1, а если он низкий, счетчик будет уменьшен на 1. Значение счета в единицу времени — это скорость передачи битов, положительное и отрицательное значение указывает направление. Преимущество этого метода в том, что он очень универсален, почти все однокристальные микрокомпьютеры имеют функцию внешнего прерывания, а недостаток в том, что он потребляет программные ресурсы, а скорость может привести к зависанию программы.

Код для расчета количества импульсов в программе:

#pragma vector=PORT2_VECTOR     // P2口中断源
__interrupt
void Port_2 (void)              // 声明一个中断服务程序,名为Port_2()//将其作为A相,用于触发中断
{
    if(GPIO_getInputPinValue(GPIO_PORT_P2, GPIO_PIN5))//读取B相,高电平计数加
        counter_right++;
    else//低电平则计数减
        counter_right--;
    GPIO_clearInterrupt(GPIO_PORT_P2, GPIO_PIN4);
}

Скажи еще несколько слов:

        1. Существует много типов энкодеров, квадратурных энкодеров (распространенные холловские и фотоэлектрические, первые имеют низкую точность, а вторые — высокую точность. Не рекомендуется использовать внешние прерывания для считывания фотоэлектрических энкодеров, т.к. они слишком потребляют большая вычислительная мощность), энкодер направления (можно понимать как квадратурный энкодер, двухфазный триггер AB через триггер D становится одним импульсом и указывает направление с положительным и отрицательным уровнями), магнитный энкодер (обычно используется в бесщеточном двигателе FOC), и т. д.;

        2. Метод измерения скорости приведен выше.Внимательные друзья могут обнаружить, что точность измерения скорости этого метода может быть выше, то есть также используется нарастающий фронт фазы B, так что можно получить двойную точность.У меня есть в проекте этого не сделано, метод двойной точности используется для экономии вычислительной мощности для msp430, но оказывается, что одинарной точности вполне достаточно;

        3. Есть много типов моторов, по возможности рекомендуется использовать сразу готовый мотор, например DJI M2006 (без рекламы, он действительно прост в использовании).

2.4 Распознавание элементов площадки openMV

        Теперь поговорим об идентификации элементов площадки, которая относится к категории видения, но не пугайтесь, игра не требует продвинутых визуальных знаний, а базовые знания можно напрямую перенести на официальный сайт openMV . Vision требует фактической отладки на месте, а на код сильно влияет высота установки и угол наклона камеры, так что здесь только осуществимая идея, не слишком объясняя код этого проекта.

        Прежде всего, нам необходимо проанализировать конкретную ситуацию. На примере этой работы элементы, которые нам нужны для принятия решений, включают въезд в Санчу, выезд из Санчи, движение прямо, повороты, знаки остановки и знаки парковки. Первый шаг - определить Положение установки камеры, высота, угол и не меняйте без необходимости! ! ! Следующим шагом является обработка изображения.Как правило, для распознавания цвета можно использовать изображения в градациях серого, а затем изображение фильтруется и бинаризируется, так что получается черно-белое бинарное изображение.

        Далее следует ключевой момент: общее распознавание дорог может быть выполнено с помощью традиционного зрения, не рассматривайте проверку линии нейронной сети, проверку линии нейронной сети как проверку линии God TM. Вообще говоря, метод добавления окон к изображению используется для идентификации элементов.Что такое окно, это добавить несколько кадров к изображению, а затем обрабатывать цветовые блоки в каждом кадре отдельно, и подсчитывать цветовые блоки, соответствующие требованиям в каждом окне Количество и размер блоков в сочетании с функциями цветовых блоков в нескольких окнах могут всесторонне определить, какой элемент сайта находится в данный момент. Например, 5 окон в этом проекте показаны на рисунке ниже.

 Рис. 9 Изображение этой работы в окне

        Фирменный стиль лежит в основе видения и является наиболее гибкой частью дизайна. Многие проблемы могут быть легко решены после идентификации.Что касается метода, в этой статье представлен возможный метод, и должны быть другие лучшие методы.Друзья также могут дать нам свой совет! Наконец, упакуйте обработанные данные и отправьте их на главный контроллер.Метод отправки см. в разделе 2.1 Межмодульное взаимодействие в этой статье.

Прикрепите код визуальной части этой работы:

import sensor, image, time
from pyb import UART
from pyb import LED
import struct

sensor.reset()
sensor.set_pixformat(sensor.GRAYSCALE)
sensor.set_framesize(sensor.QQVGA)
sensor.skip_frames(time = 2000)
black_threshold = (0, 70)#二值化阈值
line_roi = (0, 100, 160, 10)#窗口1
line_roi2 = (0, 50, 160, 10)#窗口2
line_roi3 = (0, 20, 160, 10)#窗口3
left_roi = (25, 0, 8, 120)#窗口4
right_roi = (135, 0, 8, 120)#窗口5
uart = UART(3, 115200)

# 通信协议
def send_data_packet(x1,y1,z1):
    data =struct.pack("<bbbbb",                #格式为五个字符
                   0x2C,                       #帧头1
                   0x12,                       #帧头2
                   int(x1), # up sample by 4   #数据1,道路元素
                   int(y1), # up sample by 4   #数据2,黑线横坐标
                   int(z1),                    #数据3,另一条黑线横坐标,只有一条线时为0
                   )
    uart.write(data)


#求绝对值
def abs_(x1,x2):
    xx = x1-x2
    if(xx>0):
        return xx
    else:
        return -xx

flag = 0#0正常巡线,1正常停车,2岔路口in,3岔路口out,4非正常停车,5转弯
xx1=0
xx2=0
while(True):
    img = sensor.snapshot()
    img_black=img.binary([threshold])
    img_black.mean(2)
    blobs_low = img.find_blobs([black_threshold], roi = line_roi, pixels_threshold = 150)
    blobs_high = img.find_blobs([black_threshold], roi = line_roi2, pixels_threshold = 150)
    blobs_left = img.find_blobs([black_threshold], roi = left_roi, pixels_threshold = 100)
    blobs_right = img.find_blobs([black_threshold], roi = right_roi, pixels_threshold = 100)
    blobs_high2 = img.find_blobs([black_threshold], roi = line_roi3, pixels_threshold = 150)


    # 基础题停车判定
    # 使用下面的框进行判定,是否能够找到停车标志
    if(blobs_low and blobs_high):
        #max_blob = find_biggest_blobs(blobs_low)
        if(blobs_low[0].w()>0.5*img.width() and len(blobs_high)==1 and blobs_low[0].w()<0.8*img.width()):#停车0.3m下
            print("stop")
            flag = 1
            xx1 = 80
            xx2 = 0
        elif(len(blobs_high2)==0 and blobs_high[0].w()>0.6*img.width()):#提升停车
            print("stopwww")
            flag = 4
            xx1 = 80
            xx2 = 0
        elif(len(blobs_high)==1 and len(blobs_low)==1):#正常巡线
            len_h_l=abs_(blobs_high[0].cx(),blobs_low[0].cx())
            if(len_h_l<5):
                print("line")
                flag = 0
                img.draw_cross(blobs_high[0].cx(), blobs_high[0].cy(), (255,255,255), 30)
                xx1 = blobs_high[0].cx()
                xx2 = 0
            else:
                print("line_wan")
                flag = 5
                img.draw_cross(blobs_high[0].cx(), blobs_high[0].cy(), (255,255,255), 30)
                xx1 = blobs_high[0].cx()
                xx2 = 0
        elif(len(blobs_high)==2 and len(blobs_low)==2):#一类出入三岔
            len_high = abs_(blobs_high[0].cx(),blobs_high[1].cx())
            len_low = abs_(blobs_low[0].cx(),blobs_low[1].cx())
            if(len_high>len_low):
                print("in")
                flag = 2
                img.draw_cross(blobs_high[0].cx(), blobs_high[0].cy(), (255,255,255), 30)
                img.draw_cross(blobs_high[1].cx(), blobs_high[1].cy(), (255,255,255), 30)
                xx1 = blobs_high[0].cx()
                xx2 = blobs_high[1].cx()
            else:
                print("out")
                flag = 3
                img.draw_cross(blobs_high[0].cx(), blobs_high[0].cy(), (255,255,255), 30)
                img.draw_cross(blobs_high[1].cx(), blobs_high[1].cy(), (255,255,255), 30)
                xx1 = blobs_high[0].cx()
                xx2 = blobs_high[1].cx()
        elif(len(blobs_high)==2 and len(blobs_high2)==2):#另一类出入三岔
            len_high = abs_(blobs_high[0].cx(),blobs_high[1].cx())
            len_high2 = abs_(blobs_high2[0].cx(),blobs_high2[1].cx())
            if(len_high<len_high2):
                print("in")
                flag = 2
                img.draw_cross(blobs_high[0].cx(), blobs_high[0].cy(), (255,255,255), 30)
                img.draw_cross(blobs_high[1].cx(), blobs_high[1].cy(), (255,255,255), 30)
                xx1 = blobs_high[0].cx()
                xx2 = blobs_high[1].cx()
            else:
                print("out")
                flag = 3
                img.draw_cross(blobs_high[0].cx(), blobs_high[0].cy(), (255,255,255), 30)
                img.draw_cross(blobs_high[1].cx(), blobs_high[1].cy(), (255,255,255), 30)
                xx1 = blobs_high[0].cx()
                xx2 = blobs_high[1].cx()
        elif(len(blobs_high)==2 and blobs_right ):#出弯
            print("out")
            flag = 3
            img.draw_cross(blobs_high[0].cx(), blobs_high[0].cy(), (255,255,255), 30)
            img.draw_cross(blobs_high[1].cx(), blobs_high[1].cy(), (255,255,255), 30)
            xx1 = blobs_high[0].cx()
            xx2 = blobs_high[1].cx()
        elif(len(blobs_high)==2 and blobs_left):#进弯
            print("in")
            flag = 2
            img.draw_cross(blobs_high[0].cx(), blobs_high[0].cy(), (255,255,255), 30)
            img.draw_cross(blobs_high[1].cx(), blobs_high[1].cy(), (255,255,255), 30)
            xx1 = blobs_high[0].cx()
            xx2 = blobs_high[1].cx()

        send_data_packet(xx1,xx2,flag)

    # 画出一个矩形,便于查看
    #send_data_packet(128,159,2)
    img.draw_rectangle(line_roi)
    img.draw_rectangle(line_roi2)
    img.draw_rectangle(line_roi3)
    img.draw_rectangle(left_roi)
    img.draw_rectangle(right_roi)


Скажи еще несколько слов:

        1. Обычно используемые модули зрения включают в себя, как правило, openMV и k210.Первый больше подходит для традиционного зрения, а второй больше подходит для нейронных сетей.Большой разницы между ними нет (оригинальный объектив k210 может иметь темные углы), и его можно запустить на плате Linux, если это возможно, opencv, конечно, лучше;

        2. Самая частая проблема, с которой сталкивается зрение, это плохая помехозащищенность, с одной стороны, это отражается на освещенности объекта, а с другой - на объекте. Решение первого — ручная регулировка порога на месте и использование автоматического порога (типа метода Оцу), особенно эффективного решения для второго пока не нашел, эффективные решения — регулировка света на месте чтобы сделать его как можно более равномерным и регулируя угол камеры., найти лучший угол, добавить поляризатор, но затемнить изображение.

2.5 Проведение проверки линии

        Видение, замкнутый контур скорости и т. д. были представлены ранее, а конкретная реализация части, следующей за линией, будет представлена ​​позже. Автомобиль в этой работе использует метод поворота с дифференциальной скоростью, openMV отправляет обработанные данные на главный контроллер, основной контроллер извлекает абсциссу черной линии патрульной линии и делает разницу со значением средней точки, чтобы получить ошибку ошибки , и вводит ошибку в позиционное управление PD. Выходной сигнал контроллера добавляется и вычитается из целевой скорости двух двигателей, и отслеживание линии может быть реализовано путем настройки параметров контроллера.

Рисунок 10. Блок-схема реализации проверки линии

3. Идеи реализации задачи

        Конкретная реализация в том, что благожелательный видит благожелательный, а мудрый видит мудрость, код слишком запутан, а текст не так просто описать (на самом деле, это было слишком долго, и я забыл, что писал). Подводя итог, основная машина просто едет сама по себе, а ведомая машина ездит сама по себе, только если в этом нет необходимости, при необходимости измеряя расстояние для получения инструкций от основной машины.

4. Личный опыт

        Если подумать, у меня больше никогда не будет возможности участвовать в студенческих киберспортивных соревнованиях, жаль, что мне не удалось выиграть национальную награду, и я рад, что выбрал именно киберспортивные соревнования. Мое первоначальное намерение участвовать в соревновании по киберспорту заключалось в том, что я чувствовал, что слишком хорош в нем и хотел стать сильнее, поэтому я случайным образом набрал двух товарищей по команде для участия в национальном соревновании 2021. Однако мои товарищи по команде не были заинтересованы в киберспорте вообще, и я был крайне озабочен и неуверен в себе.В финальном национальном соревновании я взял только вторую провинцию. В этом году в соревнованиях по электромобилям нет национальной награды, поэтому я отправился участвовать в соревновании умных автомобилей, и мне посчастливилось попасть на бедра двух надежных товарищей по команде и получить первое национальное призовое место. После Западной конференции я участвовал в соревнованиях по киберспорту 2022. При этом я получил провинциальное, и мне вернули все закуски, которые я не ел в прошлом году.

        Киберспорт научил меня многому, мягкому, жесткому и механическому. В то же время это также позволило мне обрести уверенность в себе: я неплох, но слишком сильно на себя давлю.

        Ниже приведены некоторые из моего личного опыта, просто для справки:

1. Товарищи по команде очень важны.Электросоревнование длится четыре дня и три ночи.Если вы не очень талантливый человек, то вам придется посылать одного к другому. Если вы ищете товарища по команде, вы должны найти кого-то надежного, а не недостатка в избытке, и не стыдиться своих чувств, вы должны пинать того, кого следует пинать, а баловать мерзавца - это быть безответственный к себе;

2. Киберспорт (только традиционное управление) предполагает широкий спектр знаний, поэтому очень важно разделение труда внутри команды.Общее разделение труда это ПО, железо и техника, но лучше не концентрироваться только на на собственном разделении труда, не говоря уже об общении внутри коллектива №1. Никто не знает какие будут традиционные контрольные вопросы перед стартом конкурса.Может быть 80% задач нужно делать программно,или 80% задач нужно делать аппаратно,так что лучше быть готовым,иначе вы умрете в праздности, устали до смерти;

3. Не ходите в киберспорт без подготовки, голые соревнования просто ищут ругань. Электронные соревнования сложны для большинства людей.Начать с 0 за четыре дня и три ночи очень сложно.Мое личное предложение - сделать обучающие вопросы,подготовить необходимые функциональные модули и угадать вопросы по исходному списку.Подготовьтесь заранее ;

4. Не висите на плате stm32 и PCB. MCU — это просто инструменты, они совместимы и должны иметь возможность быстро менять MCU или напрямую использовать платы TI. Те, кто занимается железом, могут не уметь чертить печатные платы, но они должны уметь паять платы с отверстиями Не рассчитывайте на отливку плат за четыре дня и три ночи;

5. Четыре дня и три ночи электронного соревнования должны уловить ритм, а те, кто делает софт, должны выспаться. Если вы можете не ложиться спать в первые две ночи, не ложитесь спать допоздна.После того, как вы не ложитесь спать, вы очень устанете.Вы знаете код, но вы не знаете, что вы написали. В первый день аппаратного и машинного оборудования, даже если вы поздно ложитесь спать, постарайтесь сделать физическую схему и машинное оборудование (именно поэтому вы не рассчитываете проголосовать за печатную плату);

6. Когда подумаю, добавлю.

Ссылка для скачивания проекта: my_project_2022_two_cars: 2022 Electric Race Project

Supongo que te gusta

Origin blog.csdn.net/qq_47652105/article/details/127036370
Recomendado
Clasificación