基于CW32的K210二维舵机视觉跟踪物体

这篇具有很好参考价值的文章主要介绍了基于CW32的K210二维舵机视觉跟踪物体。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言
最近想要做一个项目是涉及用国产MCU--CW32配合K210控制舵机实现跟踪物体的目的,我想要实现一个功能就是识别到目标并且把目标的坐标信息通过串口传输给单片机,单片机控制舵机进行控制,那么视觉方面目前我认为最好的选择就是使用k210了,它不仅成本低,性能好,而且基于MicroPython的开发极易上手,单片机选用的是武汉芯源半导体公司的国产芯片CW32.

什么是CW32

CW32是武汉芯源半导体推出的基于Cortex-M0+内核的32位微控制器:CW32系列MCU,该系列MCU在多项指标上大幅领先于其他品牌同类产品,可以满足通用、低成本、超低功耗以及高性能等不同应用市场的MCU需求。

什么是k210:
K210 是嘉楠(Cannaan)科技的一款集成机器视觉与机器听觉能力的系统级芯片 (RSIC-V CPU)。使用台积电 (TSMC) 超低功耗的 28 纳米先进制程,具有双核 64 位处理器,拥有较好的功耗性能,稳定性与可靠性。该方案力求零门槛开发,可在最短时效部署于用户的产品中,赋予产品人工智能(AI)。 可以说是集性能强劲与高性价比于一身。
 

 一、CW32根据K210串口传回来的数据输出PWM控制舵机进行跟踪

    CW32F030x6/x8 是基于 eFlash 的单芯片微控制器,集成了主频高达 64MHz 的 ARM® Cortex®-M0+ 内核、高速嵌入式存储器(多至 64K 字节 FLASH 和多至 8K 字节 SRAM)以及一系列全面的增强型外设和 I/O 口。
所有型号都提供全套的通信接口(三路 UART、两路 SPI 和两路 I2C)、12 位高速 ADC、七组通用和基本定时器以及一组高级控制 PWM 定时器。
CW32F030x6/x8 可以在 -40° C 到 105° C 的温度范围内工作,供电电压宽达 1.65V ~ 5.5V。支持 Sleep 和DeepSleep 两种低功耗工作模式。

基于CW32的K210二维舵机视觉跟踪物体,python,c语言

通用异步收发器 (UART) 支持异步全双工、同步半双工和单线半双工模式,支持硬件数据流控和多机通信;可编程数据帧结构;可以通过小数波特率发生器提供宽范围的波特率选择。
UART 控制器工作在双时钟域下,允许在深度休眠模式下进行数据的接收,接收完成中断可以唤醒 MCU 回到运行模式
本例程中选用的串口1

详细代码如下

1.配置系统时钟

void RCC_Configuration(void)
{
    // 1. HSE 使能&校准,外部晶振频率=8MHz
    RCC_HSE_Enable(RCC_HSE_MODE_OSC,8000000, RCC_HSE_DRIVER_NORMAL, RCC_HSE_FLT_CLOSE);
    
    // 2. 设置 HCLK&PCLK的 分频系数
    RCC_HCLKPRS_Config(RCC_HCLK_DIV1);
    RCC_PCLKPRS_Config(RCC_PCLK_DIV1);
    
    // 3. 使能 PLL,6倍频至 48MHz
    RCC_PLL_Enable(RCC_PLLSOURCE_HSEOSC, 8000000, 6);
    RCC_PLL_OUT();
    
    // 4. 设置 Flash读等待周期:48M≥时钟源HCLK>24M,为 2cycle;时钟源HCLK>48M,为 3cycle
    __RCC_FLASH_CLK_ENABLE();
    FLASH_SetLatency(FLASH_Latency_2);
    
    // 5. 切换时钟至 PLL
    RCC_SysClk_Switch(RCC_SYSCLKSRC_PLL);
    RCC_SystemCoreClockUpdate(48000000); //48000000
}


