资讯详情

智能车竞赛技术报告 | 智能车视觉 -重庆大学 - 风林火山

简 介: 本文主要介绍了基础RT Thread智能视觉组四轮跟踪智能汽车系统原理、软硬件设计和汽车生产过程,汽车系统介绍包括汽车模具机械结构设计、模块电路设计、传感器信号处理、控制算法、神经网络算法车调试方法等。设计以恩智浦公司的单片机RT1064是数字摄像头的核心控制MT9V032收集轨道元素信息,增量编码器获取车速,陀螺仪获取车姿。程序基于RT Thread操作系统, IAR 作为集成编译环境,使用 无线串口、LCD 、辅助调试手段是拨码开关和按键。经过大量的软硬件测试,智能汽车在高速下实现了稳定的循环运动。

学 校:重庆大学队伍名称:风林火山参赛队员:谢谢文祥?谢谢文祥??谢谢文祥??谢谢文祥?谢谢文祥?谢谢文祥?谢谢文祥?谢谢文祥?谢谢谢文祥?谢谢谢文祥?谢谢谢文祥?谢谢谢文祥?谢谢谢谢文祥?谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢谢文梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林梁华林陈俊林陈俊林陈俊林带队教师:杜基赫 许亨艺

第一章


??由教育部自动化专业教学指导委员会主办的全国大学生智能汽车竞赛。本次比赛以立足培养,注重参与,鼓励探索,追求卓越为基础 为了指导思想,旨在促进高校素质教育,培养大学生的综合知识应用能力、基程实践能力和创新意识。智能汽车竞赛涉及自动控制、传感技术、电子、电气、计算机、机械、汽车等学科,为大学生提供了充分展示想象力和创造力的舞台,吸引了越来越多不同专业的大学生参与,激发了大学生的创新思维,对其实践、创新能力和团队精神的培养具有重要价值。

??全国大学生智能汽车竞赛组织运营模式实施政府倡导、专家主办、学生主体、社会参与 16 充分调动各方参与的积极性。

??RT-Thread,全称是 Real Time-Thread,它是一个嵌入式实时多线程操作系统。其基本属性之一是支持多任务。任务和任务通过任务调度器快速切换(调度器根据优先级决定此时执行的任务),导致多任务同时运行的错觉。开源实时操作系统主要由中国开源社区开发。实时线程操作系统不仅是一个单一的实时操作系统核心,也是一个完整的应用系统,包括与实时嵌入式系统相关的各个组件:TCP/IP协议栈,libc接口、图形用户界面等。

??本文是风林火山对最终车型的总体总结,展示了生产过程中的技术细节。在本文的参考文献中,《C primer plus》阐述了基本的C 《模拟电子技术基础》详细《模拟电子技术基础》详细介绍了电路的基本知识,嵌入式实时操作系统:RT-Thread设计与实现简介了嵌入式系统的开发调试方法RT-Thread进行了详细的讲解。《智能车生产》简要阐述了智能车实际生产的总体方案。

??本文将在后面的文本部分按顺序解释: ??1. 模型车设计生产的主要思路和技术方案的总体说明; ??2. 模型车结构设计; ??3. 电路设计说明; ??4. RT Thread 介绍了应用和控制策略; ??5. 说明开发工具、生产、安装、调试过程; ??6. 说明模型车的主要技术参数。

第二章 车型设计制作思路


2.1选择主控芯片

??AI只有视觉组限制芯片制造商NXP,所以选择官方推荐RT1064, 该芯片主频高,能满足彩色摄像头的使用,硬件资源丰富。

▲ 图2.1 RT1064核心板

2.2.稳压电路的选择

??电源模块为系统的其他模块提供所需的电源。在设计中,除了电压范围、电流容量等基本参数外,还应优化电源转换效率、噪声和干扰。可靠的电源方案是整个硬件电路稳定可靠运行的基础。

