K210视觉机械臂发送坐标值(与下位机通信)

本文作者水平尚且有限,如有不对的地方,期待您的指正。

我参考了一些文章,很多博主是用stm32做下位机来做控制,但我目前还未接触,所以用的51单片机。

萌发了一个想法,做智能捡网球的小车,先从机械臂上做起,机械臂上的细节也很多,一个一个问题慢慢克服。

K210视觉机械臂的设想

K210摄像头是固定的,要夹取的物品也是静止不动的

C51端利用最小单片机系统,控制舵机,一个机械臂由多个舵机("手臂关节")组成。

工作原理:K210识别出要夹取的物体并将所要夹取的物体横纵坐标值(X,Y)传输给51单片机,X和Y的值通过数学计算,控制舵机的上下左右平移,到达目标位置,实现夹取的功能。

构想图如下:

上面是一个整体的畅想,一步一步来,这篇文章仅谈如何实现C51和K210的通信,实现将坐标传送过去,并能接收到。

k210发送数据:

from machine import UART,Timer
from fpioa_manager import fm
import time
fm.register(6, fm.fpioa.UART1_RX, force=True)
fm.register(7, fm.fpioa.UART1_TX, force=True)
hengzuobiao = 256
zongzuobiao = 257
class K210_transmit():                              
    head1  = 0xAA                                                                   
    x      = hengzuobiao                                       
    y      = zongzuobiao                                                                     
    head2  = 0xAA
    mo  = 0xab
K210 = K210_transmit()                            

def K210_data():                                  
    data=bytearray([K210.head1,                                          
                    K210.x>>8,K210.x,            
                    K210.y>>8,K210.y,            
                    K210.head2,K210.mo])                        
    return data
uart = UART(UART.UART1, 9600, read_buf_len=4096)
while True:
        uart.write(K210_data()) #数据回传
        time.sleep(1)

坐标值先直接给出:hengzuobiao = 256 zongzuobiao = 257。我们先实现通信,后续再做K210端返回识别物体的坐标。

代码解析:k210能自由映射引脚,我将引脚6设为RXD,引脚7设为TXD。定义了一个类,用来保存串口要发送的信息。设计了head1 = 0xAA 和 mo = 0xab 将核心数据"夹住",这样的话,在51端,我们就可以判断是否接收到了这一串数据。

uart = UART(UART.UART1, 9600, read_buf_len=4096)

串口的初始化配置,k210共两个串口,这个是串口一,波特率设置的是9600,因为我这边出厂的HC-05蓝牙模块没有内部修改,一直是9600,为保持一致。(HC-05蓝牙用在后面的测试),uart.write()用来发送。

实验心得:一步一步来,到这一步的时候,我们有些担心是否现在发送的数据就是上面代码的值?这个发送有没有出错?先确认这一步的发送是正确的,这样等我们慢慢往后搭建下一步接收的时候,就不用再去找之前发送的问题了;这里我用HC-05蓝牙模块来测试数据的发送。HC-05蓝牙模块的使用超级简单入门,如有疑问,可以参考我这篇文章: C51单片机利用HC-05蓝牙模块实现手机点灯_良辰353的博客

启动运行K210那边的程序,接线图与现象图如下:

从现象可见,数据发送成功!我们的核心数据在里面! X = 01 *256 + 00 = 256; Y =01 *256 +01 = 257

可以看见我们的每一个发送的数据包是七位数据。

在这之前,绕进了一个坑,因为k210在发送数据的时候只能发字符串类的,就是uart.write(),直接发256,257是发不过去的。然后思路就是把257,257转为"256","257",发过去在提取出来整型,可51端那里,用不了atoi()函数,这是一个可以把字符型转为整型的函数,在C编译器能用,在Keil里会提醒少一个文件,去网上找也有,全是付费下载的,我真的晕...后来参考其他博主看到这个方法了。打包在一起,又都是整型,在51端,做个乘256的计算就OK了,非常nice!

C51接收数据:

#include <REGX52.H>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#define MAX_SIZE 8
unsigned char Buffer[MAX_SIZE];
unsigned char dat;
unsigned int x,y;
unsigned int Receive_count = 0;
void UART_init()   
{
      TMOD = 0x20;
      TH1 = 0xfd;
      TL1 = 0xfd;  
      SM0 = 0;  
      SM1 = 1;   
      REN = 1;  
      TR1 = 1;
      EA = 1;
      ES =1 ;  
}