2.初始化IO口

  void GPIO_Configuration(void)
{
    // 使能 GPIOB时钟:因为使用了 PB06(M4电机)& PB07(M3电机)引脚
    __RCC_GPIOB_CLK_ENABLE();
    
    // 使能 GPIOA时钟:因为使用了 PA08(M1电机)& PA11(M2电机)引脚
    __RCC_GPIOA_CLK_ENABLE();
    
    
 
    
    // 配置 计时器:GTIM3_CH4(PA12引脚)
    PA12_AFx_GTIM3CH4();
    PA12_DIGTAL_ENABLE(); // 使能 数字方式
    PA12_DIR_OUTPUT(); // 输出
    PA12_PUSHPULL_ENABLE(); // 模式:推挽输出
    PA12_SPEED_HIGH(); // 高速
    
    
    // 声明 GPIO端口初始化配置
    GPIO_InitTypeDef GPIO_InitStructure;
    
    // 中断方式:选择 不使用
    GPIO_InitStructure.IT = GPIO_IT_NONE;
    
    // 模式:推挽输出
    GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
    
 
    
    // 配置 计时器:ATIM_CH2A(PB06引脚)
    PB06_AFx_ATIMCH2A();
    
    // 初始化 PB06(Y)引脚
    GPIO_Init(CW_GPIOB, &GPIO_InitStructure);
    
    
    // 选择引脚:PB07(X)引脚
    GPIO_InitStructure.Pins = GPIO_PIN_7;
    
    // 配置 计时器:ATIM_CH3A(PB07引脚)
    PB07_AFx_ATIMCH3A();
    
    // 初始化 PB07 引脚
    GPIO_Init(CW_GPIOB, &GPIO_InitStructure);
    
    
    

}

3.初始化串口以及串口接收函数

void UART_init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    


     RCC_APBPeriphClk_Enable2(RCC_APB2_PERIPH_UART1, ENABLE);
     RCC_AHBPeriphClk_Enable( RCC_AHB_PERIPH_GPIOA, ENABLE);  

     PA08_AFx_UART1TXD();
     PA09_AFx_UART1RXD(); 
    
  GPIO_InitStructure.Pins = GPIO_PIN_8; //PA8
  GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;
  GPIO_Init(CW_GPIOA, &GPIO_InitStructure);
    
  GPIO_InitStructure.Pins = GPIO_PIN_9; //PA9
  GPIO_InitStructure.Mode = GPIO_MODE_INPUT_PULLUP;
  GPIO_Init(CW_GPIOA, &GPIO_InitStructure);
        

  USART_InitStructure.USART_BaudRate = 115200;
  USART_InitStructure.USART_Over = USART_Over_16;
  USART_InitStructure.USART_Source = USART_Source_PCLK;
  USART_InitStructure.USART_UclkFreq = 64000000;
  USART_InitStructure.USART_StartBit = USART_StartBit_FE;
  USART_InitStructure.USART_StopBits = USART_StopBits_1;
  USART_InitStructure.USART_Parity = USART_Parity_No ;
  USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
  USART_Init(CW_UART1, &USART_InitStructure); 
    
    
  //使能UARTx RC中断
  USART_ITConfig(CW_UART1, USART_IT_RC, ENABLE);
  //优先级,无优先级分组
  NVIC_SetPriority(UART1_IRQn, 0);
  //UARTx中断使能
  NVIC_EnableIRQ(UART1_IRQn);

}
 

void UART1_IRQHandler(void)
{
  /* USER CODE BEGIN */
static int i=0; //注意不同数组不要用同一个变量!
   
  if(USART_GetITStatus(CW_UART1, USART_IT_RC) != RESET)
  { 
        USART_ClearITPendingBit(CW_UART1, USART_IT_RC); 
        k210_data[i++] =USART_ReceiveData_8bit(CW_UART1); //接收数据        
   
        
        if(k210_data[0]!=0xa3) i=0;                   //判断第一个帧头
        
        if((i==2)&&(k210_data[1]!=0xb3)) i=0;      //判断第二个帧头
      
     if(i==7)                                         //代表一组数据传输完毕
        {    PA00_SETHIGH(); 
            i = 0;
            if( k210_data_test(k210_data) )           //判断数据合理性
            {
            /****************************************************
                                                            更新数据
             ****************************************************/    
                //【1】x误差:
                  
                k210_error_x = k210_data[2];
                
                //【2】x标志位:
                x_flag = k210_data[3];
                
                //【3】x误差:
                k210_error_y = k210_data[4];
                
                //【4】x标志位:
                y_flag = k210_data[5];
                
                lenth = k210_data[6];
           //   Data_Handle();
              OLED_Show();
               
             }
         }
  /* USER CODE END */
}
}