??核心板上电存在时序问题,IO内核不能先上电,否则内核不能启动。可使用CR引脚控制外围设备的供电电路。因为当CR当引脚变成高电平时,表面内核成功启动。外部电路通过三极管和Mos管道设计合理的电路。整车电源额定电压7.4V,满电电压8.4V锂电池供电。将电池电压转换为各模块所需的电压,采用不同的稳压方案。

??1) 锂电池供电,正常使用时电压为7.4~8.4V。可直接用于电机供电。 ??2) 通过TPS76850产生5v提供编码器、串口通信、陀螺仪等电压。 ??3) 使用稳压芯片AMS1117系列稳压到6V,供电转向舵机和数字舵机。 ??4) 通过TPS76833产生3.3v电压,为摄像头供电

▲ 图2.2 稳压电路原理图

2.3.驱动电路的选择

??使用MOS桥式电路驱动电机,利用隔离芯片为桥式电路提供信号,避免电流反冲进芯片,造成芯片损坏。

▲ 图2.3 驱动电路原理图

2.4电流环电路

??电流环是指电流反馈系统。一般是指通过负反馈连接输出电流,提高电流稳定性的方法.使用电流环后,可结合电流内环和外环,提高系统性能和车辆运行稳定性。

▲ 图2.4电流环原理图

2.5传感器的选择

??可分为两类: CCD摄像头和CMOS摄像头。CCD相机图像对比度高,动态特性好,但电源电压高,需要12V工作电压。功耗严重,图像稳定性不高。CMOS摄像头,体积小,图像稳定性较高,只需3.3V供电,耗电量低。基于总转风摄像头的总转风摄像头MT9V032芯片设计的CMOS摄像头是逐飞科技独家开发的高性能快门摄像头,在恩智浦竞赛市场上性能最好,最适合高速图像采集。

▲ 图2.5总转风摄像头

2.6编码器的选择

??输出轴上的机械几何位移转换为脉冲或数字量,实现速度测量,从而完成电机的闭环控制。 模型车机械安装

▲ 图2.6 1024线光电编码器

第三章 感器安装


3.1摄像头

  逐飞科技设计的130度无畸变总钻风广角摄像头,调节镜片中心离地面的高度为30cm ,视角为30°,智能车据此获得了良好且稳定的图像。

▲ 图 3.1 模型车侧视图

3.2编码器

  为了实现电机闭环,提高控制精度,本车使用了1024线带方向的编码器,并对编码器传回数据进行简单的滤波处理,在不牺牲处理时间的前提下尽可能提高编码器传回数据的精确度。

3.3系统电路板的固定及连接

  C车模由于电机及编码器都在车尾部,重心偏后,所以我们在不影响舵机连杆运动的情况下将电路板尽量靠前安装,通过对硬件的合适处理,减小车的重心到最低,并通过四个电子秤保证车子重心尽可能在车中心。

 

第四章 路设计


4.1最小系统部分

  在设计主板的时候,主要考虑的原则是电路板足够窄,同时满足电流的要求,适当增大线宽,在布局布线的时候,尽可能考虑电流的流向。

▲ 图 4.1 最小系统部分

4.2电机驱动部分

  驱动电路对电流的要求更严格,电流线要格外加粗,同时为了利于散热,我进行了开窗处理,同时必须采用隔离芯片防止烧坏单片机。并且增加电流信号采集芯片,为电流环和电机保护提供硬件基础。

▲ 图 4.1 最小系统部分

 

第五章 于RT Thread的控制算法


5.1程序运行流程

  在AI视觉组的任务相对其他更加繁杂,包括基础循迹、数字识别、二维码识别、激光打靶等等。同时为了方便调试运行、需要TFT显示标志位、按键响应、蜂鸣器提示和LED闪烁等功能。对于这样一个智能车任务,完全可以将它分解成多个简单、容易解决的小问题,小问题逐个被解决,大问题也就随之解决了。在多线程操作系统中,也同样需要开发人员把一个复杂的应用分解成多个小的、可调度的、序列化的程序单元,当合理地划分任务并正确地执行时,这种设计能够让系统满足实时系统的性能及时间的要求在本次智能车比赛中我们主要使用了RTthread中的线程、时钟、线程同步等功能。

  用于检测电池电压变化的定时器bat_timer:

rt_timer_t bat_timer = rt_timer_create("bat_timer", adc_bat_thread, RT_NULL, ADC_BAT_INTERVAL, RT_TIMER_FLAG_PERIODIC);
    rt_timer_start(bat_timer);

void adc_bat_thread(void *parameters)
{ 
        
    uint16 value = adc_mean_filter(ADC_1, ADC1_CH3_B14, 5);
    f1.bat_voltage = (float)value * 3.3 / 0xFFF * 5.7;
}

  用于获取陀螺仪数据的定时器gyro_timer,并在定时器线程中进行姿态解算:

    rt_timer_t gyro_timer = rt_timer_create("gyro_timer", gyro_thread, RT_NULL, GYRO_INTERVAL, RT_TIMER_FLAG_PERIODIC);
rt_timer_start(gyro_timer);

void gyro_thread(void *parameter)
{ 
        
    get_icm20602_gyro_spi();
    get_icm20602_accdata_spi();

    inoutdev.update_gyro_y();
    inoutdev.update_gyro_z();
}

void inoutdev_ctrl::update_gyro_z()
{ 
        
    LPF_1_db(35, 1000, (float)(icm_gyro_z - gyro_z_offset), &gyro_z_filter);

    yaw_rate = -0.03051757f * gyro_z_filter;
    if (yaw_rate < 1.3 && yaw_rate > -1.3)
        yaw_rate = 0;

    // rt_kprintf("%f\n", inoutdev.y_rate);
    delta_z = 10.3 * yaw_rate / 1000.0;
    gyro_z_angle += delta_z;
    start_angle += delta_z;

    if (fabs(gyro_z_angle) >= 360)
        gyro_z_angle = 0;
}

  用于更新电流环的定时器current_timer:

current_timer = rt_timer_create("current_timer", current_thread, RT_NULL, CURRENT_INTERVAL, RT_TIMER_FLAG_PERIODIC);
  
void current_thread(void *parameters)
{ 
        
    if (0 == f1.chassis_update_type)
    { 
        
        chassis.left_wheel.update_current();
        chassis.right_wheel.update_current();
    }
    else if (1 == f1.chassis_update_type)
    { 
        
    }
}

  用于更新速度环的定时器chassis_timer:

    rt_timer_t timer = rt_timer_create("chassis_timer", chassis_thread, RT_NULL, CHASSIS_INTERVAL, RT_TIMER_FLAG_PERIODIC);
rt_timer_start(timer);

void chassis_thread(void *parameter)
{ 
        
    if (0 == f1.chassis_update_type)
    { 
        
        chassis.left_wheel.update();
        chassis.right_wheel.update();
        chassis.update_speed();
    }
    else if (1 == f1.chassis_update_type)
    { 
        
        chassis.left_wheel.get_speed();
        chassis.right_wheel.get_speed();
        chassis.update_speed();

        if (chassis.speed_now[0] > 2)
        { 
        
            chassis.hard_bake_cnt = 0;
            chassis.left_wheel.w_motor.run(-1000);
            chassis.right_wheel.w_motor.run(-1000);
        }
        else
        { 
        
            chassis.hard_bake_cnt++;
            if (chassis.hard_bake_cnt >= 3)
            { 
        
                chassis.set_speed(0, 0);
                f1.chassis_update_type = 0;
            }
        }
    }

    chassis.update_dis();
}

  用于更新TFT显示屏的定时器display_timer,并且其线程优先级最低,以确保其他控制小车运行的线程正常运行:

    rt_thread_t tid_display = rt_thread_create("display_thread", display_thread, RT_NULL, 2048, 31, 5);
rt_thread_startup(tid_display);