void UART_SendByte(unsigned char Byte)  
{
   SBUF = Byte;
    while(TI == 0);
     TI = 0; 
}
char putchar(char c)//閲嶅畾鍚?
{
    UART_SendByte(c);
    return c;
}
void main()
{
    
    UART_init();
    
  while(1)
    {
    }

}
void UART_INTERRUPT() interrupt 4
{   
        dat = SBUF;
        RI = 0;//手动置0是下一次能够进入中断的关键
        if(dat != 0xab)//判断是否接收完成我的那串数据了?
        {
            Buffer[Receive_count] = dat;
            Receive_count ++;
            if(Receive_count == MAX_SIZE)
            {
                x = Buffer[1]*256+Buffer[2];
                y = Buffer[3]*256+Buffer[4];
                if(Buffer[0] == 0xAA && Buffer[5] == 0xAA && x == 256 && y == 257)
                {
                    printf("the test was successful");
                }
                else
                {
                    printf("the test failed!");
                }
            }
        }
}

这里先总结一下我学习到的51单片机的串口通信:

void UART_init()   
{
      TMOD = 0x20;
      TH1 = 0xfd;
      TL1 = 0xfd;  
      SM0 = 0;  
      SM1 = 1;   
      REN = 1;  
      TR1 = 1;
      EA = 1;
      ES =1 ;  
}

串口的初始化,可以自己在 stc-isp上勾选生成,勾选9600波特率,这点要切记,两单片机之间的通信,波特率必须保持一致。模式一,八位数据等,EA,ES是总中断。

如图你可以看到51单片机串口通信的工作流程,RX和TX分别是发送数据和接收数据,比如,本来RI和TI两个管理着一个"闸门",内部配置好的RI和TI都是0,当接收到数据时,系统会将RI自动置1,只要我们将后面的"闸门"配置好都接通,这时就是打开中断了,就可以写中断函数(51的串口通信中断是interrupt 4),同理发送数据的时候是TI=1 ,同样地打开中断。但是寄存器SBUF一次性只能存一个字节的数据,如果像前面我们发的七个数据都想过去,就需要进入中断函数后,再手动置0,等待下一个数据发送时,RX---->致RI = 1再进中断,再提取数据。

SBUF寄存器的介绍:SBUF是用来存取数据的,在51单片机的系统内部,但dat=SBUF 和SBUF=dat是不一样的,dat = SBUF是我们自己创的一个变量dat来存装接收到的数据,SBUF=dat则是将数据发送出去,是同一个SBUF,但是功能不同,参考文章中有讲,底层配置时其实是两个的,这里不多再深探索。

定义一个数组用来存装每次传来的数据是很关键的一步,我之前以为dat = SBUF就可以一次性把数据都接来了,然后我就自以为的定义了一个dat[7],以为数据分别装进每个[0],[1],[2]里面了,后来怎么都提不出来,因为根本就没有dat[2],dat[3]这些数!记住,我们的中断函数一次性接收到一个字节的数据后就跳出中断了,所以我们想提取出我们的核心数据,就要写个数组Buffer[],每次接收到一个数据后就赶紧把它存进去,这时候,我们K210发送的数据mo = 0xab就有作用了,作为我们发送的一串数据的末尾,就能用来判断数据的发送完成。

void UART_SendByte(unsigned char Byte)  
{
   SBUF = Byte;
    while(TI == 0);
     TI = 0; 
}
char putchar(char c)
{
    UART_SendByte(c);
    return c;
}

这两段函数是为了实现printf函数,比如说我们写printf("Hello,world");先将寄存器SBUF为"H",TI = 0表示接收完成,while(TI ==0);是判断是否接收完成,如果没有完成,就是TI ==0,让程序在循环里在等等,然后退出循环后,将TI打成0,等'e',进入....最后实现打印在串口通信助手上的效果,可参考之前有写的一篇51的printf()51单片机也能用printf()函数进行调试_良辰353的博客

终于到这一刻了!x,y就是我们想要的坐标值。

接线图:

一键启动发送数据

HEX显示不勾选,因为我们发的是字符串数据

波特率9600同C51同K210

外界问题总结:

烧录HEX文件时,串口调试器要关闭,因为此时是PC连了51占用了串口。

烧录时,先拔开与K210的接线,因为K210在通电,会干扰到相接的51的引脚。

现象:

猜你喜欢

转载自blog.csdn.net/qq_62262788/article/details/128673681