5.X轴与Y轴的误差通过PID算法得到的值输出PWM控制舵机

 

int PID_xCalc(int error_x)
{
     float Pout_x;
//     float Iout;
     float Dout_x;
//     float DelEk;
     float out_x; 
  //判断时间......

  if(pid.C1ms>(pid.T_x)/*||    (Circle_Flag==4)|| Circle_Flag==2*/)  
    {
    pid.Pv_x = error_x;
      pid.Ek_x=pid.Pv_x-pid.Sv_x; //P
       Pout_x=pid.Kp_x*pid.Ek_x;
       Dout_x=pid.Kd_x*(pid.Ek_x-pid.Ek_1_x);
         out_x = Pout_x+Dout_x;
     pid.OUT_x=out_x;

    if(pid.OUT_x>pid.pwmcycle_x)  {pid.OUT_x=pid.pwmcycle_x;  }
    if(pid.OUT_x<-pid.pwmcycle_x)  {pid.OUT_x=-pid.pwmcycle_x;  }

 
        pid.Ek_1_x=pid.Ek_x;


        pid.C1ms=0;
          return pid.OUT_x;
    }

}
int PID_yCalc(int error_y)
{
     float Pout_y;
//     float Iout;
     float Dout_y;
//     float DelEk;
     float out_y; 
  //判断时间......
  if(pid.C2ms>(pid.T_y)/*||    (Circle_Flag==4)|| Circle_Flag==2*/) 
    {
    pid.Pv_y = error_y;
      pid.Ek_y=pid.Pv_y-pid.Sv_y; //P
       Pout_y=pid.Kp_y*pid.Ek_y;
       Dout_y=pid.Kd_y*(pid.Ek_y-pid.Ek_1_y);
         out_y = Pout_y+Dout_y;
     pid.OUT_y=out_y;
         //判断并修正输出结果
      if(pid.OUT_y>pid.pwmcycle_y)  {pid.OUT_y=pid.pwmcycle_y;  }
      if(pid.OUT_y<-pid.pwmcycle_y)  {pid.OUT_y=-pid.pwmcycle_y;  }

 
        pid.Ek_1_y=pid.Ek_y;


        pid.C2ms=0;
     return pid.OUT_y;
    } 
    
}


 二、K210获取物体x轴y轴的位置通过串口把数据传给单片机

导入模块

from machine import Timer,PWM
import sensor, image, lcd
from fpioa_manager import  fm
from Maix import GPIO 
from machine import UART
 
配置串口
fm.register(10, fm.fpioa.UART1_TX, force=True)
fm.register(11, fm.fpioa.UART1_RX, force=True)
 
usart1 = UART(UART.UART1, 115200)
usart1.init(115200, bits=8, parity=None, stop=1) #初始化串口
 

设置颜色阈值