void display_thread(void *param)
{ 
        
    while (1)
    { 
        
        ui_title_fresh(NULL);
        rt_thread_mdelay(100);
    }
}

  在工程代码中使用了基于RTthread的agile_button的库,agile_button是基于RT-Thread实现的button软件包,提供button操作的API。特性:代码简洁易懂,充分使用RT-Thread提供的API;详细注释;线程安全;断言保护;API操作简单

key1 = agile_btn_create(KEY1_PIN, PIN_LOW, PIN_MODE_INPUT_PULLUP);
key2 = agile_btn_create(KEY2_PIN, PIN_LOW, PIN_MODE_INPUT_PULLUP);
key3 = agile_btn_create(KEY3_PIN, PIN_LOW, PIN_MODE_INPUT_PULLUP);
key4 = agile_btn_create(KEY4_PIN, PIN_LOW, PIN_MODE_INPUT_PULLUP);
key5 = agile_btn_create(KEY5_PIN, PIN_LOW, PIN_MODE_INPUT_PULLUP);
key6 = agile_btn_create(KEY6_PIN, PIN_LOW, PIN_MODE_INPUT_PULLUP);
key7 = agile_btn_create(KEY7_PIN, PIN_LOW, PIN_MODE_INPUT_PULLUP);

agile_btn_set_event_cb(key1, BTN_CLICK_EVENT, btn_event_cb);
agile_btn_set_event_cb(key2, BTN_CLICK_EVENT, btn_event_cb);
agile_btn_set_event_cb(key3, BTN_CLICK_EVENT, btn_event_cb);
agile_btn_set_event_cb(key4, BTN_CLICK_EVENT, btn_event_cb);
agile_btn_set_event_cb(key5, BTN_CLICK_EVENT, btn_event_cb);
agile_btn_set_event_cb(key6, BTN_CLICK_EVENT, btn_event_cb);
agile_btn_set_event_cb(key7, BTN_CLICK_EVENT, btn_event_cb);

agile_btn_start(key1);
agile_btn_start(key2);
agile_btn_start(key3);
agile_btn_start(key4);
agile_btn_start(key5);
agile_btn_start(key6);
agile_btn_start(key7);

  同时也使用了基于RTthread的easyblink的库。小巧轻便的LED控制软件包,可以容易地控制LED开、关、反转和各种间隔闪烁,占用RAM少,可以设置成线程安全型的;同时提供 RT-Thread 标准版和 Nano 版。

  特点:和其它LED同类软件相比,easyblink 有一个显著的特点,占用 RAM 特别少,其它 LED 软件一般每一个LED都需要创建一个线程,LED一多,线程数就多了,所占用的栈空间就相应的增大。而 easyblink 始终只使用一个守护线程(线程栈可以是预先分配的静态栈空间),无论多少个 LED,就一个线程。另外,有不需要移植就可以直接使用的 Nano 版,特别适合 RAM 紧张的产品。同时,也可以设置成线程安全型的。

    errno_led = easyblink_init_led(LED0_PIN, PIN_LOW);
    info_beep = easyblink_init_led(BEEP_PIN, PIN_HIGH);
easyblink(errno_led, -1, 200, 1000);

void inoutdev_ctrl::beep(int num)
{ 
        
    easyblink(info_beep, num, 30, 80);
}

void inoutdev_ctrl::lbeep(int num)
{ 
        
    easyblink(info_beep, num, 200, 400);
}

5.2定义信号量

  RT-Thread操作系统支持采用信号量、互斥量、邮箱、消息队列等等方式进行线程间的通信。由于我们在智能车的设计中只是用了信号量和互斥量,我们将仅介绍信号量和互斥量。

  信号量是一种轻型的用于解决线程间同步问题的内核对象,线程可以获取或释放它, 从而达到同步或互斥的目的。信号量就像一把钥匙,把一段临界区给住,只允许 有钥匙的线程进行访问:线程拿到了钥匙,才允许它进入临界区;而离开后把钥匙 传递给排队在后面的等待线程,让后续线程依次进入临界区。

  互斥量又叫相互排斥的信号量,是一种特殊的二值性信号量。它和信号量不同的是, 它支持互斥量所有权、递归访问以及防止优先级翻转的特性。互斥量的使用比较单一,因为它是信号量的一种,并且它是以锁的形式存在。 在初始化的时候,互斥量永远都处于开锁的状态,而被线程持有的时候则立刻转为 闭锁的状态。

