精华内容
下载资源
问答
  • 基于RT1064对于四轮寻迹智能车的设计工作笔记 目录基于RT1064对于四轮寻迹智能车的设计工作笔记1.前篇(1)adc (模数/数模转换)(2)pit(定时中断)(3)pwm(波特率)(4)gpio(引脚使用)2.舵机篇3.电机篇4....

    四轮寻迹智能车的设计(逐飞IMX-RT1064)

    1.前篇

    1064单片机基础函数

    (1)adc (模数/数模转换)

    在这里插入图片描述
    一般就是芯片的输出和输入,芯片输出信号,要做数模转换。芯片接收的信号,要进行模数转换。( 只要跟CPU打交道的通常是数字量,和控制系统相关的一般是模拟非电量(温度,速度等),模拟量和数字量之间的通信就需要A/D和D/A转换,A/D和D/A转换起到了桥梁的作用。)
    原理:
    在这里插入图片描述
    重要参数
    分辨率:
    AD转换器输出的数字量的最低位变化一个数时,对应输入模拟量的变化量,A/D转换器的位数越多,能够分辨的最小模拟电压值就越小,分辨率就越大,STM32的A/D转换器是12位的,假设最大输入电压为5V,所能分辨的最小电压量就是5/(2^12),很多时候我们会直接说一个n位的A/D转换器分辨率为n,这只是一个设计参数,不是实际的测量值。
    相对精度:
    A/D转换器实际输出数字量与理论值之间的最大差值称为相对精度
    转换速度:
    A/D转换器完成一次转换所需要的时间,一般是us级别

    相关函数(逐飞库为例)
    /******************************/
    //引脚adc初始化函数
    //参数:adc模块(两个),adc通道(B组引脚),通道分辨率(8,10,12位—分辨率越高精度越高)
    //ADCN_enum,ADCCH_enum等函数都是枚举类型的
    /******************************/
    void adc_init(ADCN_enum adcn, ADCCH_enum ch, ADCRES_enum resolution)
    
    //adc采集转换函数
    //参数:adc模块,adc通道
    uint16 adc_convert(ADCN_enum adcn, ADCCH_enum ch)
    

    (2)pit(定时中断)

    对于逐飞库来说其可使用的中断通道数有三个PIT_CH1,PIT_CH2,PIT_CH3,但是三个中断函数是写在同一个函数中,然后初始化要使用的中断通道,在中断触发的时候,会进入中断函数,并进行中断函数类型的判断,并执行对应的操作。

    //引脚pit初始化函数
    void  pit_init(void );
    
    //pit中断时间设置(时间单位为ms,us,一般使用ms)
    void pit_interrupt(PIT_enum pit_ch, uint32 count)
    

    (3)pwm(波特率)

    波特率输出,其实就是将电压微分,在部分积分控制,从而输出你想要的电压值,从而控制舵机,电机等,根据电压输出量不同,而输出不同转态的器件。
    PWM是一种对模拟信号电平进行数字编码的方法。通过高分辨率计数器的使用,方波的占空比被调制用来对一个具体模拟信号的电平进行编码。PWM信号仍然是数字的,因为在给定的任何时刻,满幅值的直流供电要么完全有(ON),要么完全无(OFF)。电压或电流源是以一种通(ON)或断(OFF)的重复脉冲序列被加到模拟负载上去的。通的时候即是直流供电被加到负载上的时候,断的时候即是供电被断开的时候。只要带宽足够,任何模拟值都可以使用PWM进行编码。

    /******************************/
    //1.pwm初始化
    //参数:通道号及引脚号,pwm频率,pwm占空比
    //第一个参数包含了两个信息,通道号,和引脚号,因为初始化函数中有个字函数void pwm_iomuxc(PWMCH_enum pwmch),内部通过参数一,进行了引脚的判断和初始化引脚pwm状态。
    /******************************/
    void pwm_init(PWMCH_enum pwmch, uint32 freq, uint32 duty)
    
    /******************************/
    //2.pwm占空比设置,通过改变占空比,实现对于输出量的控制
    /******************************/
    void pwm_duty(PWMCH_enum pwmch, uint32 duty)
    
    /******************************/
    //3.pwm频率设置(与初始化操作类似)
    /******************************/
    void pwm_freq(PWMCH_enum pwmch, uint32 freq, uint32 duty)
    

    (4)gpio(引脚使用)

    用于高低电平,以及IO复用外部中断

    /******************************/
    //GPIO初始化
    //参数:选择的引脚,引脚方向(输入或输出),输出高低电平,上下拉电阻
    void gpio_init(PIN_enum pin, GPIODIR_enum dir, uint8 dat, uint32 pinconf)
    
    

    2.舵机篇

    (1)模数转换:通过运放和滤波,调制电路将电感采集回来的模拟量转换成数字量
    (2)定时中断控制:先将对应的芯片接收电感转换后数字量的引脚 初始化为定时中断功能,再对接收到数据进行转换,保存和处理
    (3)数据处理:对于采集回来的电感量使用冒泡法进行排序,再取中间的值的平均数,作为单次采集的数据。在将数据应用于PID算法控制,算出舵机每次的偏差值,由中值和偏差值得出需要输出的正确的舵机控制信号

    中断控制部分函数
    ①电感采集

    uint8 i;
        
    uint8 left[10]={0};
    uint8 right[10]={0};
    
    //左右电感 ad数据采集
    for(i=0;i<10;i++)
    {
    	left[i]=adc_convert(ADC_1,ADC1_CH3_B14);
    	right[i]=adc_convert(ADC_1,ADC1_CH4_B15); 
    }
    left_ad = sort(left);
    right_ad = sort(right);
    out_ad = left_ad + right_ad;
    
    return;
    

    电感采集后的数据处理使用冒泡排序法

    //就是一次中断采集十次电感数据,并排序,取中间三个值的平均值
    uint8 sort(uint8 *sum)
    {
      uint8 i,j;
      uint8 temp,k;
      for(i=0;i<10;i++)
      {
        for(j=0;j<9-i;j++)
        {
          if(sum[j]>sum[j+1])
          {
            temp=sum[i];
            sum[i]=sum[i+1];
            sum[i+1]=temp;     
          }
        }
      }
      k=(sum[4]+sum[5]+sum[6])/3;
      return k;
    }
    

    ②差比和

    //将上诉采集到的左右两边电感的数据进行差比和计算(归一化处理)
    float cha=0;
    float he=0;
    //差比和
    cha = left_ad - right_ad;
    he = left_ad + right_ad;
    now_abs = cha/he;
    now_abs *= beishu;  
    

    ③PID算法控制(增量式控制)

     //PID控制
      last_2_abs = now_abs - last_abs;
      result= (P * now_abs + D * last_2_abs);
      last_2_abs = last_abs;
      last_abs = now_abs;
      
      result = 640 - result;
    

    最后舵机pwm的输出写在定时中断函数中

    (实际算法只采用前两项,即PD控制)
    参数调整:包括舵机中值,舵机左右极限打脚值,PID控制参数,的调整。

    3.电机篇

    目前电机控制处于开环状态,持续输出一个pwm值,控制电机正向转动。

    4.调试篇

    IAR工程编译,调试硬件连接过程:
    (顺序如下)
    将调试器连上芯片
    调试器连上电脑
    电脑debug将程序写入芯片
    打开芯片电源开关
    IAR中点击go按钮(跑程序)
    通过livewight(实时变量观测窗口)观测目标变量,并可以对目标变量进行修改,从而对得到的结果数据进行观测,实现实时调试参数。
    结束时先将程序停止运行,再将USB数据线拔掉,在将芯片电源开关关掉

    参数调整

    控制系统无非要求稳,准,快(但本次只是用到PD控制)
    即最大超调量和上升时间,反应到小车上是舵机打脚的角度大小和打脚的反应速度。在调整的时候可以先调整一个参数,例如P,使另一个参数值零。P调得差不多了,在调整D。

    展开全文
  • (2)简介RT1064与无线串口透传模块; (3)MATLAB数据处理过程详解; (4)效果展示与分析; (5)操作指南(手把手教你使用)。 一、控制系统相关知识 (1)控制系统的基本性能要求:稳、准、快 稳:指的是系统...

    本文框架:

    (1)介绍控制系统的基本性能要求及常用性能指标;
    (2)简介RT1064与无线串口透传模块;
    (3)MATLAB数据处理过程详解;
    (4)效果展示与分析;
    (5)操作指南(手把手教你使用)。
    在这里插入图片描述


    一、控制系统相关知识

    (1)控制系统的基本性能要求:稳、准、快
    :指的是系统的稳定性。稳定性是系统重新恢复平衡状态的能力。不稳定的系统将出现持续的震荡,无法运用于自动控制系统中。
    :对系统稳态(静态)性能的要求。对于一个稳定的系统而言,当过渡过程结束后,系统输出量的实际值与期望值之差称为静态误差,它是衡量系统控制精度的重要指标。稳态误差越小,表示系统的准确性越好,控制精度越高。
    :对系统动态(过渡过程)性能的要求。描述系统动态性能可以用平稳性和快速性加以衡量。平稳是指系统由初始状态过渡到新的平衡状态时,具有较小的过调和振荡性;快速性是指系统过渡到新的平衡状态所需要的调节时间最短。动态性能是衡量系统质量高低的重要指标。
    (2)系统的动态性能指标:
    在这里插入图片描述
    延迟时间td :阶跃响应第一次达到终值h(∞)的50%所需时间。
    上升时间tr :阶跃响应从终值的10%上升到终值的90%所需时间;对有振荡的系统,也可以定义为从0到第一次达到终值所需要的时间。
    峰值时间tp:阶跃响应越过终值h(∞)达到第一个峰值所需时间。
    调节时间ts :阶跃响应到达并保持在终值h(∞)±5%(或2%)误差带内所需要的最短时间。
    超调量σ%:峰值超出终值h(∞)的百分比,即
    在这里插入图片描述

    在上述动态性能指标中,我们常用调节时间ts (反映过渡过程的长短)、超调量σ%(反映过渡过程的波动程度)和峰值时间tp来作为系统的动态性能指标。


    二、硬件模块简介

    (1)RT1064核心板
    RT1064为NXP公司推出的RT1064,属于RT1060系列,Cortex M7内核,拥有600Mhz运行主频4MB Flash,1MB SRAM,32KB I-Cache,32KB D-Cache,是现阶段运算性能最为强劲的一款微控制器。详细技术指标可到NXP官网查看。这里我使用的是逐飞科技有限公司推出的RT1064最小系统版。
    在这里插入图片描述

    (2)无线串口透传模块
    这里我使用的是逐飞科技推出的无线转USB(接上位机)/无线转串口(接下位机)模块,相比于平常使用的蓝牙模块,无需了解其他知识,就能快速入手,且该模块传输距离更远、传输速度更快!个人感觉:真香!
    在这里插入图片描述
    有两点需要注意一下:①在接线时,上位机的RX引脚要接下位机的TX引脚,同样上位机的TX引脚要接下位机的RX引脚。②我们传输的数据类型一般为int型、double型等等,而串口一次只能发送8位的数据,且发送的数据格式为uint8。这就需要涉及到数据转换。以int32型为例,因为int型数据有正负,需要先进行符号位的判断,先向上位机发送符号位(2字节);int32有32位数据,须将它分解为4个字节,依次发送给上位机。因此,一个int32型的数据通过数据转换为6个字节数据进行传输。其他数据类型的传输同理可得。若不知道某数据类型的字节数,可用sizeof( )函数进行获取。以下为数据转换代码,基于RT1064+逐飞的无线转串口模块,仅供参考。

    void data_int32_transform(int32 data)//数据转换
    {
        i_bit=sizeof(data);		//获取数据字节数
        if(data>=0)         //判断数据正负,若为正值,标志位为0
        {
            val=0;
            seekfree_wireless_send_buff(&val,1);//发送符号标志位
            //data=abs(data);
             for(i_bit;i_bit>=0;--i_bit)     //移位处理,先发送高位
            {
                data_temp=(uint8)(data>>(8*i_bit));
                seekfree_wireless_send_buff(&data_temp,1);//发送数据
             }   
        }
        else               //若为负值,标志位为1
        {
            val=1;
            seekfree_wireless_send_buff(&val,1);//符号标志位
            data=abs(data);
             for(i_bit;i_bit>=0;--i_bit)
            {
                data_temp=(uint8)(data>>(8*i_bit));
                seekfree_wireless_send_buff(&data_temp,1);
            }
        }
    }
    

    三、MATLAB数据处理:

    如下图所示,我在做速度、电流双闭环时同时向上位机发送了两种数据内容:电流值与速度值,且轮流发送;数据值即为单片机经过上述数据转换后发送给上位机的内容;每个数据内容为6个字节,其中分为2个字节的符号位和4个字节的数据位。
    在这里插入图片描述
    诚然,在MATLAB里需要将数据值再一次进行数据转换才能处理。我的转换思路为:(1)将数据值的每2个字节进行合并,即第一个字节左移8位并和第二个字节进行或运算;(2)经上述处理后,每个数据内容变为一个符号位和两个数据位;此时再将两个数据位合并,根据符号位判断数据的正负,到此数据转换结束,我们就能得到单片机原始要发送的数据(3)因为我同时发送了两种内容的数据,最后我还需要将数据进行分类处理。
    以下为MATLAB数据处理代码:

    duty=30;
    s_P=2.58;
    s_I=0.82;
    c_P=0;
    c_I=0;
    goal_speed=(duty*2); 
    goal_current=(310+duty);  %以上为我所需要的一些常量
    
    a=textread('E:\毕业设计\无线转串口\串口助手\串口助手\sscom32\SaveWindows2021_3_28_19-28-50.txt','%s')';%以字符形式打开文件,文件地址具体查看你的数据文档所在地址
    alpha=hex2dec(a)'; %16进制转化为10进制数,存入alpha矩阵,方便后面的数据处理        
    row=size(alpha,2); %判断我的数据总数,若只有一个数据内容:00 01 00 00 0C 5A 则						row=6,存入1X6大小的矩阵
    %以下为变量初始化
    temp=zeros(1,row/2);%将数据值的每2个字节合并后暂存区矩阵
    data=zeros(1,row/6);%数据内容暂存区矩阵
    current_data=zeros(1,row/12); %存放电流数据的矩阵
    speed_data=zeros(1,row/12);    %存放速度数据的矩阵
    speed_lower_err_line=zeros(1,row/12);%速度动态响应曲线的下误差线
    speed_upper_err_line=zeros(1,row/12);%速度动态响应曲线的上误差线
    current_lower_err_line=zeros(1,row/12);%电流动态响应曲线的下误差线
    current_upper_err_line=zeros(1,row/12);%电流动态响应曲线的上误差线
    for i=1:row/2
        temp(1,i)=bitor(bitshift(alpha(1,2*i-1),8),alpha(1,2*i));%2个字节数据进行合并处理,经过这步处理后,每个数据内容由原本占用1X6的矩阵变为1X3的矩阵,其中第一个表示符号位,第二、三个表示数据数据位。
    end
    for j=1:row/6
        data(1,j)=bitor(bitshift(temp(1,3*j-1),8),temp(1,3*j));%将数据位合并
        if(temp(1,(3*j-2))==256)%判断符号位正负,移位后原本的负号标志1变为256
          data(1,j)=-data(1,j);
        end
    end
    for jj=1:row/12 %将电流数据和速度数据经行分类处理,并确定各自的误差带
       current_data(1,jj)=data(1,(2*jj-1));
       speed_data(1,jj)=data(1,(2*jj));
       speed_lower_err_line(1,jj)=(goal_speed+goal_speed*0.05);
       speed_upper_err_line(1,jj)=(goal_speed-goal_speed*0.05);
       current_lower_err_line(1,jj)=(goal_current+goal_current*0.05);
       current_upper_err_line(1,jj)=(goal_current-goal_current*0.05);
    end
     
    figure(1);%画出电流动态响应曲线
    hold on
      plot(1:5:(row/12)*5,current_data(1,1:row/12));
      plot(1:5:(row/12)*5,current_lower_err_line(1,1:row/12),'r--');%上误差线
      plot(1:5:(row/12)*5,current_upper_err_line(1,1:row/12),'r--');%下误差线
    hold off
      current_ave=mean(current_data(:));%求电流平均值
      %legend('name');
      title({['左轮开环空载电流时间图像(占空比:',num2str(duty),'%)'],['电流平均值:',num2str(current_ave),'mA/5ms']});
      xlabel('Time(ms)');
      ylabel('Current(mA)');
     
    figure(2)%画出速度动态响应曲线
    hold on
        plot(1:5:(row/12)*5,speed_data(1,1:row/12));
        plot(1:5:(row/12)*5,speed_upper_err_line(1,1:row/12),'r--');%上误差线
        plot(1:5:(row/12)*5,speed_lower_err_line(1,1:row/12),'r--');%下误差线
    hold off
    speed_ave=mean(speed_data(:));%求转速平均值
    %legend('name');
    title({['左轮空载脉冲时间图像(占空比:',num2str(duty),'%  P:',num2str(s_P),'  I:',num2str(s_I),')'],['转速平均值:',num2str(speed_ave),'脉冲/5ms']});
    xlabel('Time(ms)');
    ylabel('Speed(脉冲)');
    saveas(gcf,'E:\毕业设计\Matlab\波形\空载\Speed\左轮\test1.jpg');%保存图像
    

    四、效果展示与分析:

    话不多说,直接上图展示:
    (1)空载下采用开环控制
    在这里插入图片描述
    在这里插入图片描述

    (2)空载下采用电流单闭环控制
    在这里插入图片描述
    在这里插入图片描述

    (3)空载下采用速度单闭环控制
    在这里插入图片描述
    在这里插入图片描述
    (4)空载下采用速度、电流双闭环控制
    在这里插入图片描述
    在这里插入图片描述
    本期就只给出空载下的效果图哈,下期给出负载下的效果图和个人调节双闭环的心得!想要学习的小伙伴记得关注我哈~
    从图像上来分析,在空载时若采用电流、速度闭环控制方式,其电流值出现超调量后快速趋于一个恒定值而波动,其调节时间最短;其速度值出现超调量后快速趋于期望值,调节时间最短,且调节过程较为平稳,没有太大的波动。
    相比于传统的目测法、经验法调节PID参数,采用辅助工具进行调参显然更具科学性!
    此外根据响应情况,我们可以快速的判断出该调节哪个参数、调大或者调小。


    五、操作指南:

    1、硬件连接、无线模块的配置、单片机程序设计
    依照自己的情况而定。
    2、上位机处理
    我所使用的串口助手是sscom5.13.1,具体使用步骤如下:
    在这里插入图片描述
    3、导入数据到MATLAB
    将数据文本的地址拷贝到MATLAB中,点击运行,进行数据处理。
    4、图像分析
    根据MATLAB生成的系统动态响应图像,借助第一节所提到的相关性能指标,进行参数调节。


    总结

    整篇文章涉及的内容庞杂,爱学习的小伙伴细品细品,相信你会学习到很多知识!鉴于我也是刚入门的C鸟,所以还请多多指教!有不懂的地方欢迎留言…

    展开全文
  • 基于RT1064的电磁巡线小车

    千次阅读 多人点赞 2020-10-29 21:46:41
    基于RT1064的电磁巡线小车 文章目录一、原理图二、使用步骤1.初始化参数2.中断函数3.代码整体总结新的改变功能快捷键合理的创建标题,有助于目录的生成...本文章是基于RT1064智能小车实现电磁巡线。 提示:以下是

    基于RT1064的电磁巡线小车


    本文章是基于RT1064让智能小车实现电磁巡线。


    提示:以下是本篇文章正文内容,下面案例可供参考

    使用步骤

    1.初始化参数

    代码如下(示例):

        DisableGlobalIRQ();
        board_init();
          //电机初始化
          //右轮转动方向设置
          gpio_init(D12, GPO, 0, GPIO_PIN_CONFIG);
          gpio_init(D13, GPO, 0, GPIO_PIN_CONFIG);
          //左轮转动方向设置
          gpio_init(D14, GPO, 0, GPIO_PIN_CONFIG);
          gpio_init(D15, GPO, 0, GPIO_PIN_CONFIG);
         //初始化电机PWN
          pwm_init(PWM1_MODULE3_CHB_D1, 1000, 10000);
          pwm_init(PWM1_MODULE3_CHA_D0, 1000, 10000);
          
          //舵机初始化
          pwm_init(PWM4_MODULE2_CHA_C30, 50, 800); 
          
          //初始化ADC模块
          adc_init(ADC_1,ADC1_CH4_B15,ADC_8BIT);
          adc_init(ADC_1,ADC1_CH3_B14,ADC_8BIT);
          
          //中断初始化
          pit_init();
          pit_interrupt_ms(PIT_CH1, 10);
          
        EnableGlobalIRQ(0);
    

    2.中断函数

    代码如下(示例):

          //AD采集
          for(int i=0;i<10;i++)
          {
            adcnumber_right_value[i]=adc_convert(ADC_1,ADC1_CH4_B15);
            adcnumber_left_value[i]=adc_convert(ADC_1,ADC1_CH3_B14);
          }      
          adcnumber_right=(adcnumber_right_value[4]+adcnumber_right_value[5])/2;
          adcnumber_left=(adcnumber_left_value[4]+adcnumber_left_value[5])/2;
          
          //越界判断
          if(adcnumber_right>10&&adcnumber_left>10)
          {
            gpio_set(D12, 0);
            gpio_set(D13, 1);
            gpio_set(D14, 0);
            gpio_set(D15, 1);        
          }
          else
          {
            gpio_set(D12, 0);
            gpio_set(D13, 0);
            gpio_set(D14, 0);
            gpio_set(D15, 0);          
          }
          
          
          //PID数据处理
          PIDRegulation(&pid_value, adcnumber_left-adcnumber_right)  
          
          //舵机控制
          pwn_serve=800+pid_value.result;
    

    3.代码整体

    main.c文件

    #include "headfile.h"
    
    uint32 pwn_serve_init = 800;
    
    
    main(void)
    {
        DisableGlobalIRQ();
        board_init();
          //电机初始化
          //右轮设置
          gpio_init(D12, GPO, 0, GPIO_PIN_CONFIG);
          gpio_init(D13, GPO, 0, GPIO_PIN_CONFIG);
          //左轮设置
          gpio_init(D14, GPO, 0, GPIO_PIN_CONFIG);
          gpio_init(D15, GPO, 0, GPIO_PIN_CONFIG);
          pwm_init(PWM1_MODULE3_CHB_D1, 1000, 10000);
          pwm_init(PWM1_MODULE3_CHA_D0, 1000, 10000);
          
          //舵机初始化
          pwm_init(PWM4_MODULE2_CHA_C30, 50, 800); 
          
          //初始化ADC模块
          adc_init(ADC_1,ADC1_CH4_B15,ADC_8BIT);
          adc_init(ADC_1,ADC1_CH3_B14,ADC_8BIT);
          
          //中断初始化
          pit_init();
          pit_interrupt_ms(PIT_CH1, 10);
          
        EnableGlobalIRQ(0);
        
        while (1)
        {
          //pwm_duty(PWM4_MODULE2_CHA_C30, pwn_serve_init); 
        }
    }
    

    isr.c文件

    #include "headfile.h"
    #include "isr.h"
    
    typedef struct
    
    typedef struct
    {
      int KP;//比例系数
      int KI;//积分系数
      int KD;//微分系数
      int lasterror_1;//前一拍偏差  
      int lasterror_2;//前两拍偏差
      int result;//输出值
    }PID;
    
    
    
    //初始化pid参数
    PID pid_value={3,0,30,0,0,0};
    
    
    //ADC采集
    int adcnumber_right_value[10]={0}; 
    int adcnumber_left_value[10]={0};
    
    
    int pwn_serve=800;
    
    //PID算法
    void PIDRegulation(PID *vPID, int thiserror)
    {
      vPID->result = vPID->KP * ( thiserror - vPID->lasterror_1 ) + vPID->KI * thiserror + vPID->KD * ( thiserror - 2 * vPID->lasterror_1 + vPID->lasterror_2 );
      vPID->lasterror_2 = vPID->lasterror_1;
      vPID->lasterror_1 = thiserror;
    }
    
    
    void CSI_IRQHandler(void)
    {
        CSI_DriverIRQHandler();     //调用SDK自带的中断函数 这个函数最后会调用我们设置的回调函数
        __DSB();                    //数据同步隔离
    }
    
    void PIT_IRQHandler(void)
    {
        if(PIT_FLAG_GET(PIT_CH0))
        {
          PIT_FLAG_CLEAR(PIT_CH0);
        }
        
        if(PIT_FLAG_GET(PIT_CH1))
        {  
        
    	  int adcnumber_right=0;
    	  int adcnumber_left=0;
          //AD采集
          for(int i=0;i<10;i++)
          {
            adcnumber_right_value[i]=adc_convert(ADC_1,ADC1_CH4_B15);
            adcnumber_left_value[i]=adc_convert(ADC_1,ADC1_CH3_B14);
          }      
          adcnumber_right=(adcnumber_right_value[4]+adcnumber_right_value[5])/2;
          adcnumber_left=(adcnumber_left_value[4]+adcnumber_left_value[5])/2;
          
          //越界判断
          if(adcnumber_right>10&&adcnumber_left>10)
          {
            gpio_set(D12, 0);
            gpio_set(D13, 1);
            gpio_set(D14, 0);
            gpio_set(D15, 1);        
          }
          else
          {
            gpio_set(D12, 0);
            gpio_set(D13, 0);
            gpio_set(D14, 0);
            gpio_set(D15, 0);          
          }
          
          
          //PID数据处理
          PIDRegulation(&pid_value, adcnumber_left-adcnumber_right);
          
          //舵机控制
          pwn_serve=800+pid_value.result;//800为舵机中值
          pwm_duty(PWM4_MODULE2_CHA_C30,pwn_serve); 
           
          PIT_FLAG_CLEAR(PIT_CH1);//清除中断标记位
        }
        
        if(PIT_FLAG_GET(PIT_CH2))
        {
            PIT_FLAG_CLEAR(PIT_CH2);
        }
        
        if(PIT_FLAG_GET(PIT_CH3))
        {
            PIT_FLAG_CLEAR(PIT_CH3);
        }
    
        __DSB();
    }
    
    
    void GPIO2_Combined_16_31_IRQHandler(void)
    {
        if(GET_GPIO_FLAG(B15))
        {
            CLEAR_GPIO_FLAG(B15);//清除中断标志位
        }
    }
    
    
    
    void GPIO2_Combined_0_15_IRQHandler(void)
    {
        if(GET_GPIO_FLAG(MT9V03X_VSYNC_PIN))
        {
            //不用清除标志位,标志位在mt9v03x_vsync函数内部会清除
            if(1 == flexio_camera_type)mt9v03x_vsync();
        }
        if(GET_GPIO_FLAG(SCC8660_VSYNC_PIN))
        {
            //不用清除标志位,标志位在scc8660_vsync函数内部会清除
            if(2 == flexio_camera_type)scc8660_vsync();
        }
    }
    
    
    

    总结

    注意事项
    (1)本文章的使用了tb6612电机驱动芯片对电机进行驱动。
    (2)各个函数的操作都可以在相应的库里的.c文件和.h文件里查找。
    展开全文
  • 基于RT1064的MPU6050,DMP的移植与使用

    千次阅读 2019-12-14 00:14:18
    MPU6050是一款六轴(三轴加速度+三轴角速度(陀螺仪))传感器,该传感器广泛用于四轴、平衡和空中鼠标等设计,具有非常广泛的应用范围。但在实践中,如制作平衡,四旋翼时,我们需要得到横滚角(roll ),俯仰角...

    概述

            MPU6050是一款六轴(三轴加速度+三轴角速度(陀螺仪))传感器,该传感器广泛用于四轴、平衡车和空中鼠标等设计,具有非常广泛的应用范围。但在实践中,如制作平衡车,四旋翼时,我们需要得到横滚角(roll ),俯仰角(yaw )和偏航角(pitch)等姿态信息。但是,使用MPU6050时从中只能得到各方向的加速度角速度,并不能直接得到角度信息。就得利用我们的原始数据,进行姿态融合解算如卡尔曼滤波算法,这个比较复杂,知识点比较多,初学者不易掌握。而 MPU6050 自带了数字运动处理器,即 DMP( Digital Motion Processor),并且,InvenSense提供了一个 MPU6050 的嵌入式运动驱动库,结合 MPU6050 的 DMP,可以将我们的原始数据直接转换成四元数输出。而得到四元数之后,就可以很方便的计算出欧拉角,从而得到 yaw、roll 和 pitch。使用MPU6050内置的 DMP,大大简化了四轴和平衡车的代码设计,且 MCU 不用进行姿态解算过程,可以减少软件的开发周期,大大降低了 MCU 的负担,从而有更多的时间去处理其他事件,提高系统实时性。

            本文是基于恩智浦的MCU,RT1064,使用逐飞RT1064开源库,对InvenSense 提供的 MPU6050 运动驱动库进行移植,其中还借鉴了正点原子STM32的MPU6050例程。经过这次移植,我得出学会了一种芯片的DMP移植就可以一以贯之地将DMP方便地移植到其他芯片上去。从而使DMP硬件解算的方法成为MPU6050姿态解算除了软件解算外的另一种选择。

    准备阶段

    •  关于MPU6050,因为对实际的应用不甚了解,我之前搜集了大量关于MPU6050的信息。然而一旦有了实际需要,相信大家都会有的放矢地去了解有效的信息。关于MPU6050的信息网上有很多,在这里不再赘述,本文假设读者基本掌握对MPU6050的使用。
    • 芯片使用RT1064,使用逐飞的开源库。更改前后的工程代码将附于资源处方便比较。
    • MPU6050一块,杜邦线四根。
    • InvenSense的运动解算库,我又借鉴了STM32对于四元数合成姿态角的函数。

    移植过程

    • 上面就是运动解算库的六个文件,我们需要将他添加进自己的工程文件路径中
    • 并将inv_mpu.c和inv_mpu_dmp_motion_driver.c添加进工程,如图
    • 图片2
    • 运动解算库是根据msp430来编写的,我们需要更改库中的几个函数,这几个函数主要是和iic的读取和延时有关的,如图qwe
    • asd
    • 上面就是添加进工程的两个文件中需要改动的地方,其中使用宏定义的方式进行了函数的替换,比如使用i2c_write函数的地方实际上是使用了mpu_write_regs.
    • i2c_write,i2c_read,delay_ms,get_ms处的宏定义都需要替换成自己使用的i2c库函数还有延时函数库中对应的函数,其中mpu_write_regs和mpu_read_regs是因为库函数中没有对应的函数,我自己对库函数进行改造而成的函数,大家在移植的过程中要注意不一定能找到合适的函数来替代,这时候就需要对已有的库函数进行改造。
    • 123
    • 上面就是我对库函数改造而成的函数,要注意找替代函数的时候要看define上面的注释,上面标明了函数的参数和顺序,如果发现库函数没有合适的,那就需要自己来改了。
    • 改完之后就可以进行编译,然而事情并没有那么顺利,肯定会报一堆错误,不过这些都是小错误,大家只需要按照编译器给出的提示来改就可以了,最重要的还是我刚刚提到的函数的替换
    • 最后别忘了在main.c中包含运动解算库的头文件
    • #include "inv_mpu.h"
      #include "inv_mpu_dmp_motion_driver.h"

      这样我们的运动解算库就算移植好了,接下来进入使用阶段

     

    使用解算库得到姿态角实验

    贴出main的代码,删去了一些和mpu无关的东西,并可以将角度显示在屏幕上

    /*********************************************************************************************************************
     * COPYRIGHT NOTICE
     * Copyright (c) 2019,逐飞科技
     * All rights reserved.
     * 技术讨论QQ群:一群:179029047(已满)  二群:244861897
     *
     * 以下所有内容版权均属逐飞科技所有,未经允许不得用于商业用途,
     * 欢迎各位使用并传播本程序,修改内容时必须保留逐飞科技的版权声明。
     *
     * @file       		main
     * @company	   		成都逐飞科技有限公司
     * @author     		逐飞科技(QQ3184284598)
     * @version    		查看doc内version文件 版本说明
     * @Software 		IAR 8.3 or MDK 5.24
     * @Target core		NXP RT1064DVL6A
     * @Taobao   		https://seekfree.taobao.com/
     * @date       		2019-04-30
     ********************************************************************************************************************/
    
    
    //整套推荐IO查看Projecct文件夹下的TXT文本
    
    
    
    //打开新的工程或者工程移动了位置务必执行以下操作
    //第一步 关闭上面所有打开的文件
    //第二步 project  clean  等待下方进度条走完
    
    
    #include "SEEKFREE_FONT.h"
    #include "headfile.h"
    
    
    
    #include "inv_mpu.h"
    #include "inv_mpu_dmp_motion_driver.h"
    
    float pitch,roll,yaw; 		//?·à-??
    short aacx,aacy,aacz;		//?ó?ù?è′??D?÷?-ê?êy?Y
    short gyrox,gyroy,gyroz;
    uint32 t; 
    short temp;
    int main(void)
    {
        DisableGlobalIRQ();
        board_init();   //务必保留,本函数用于初始化MPU 时钟 调试串口
        
    	systick_delay_ms(100);	//延时100ms,等待主板其他外设上电成功
    	
        lcd_init();
        lcd_clear(WHITE);
        simiic_init();
        //引脚链接查看SEEKFREE_IIC h文件的引脚定义
        mpu6050_init();
        
        lcd_showstr(0,0,"test");
        
        EnableGlobalIRQ(0);
        while(mpu_dmp_init())
     	{
              lcd_showstr(0,1,"error");
              systick_delay_ms(200);
              lcd_showstr(0,1,"     ");
              systick_delay_ms(200);
            }
        
        lcd_showstr(0,1,"Pitch");
        lcd_showstr(0,2,"Roll");
        lcd_showstr(0,3,"Yaw");
        while(1)
        {
            if(mpu_dmp_get_data(&pitch,&roll,&yaw)==0)
            { 
    		if((t%10)==0)
                    { 
                        temp=pitch*10;
                        lcd_showint8(40,1,temp/10);
                        temp=roll*10;
                        lcd_showint8(40,2,temp/10);
                        temp=yaw*10;
                        lcd_showint8(40,3,temp/10);
                    }
                    t++;
            }
                    
                    
         }
    
        
    }
    

    要注意上面的mpu_dmp_init()初始化函数要不停地检测,因为刚开始上电时dmp需要初始化一段时间,这时候有可能读不出来会报错,但不要担心,等一秒基本就恢复成正常了

    总结

    虽然只是rt1064上mpu6050运动解算库的移植,但是熟悉了这套过程后大家在其他MCU上移植dmp也不再话下,我认为多去尝试新技术是十分有必要的。dmp输出有200Hz,已经可以满足大部分需求,但是据说采样频率还是不够快,如果是做竞速平衡车的话会影响速度上限。文章有不足之处,还请多交流。

    展开全文
  • 本WIFI智能小车基于RT5350(RT 5350数据手册)无线wifi模块以及外接功能模块设计完成。 该WIFI智能小车结构上主要分为两部分:WIFI小车和输出MJPG的USB/CMOS二合一摄像头。 小车电路设计主要包括:电源部分、电机驱动...
  •   今天(2021-05-16)收到一位参加智能车竞赛的学生发送过来的信息,它对于逐飞RT1064的库进行了GCC 移植: 卓大大,我为逐飞的 RT1064 库做了一下 GCC 移植,希望能帮到使用 RT1064 但是因为各种原因无法用 ...
  • 本WIFI智能小车基于RT5350(RT 5350数据手册)无线wifi模块以及外接功能模块设计完成。该WIFI智能小车结构上主要分为两部分:WIFI小车和输出MJPG的USB/CMOS二合一摄像头。小车电路设计主要包括:电源部分、电机驱动...
  • 前言 生活中我们使用RGB颜色空间更多一些,但在计算机视觉中,尤其颜色识别相关的算法设计中,rgb,hsv,...15届全国大学生智能车竞赛即将到来,逐飞新出品了一款名为“凌瞳”的彩色摄像头,分辨率最高可达VGA(480*6...
  • 上期回顾:RT-Thread智能车目标识别系统连载教程——手写体识别模型 (1)RT-Thread智能车目标识别系统连载教程——训练卷积神经网络模型(2)RT-Thread智能车目标识别...
  • 上期回顾:RT-Thread智能车目标识别系统连载教程——手写体识别模型 (1)这里会介绍如何训练图像领域应用非常广的卷积神经网络 (Convolutional Neural Netwo...
  • 上期回顾:RT-Thread智能车目标识别系统连载教程——手写体识别模型 (1)RT-Thread智能车目标识别系统连载教程——训练卷积神经网络模型(2)RT-Thread智能车目标识别...
  • 2019.3一2019.7 基于MK60DN512ZVLQ10 的室外自动寻迹智能越野(集体项目)  2020.3一2020.7 基于NXP ...此项目为第十四届、第十五届全国大学生恩智浦杯智能汽车竞赛室外越野竞速项目,依照组委会公布的比赛规则,
  •   一、专项奖说明   在第十六届全国大学生智能汽车竞赛中引入了多种MCU类型应用于不同的赛题组,包括有Infineon, STC, ...  在第十六届智能车竞赛中,RT-Thread公司进行了赞助。为了鼓励参赛同学在制作车模.
  • RT-Thread与智能车比赛

    2021-02-11 09:11:33
    RT-Thread与智能车比赛     在第十六届全国大学生智能汽车竞赛中引入了多种MCU类型应用于不同的赛题组,包括有Infineon, STC, WCH, MindMotion,NXP等。在智能车控制系统开发过程中中引入实时嵌入式操作系统...
  • 本程序是基于RT1064芯片的智能车比赛程序。拥有NXP工程师的模型调用,具体的模型训练,模型的始数据收集需要自己阅读NXP工程师给的新手教程。小车比赛跑了12秒左右,算不上厉害,但是对于初学者或者以后想使用AI比赛...
  • 在验证AI算法是否可以用在智能小车的运行时,我们曾经考虑过不是让AI模型输出舵机控制信号,而是输出小车的姿态信息,简单地说就是“偏左”、“偏右”或“正好”这几种信息,然后再用传统的PID算法产生舵机控制信号...
  • 这篇文章假定大家都已经会用 RT-Thread 的 env 工具下载软件包,并且生成项目上传固件到 stm32 上,因为这几天的两篇连载文章重点在于加载 onnx 通用机器学习模型,关于 RT-Thread 的教程大家可以在官网文档中心: ...
  • 基于东软载波es32+RT-Thread RTOS入门实战篇-如何快速构建一个智能小车
  • ...现在我们已经有了 RT-Thread 支持的 protobuf 软件包,下一步就是弄清楚 onnx 模型的格式到底是怎么定义的了,关于 onnx 数据格式的完整定义可以在这里看到。 onnx 数据格式定义:  ...
  • 1# Untitled - By: RT-Thread - 周五 7月 19 2019 2 3import sensor, image, time, lcd 4from fpioa_manager import * 5from Maix import GPIO 6import os 7 8def getMax(): 9 max...
  • 基于东软载波es32+RT-Thread RTOS入门实战篇-如何快速构建一个智能小车
  • 第十五届全国大学生智能汽车竞赛 基础四轮组总结

    千次阅读 多人点赞 2020-08-30 21:56:35
    第十五届全国大学生智能汽车竞赛 基础四轮组总结一、方案循迹:纯电磁硬件比赛过程总结 一、方案 1.车模:C1 2.主控:RT1064 3.传感器:电磁循迹、红外对管+干簧管识别斑马线 循迹:纯电磁 1.电感排布:七个电感,...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,518
精华内容 1,007
关键字:

rt1064智能车