class Color_Property():
    cx                      =  0                            # 色块 x轴 中心坐标
    cy                      =  0                            # 色块 y轴 中心坐标
    flag                    =  0                            # 色块标志位 1 找到 0 未找到
    color                   =  0                            # 色块颜色标志位 例如 你可以用 1 来表示 黑色
    density                 =  0                            # 色块密度比 反映色块锁定程度 值越大 锁定程度越好
    pixels_max              =  0                            # 色块像素最大值
    led_flag                =  0                            # LED标志位 方便调试用
 
    color_threshold         = (0, 0, 0, 0, 0, 0)            # 色块颜色阈值
    color_roi               = (0,0,320,240)                 # 色块寻找区域(感兴趣区域)
    color_x_stride          =  1                            # 色块 x轴 像素最小宽度 色块如果比较大可以调大此参数 提高寻找速度
    color_y_stride          =  1                            # 色块 y轴 像素最小宽度 色块如果比较大可以调大此参数 提高寻找速度
    color_pixels_threshold  =  100                          # 色块 像素个数阈值 例如调节此参数为100 则可以滤除色块像素小于100的色块
    color_area_threshold    =  100                          # 色块 被框面积阈值 例如调节此参数为100 则可以滤除色块被框面积小于100的色块
    color_merge             =  True                         # 是否合并寻找到的色块 True 则合并 False 则不合并
    color_margin            =  1                            # 色块合并间距 例如调节此参数为1 若上面选择True合并色块 且被找到的色块有多个 相距1像素 则会将这些色块合并
 
 
# 红色
red  = Color_Property()
red.color_threshold           = (15, 35, -37, -13, 0, 39)
 
#red.color_roi                = (0,0,320,240)
red.color_roi                 = (0,110,320,20)
 
red.color_x_stride            =  1
red.color_y_stride            =  1
 
#red.color_pixels_threshold   =  100
#red.color_area_threshold     =  100
red.color_pixels_threshold    =  10
red.color_area_threshold      =  10
 
red.color_merge               =  True
red.color_margin              =  1
 
 初始化参数配置
sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA)
sensor.run(1)
 
#lcd初始化
lcd.init()
 
def find_max(blobs):
        max_size=0
        for blob in blobs:
            if blob[2]*blob[3] > max_size:
                max_blob=blob
                max_size = blob[2]*blob[3]
        return max_blob
 
获取误差
def get_target_err():
    img=sensor.snapshot()
    blobs = img.find_blobs([red.color_threshold])
    if blobs:
      max_blob = find_max(blobs)
      cx_error = max_blob.cx()-img.width()/2
      cy_error = max_blob.cy()-img.height()/2
      img.draw_rectangle(max_blob.rect()) # rect
      img.draw_cross(max_blob.cx(), max_blob.cy()) # cx, cy
      lcd.display(img)
      # 在这个范围【-5,5】,则认为在中心
      if abs(cx_error) < 10:
          cx_error = 0
      if abs(cy_error) <  10:
          cy_error = 0
      img = img.draw_cross(int(cx_error), int(cy_error))
 
      return (cx_error,cy_error)
    else:
      img = img.draw_cross(160, 120)
      lcd.display(img)
      return (0, 0)              #               没找到 就返回在中央坐标
 
#串口发送数据函数:
def usart_send(x, y):
    global Turn
    #【1】设置标志位:
    if x>=0:
            x_flag = 1
    if x<0 :
            x_flag = 0;
    if y>=0:
            y_flag = 1
    if y<0 :
            y_flag = 0;
 
    #【2】处理数据:
    x_err = int(x)
    y_err = int(y)
    #print(x_err,y_err)
    #【3】串口发送:
    data = bytearray([0xa3,0xb3, x_err,x_flag ,y_err , y_flag, 0xc3]) #帧头 + 帧头 + 循迹值 + 帧尾
    usart1.write(data)
 
while(True):
    cx_error,cy_error=get_target_err()  
    usart_send(cx_error,cy_error)

 文章来源地址https://www.toymoban.com/news/detail-626323.html