chassis_mutex = rt_mutex_create("chassis_mutex", RT_IPC_FLAG_FIFO);
csi_done_sem = rt_sem_create("csi_done_sem", 0, RT_IPC_FLAG_FIFO);
ano_upload_sem = rt_sem_create("ano_upload_sem", 0, RT_IPC_FLAG_FIFO);

5.3初始化线程\定时器

  对需要使用的硬件模块进行初始化,然后便开始为各个模块创建自己的线程,设置线程的运行周期,对于不能使用操作系统的裸机只能通过定时器中断来实现各个模块的周期运行,然而使用RT Thread后,可以更方便的管理各个模块的运行,也不用关心底层定时器怎么写,不必担心定时器数量是否够用,RT Thread编写的智能车代码更具有可读性,   current_timer = rt_timer_create(“current_timer”, current_thread, RT_NULL, CURRENT_INTERVAL, RT_TIMER_FLAG_PERIODIC);

  电流环的定时器配置,设置定时周期为CURRENT_INTERVAL,优先级为RT_TIMER_FLAG_PERIODIC   rt_timer_start 设置完成定时器的参数之后定时器不会立即启动,只有调用rt_timer_start函数之后定时器才开始计时,这个定时我们设定在主函数里面 rt_thread_mdelay(3000); rt_timer_start(current_timer);   程序延时3s后开始计时,开启电流环

  rt_thread_t tid_display = rt_thread_create(“display_thread”, display_thread, RT_NULL, 2048, 31, 5);   rt_thread_startup(tid_display);

  在这里创建并开启了显示屏的线程,并且分配堆栈大小为2048,设置线程优先级为31,设置时间片为5

5.4线程间通信

  线程通过获取信号量来获得信号量资源实例,当信号量值大于零时,线程将获得信号量,并且相应的信号量值都会减1。在调用这个函数时,如果信号量的值等于零,那么说明当前信号量资源实例不可用,申请该信号量的线程将根据time参数的情况选择直接返回、或挂起等待一段时间、或永久等待,直到其他线程或中断释放该信号量。如果在参数time指定的时间内依然得不到信号量,线程将超时返回,返回值是-RT_ETIMEOUT。这里我们获取csi图像采集的信号,判断图像采集是否完成,完成后再进行下一步工作,实现图像的处理,路径规划,元素识别,速度控制等等。

  当通过设定摄像头帧率后,摄像头完成一帧图像获取后发出信号量,在main函数中接受道信号量后继续运行,并进行后续的图像处理:

    rt_sem_take(csi_done_sem, RT_WAITING_FOREVER);
rt_sem_control(csi_done_sem, RT_IPC_CMD_RESET, RT_NULL);

  inoutdev的类中clock函数用于统计实际帧率:

inoutdev.clock();

void inoutdev_ctrl::clock()
{ 
        
    current_time = pit_get_ms(PIT_CH0);
    fps = 1000 / (current_time - last_time);
    last_time = current_time;
}

5.5 控制策略选择

  PID控制器是一种线性控制器,它根据给定值与实际输出值构成控制偏差。将偏差的比例§、积分(I)和微分(D)通过线性组合构成控制量,对被控对象进行控制,故称PID控制器。传统PID控制器自出现以来,凭借其结构简单、稳定性好、工作可靠、调整方便等优点成为工业控制主要技术。当被控对象的结构和参数具有一定的不确定性,无法对其建立精确的模型时,采用PID控制技术尤为方便。PID控制原理简单、易于实现,但是其参数整定异常麻烦。对于小车的速度控制系统而言,由于其为时变非线性系统不同时刻需要选用不同的PID参数,采用传统的PID控制器,很难使整个运行过程具有较好的运行效果。

▲ 图5.1 PID控制器原理框图

5.5.1 位置式PID

  位置式PID中,由于计算机输出的u (k) 直接去控制执行机构(如阀门),u(k)的值和执行机构的位置(如阀门开度)是一一对应的,所以通常称公式2为位置式PID控制算法。

  位置式PID控制算法的缺点是:由于全量输出,所以每次输出均与过去的状态有关,计算时要对过去e(k)进行累加,计算机工作量大;而且因为计算机输出的u(k)对应的是执行机构的实际位置,如计算机出现故障,u(k)的大幅度变化,会引起执行机构位置的大幅度变化,这种情况往往是生产实践中不允许的,在某些场合,还可能造成严重的生产事故。因而产生了增量式PID 控制的控制算法,所谓增量式PID 是指数字控制器的输出只是控制量的增量△u(k)。

#ifndef __POS_PID__
#define __POS_PID__

#include "headfile.h"
#include "rtthread.h"
using namespace rtthread;

class pos_pid
{ 
        
public:
    float kp = 0;
    float ki = 0;
    float kd = 0;

    float error = 0;
    float error_last = 0;
    float error_diff = 0;

    float error_history[5];
    float error_diff_history[5];

    float p_error = 0;
    float i_error = 0;
    float d_error = 0;

    float last_out = 0;
    float output = 0;
    float target = 0;
    float intergral = 0;

    float anti_wind_radio = 0.5f;
    float anti_windup_value = 0;

    float maximum = 0;
    float minimum = 0;

    pos_pid() { 
        }

    pos_pid(float kp, float ki, float kd, float maximum, float minimum) : kp(kp), ki(ki), kd(kd), maximum(maximum), minimum(minimum)
    { 
        
        anti_windup_value = maximum * anti_wind_radio;
    }

    void set_pid(float kp_p, float ki_p, float kd_p)
    { 
        
        kp = kp_p;
        ki = ki_p;
        kd = kd_p;
    }

    void update(float current_point)
    { 
        
        error = target - current_point;

        for (int i = 5; i >= 1; i--)
            error_history[i] = error_history[i - 1];
        error_history[0] = error;

        intergral += ki * error;
        __Limit_Both(intergral, anti_windup_value);

        error_diff = (error - error_last);

        for (int i = 5; i >= 1; i--)
            error_diff_history[i] = error_diff_history[i - 1];
        error_diff_history[0] = error_diff;

        p_error = kp * error;
        i_error = intergral;
        d_error = kd * error_diff;

        last_out = p_error + i_error + d_error;
        __Limit_AB(last_out, minimum, maximum);

        error_last = error;
        output = last_out;
    }
};

#endif

5.5.2 增量式PID

  当执行机构需要的是控制量的增量(例如:驱动步进电机)时,可由式2推导出提供增量的PID控制算式。   增量式PID具有以下优点:

(1) 由于计算机输出增量,所以误动作时影响小,必要时可用逻辑判断的方法关掉。

(2) 手动/自动切换时冲击小,便于实现无扰动切换。此外,当计算机发生故障时,由于输出通道或执行装置具有信号的锁存作用,故能保持原值。

(3) 算式中不需要累加。控制增量△u(k)的确定仅与最近k次的采样值有关,所以较容易通过加权处理而获得比较好的控制效果。   但增量式PID也有其不足之处:积分截断效应大,有静态误差;溢出的影响大。使用时,常选择带死区、积分分离等改进PID控制算法。

#ifndef __INC_PID__
#define __INC_PID__

#include "common_macro.h"
#include "rtthread.h"
using namespace rtthread;

class inc_pid
{ 
        
public:
    float kp = 0;
    float ki = 0;
    float kd = 0;
    float error = 0;
    float error_l = 0;
    float error_ll = 0;
    float p_error = 0;
    float i_error = 0;
    float d_error = 0;

    float last_out = 0;
    float output = 0
        标签: 955s智能线性位移传感器ch2m光电传感器tps767d318集成电路5l智能开关三极管智能开关三极管三极管分离正负电流

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台