到了这里,关于基于CW32的K210二维舵机视觉跟踪物体的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • K210学习笔记(十):KPU之物体识别

    进行到KPU的又一个应用咯,其实跟前一个人脸识别的应用没有太多的不同。物体识别这里可是分类二十个物体,而人脸识别只是一个简单的二分类问题。(理论上机器学习也能做但是效果咋样就不知道了)。 大概的程序思路跟上一个实验也是一致的,将该用的函数库导入之后

    2024年02月13日
    浏览(45)
  • 智能送药小车(二)——K210物体检测,训练模型与部署

    线上训练模型参考这篇: Maixhub模型训练平台整体流程 下面仅介绍利用Mx-yolov3训练模型并部署在k210上的整体流程。 利用K210采集数据集 使用说明:插上合适的SD卡(最大32GB),采集不同类别图像时要在代码相应位置进行修改(有注释提示),程序运行后按下KEY会进行图像采集

    2024年02月14日
    浏览(44)
  • K210 Mx-yolov3模型训练和物体识别

    一、简介        (1)硬件准备:               K210开发板:拥有1TOPS算力,可以运行神经网络模型,同时其提供在线模型训练平台(maixhub),支持物体分类和物体识别。        (2)软件环境               Mx-yolov3:(用于在本地训练模型)             

    2024年02月15日
    浏览(45)
  • K210学习笔记(八):颜色识别计数与二维码识别

    宿醉断更enmmm(喝多太难受了)。前面我们介绍了使用K210进行颜色识别,在实际工程中,我们可能不止需要单纯的识别出来颜色,可能还需要计数(比如前段时间看到的有串串店利用摄像头拍照识别签子数的),当然,识别签子数肯定不是简单的颜色识别计数能解决的,为了

    2024年02月13日
    浏览(40)
  • K210学习笔记(二) K210与STM32进行串口通信,K210收,STM32发

    想用STM32通过串口给K210发数据,并在屏幕上显示,看了好几篇博客,终于搞通了,大家感兴趣也可以看看。 K210学习笔记(一) K210与STM32串口通信相关 接线,STM32的串口引脚比较固定,而K210就牛比了,任意映射,懒人福音。这里我找了两个没有被复用的IO,IO9和IO10 STM32 K210 GND

    2023年04月08日
    浏览(40)
  • K210视觉机械臂发送坐标值(与下位机通信)

    本文作者水平尚且有限,如有不对的地方,期待您的指正。 我参考了一些文章,很多博主是用stm32做下位机来做控制,但我目前还未接触,所以用的51单片机。 萌发了一个想法,做智能捡网球的小车,先从机械臂上做起,机械臂上的细节也很多,一个一个问题慢慢克服。 K2

    2024年02月14日
    浏览(62)
  • STM32与K210串口通信

    目录 1.前言  2.接线部分 3.代码部分 1.k210部分 1.调用自带的库文件 2.将I/O18设置为UART1_TX功能并设置串口 3.数据发送函数 4.主函数 4.程序现象 2.STM32部分 1主函数 2.串口接收程序 3.程序现象  4.完整代码 5.总结         这篇文章是为了填上一篇k210的简单PID巡线埋下的坑,k2

    2024年02月06日
    浏览(49)
  • K210和STM32串口通信(亲测有效)

    最近想做一个K210数字识别和寻迹,方便完成2021年电赛F题,完成了数字训练和脱机运行就想赶紧进行一次通信,调了好几天(郁闷+自闭几天),按照官方的历程看,配置的没问题但是会一直出现乱码,得不到自己想要的数据,所以准备发一下这个文章,希望帮助一下道友。 代码

    2024年02月14日
    浏览(41)
  • K210 UART串口通信介绍与 STM32通信

    目录 K210-UART串口通信相关函数: 使用K210串口的时候需要映射引脚: K210与STM32串口通信  发送单字节: K210端 STM32端 发送数据包 K210端 STM32端  K210的UART模块支持全双工通信,可以同时进行数据的发送和接收。在K210上使用UART串口通信,你可以连接外部设备,如传感器、显示器

    2024年03月23日
    浏览(47)
  • 基于K210的声源定位系统

    2022年全国大学生电子设计竞赛——声源定位跟踪系统(E题) 设计一种能够检测声音源的偏航角、俯仰角及距离来定位和指示声源的装置。水平方向上采用K210结合麦克风阵列采集不同方向麦克风的强度,从而计算偏航角和距离;从而控制舵机,将激光笔指到声源位置。 所需硬件

    2024年02月13日
    浏览(37)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包