总的思路是以openmv 接收蓝牙的指令,如果是自动选项,就在openmv 运行识别红球进行固定距离跟踪的程序;如果是手动选项,openmv就直接把所得到的数据传给STM32,不做其它处理。那这里就需要做两件事情,一个是要接收蓝牙传过来的数据,一个是给STM32输出指令。
通过测试,openmv是有1和3两个串口可用,那就用1接收数据,用3输出数据。(计划很理想,但是有bug)
串口通信
OpenMV本质还是一个单片机,可以通过调用pyb中的UART使用串口通信,注意发送的数据类型为字符串,可以通过json.dumps()进行字符串转换
数据类型为字符串
from pyb import UART
uart = UART(3, 9600)
uart.write('hello')
uart.read(5) # read up to 5 bytes
字符串转换
uart3.write(ujson.dumps(cxy)+'\r\n')
数据打包
def send_data_packet(x, y):#数据打包
temp = struct.pack("<bbii", #格式为俩个字符俩个整型
0xAA, #帧头1
0xAE, #帧头2
int(x), # up sample by 4 #数据1
int(y)) # up sample by 4 #数据2
uart.write(temp) #串口发送
接收蓝牙数据
串口接收数据
#串口接收数据
import time
from pyb import UART
uart = UART(3, 9600,time_out_char=1000)
while(True):
if uart.any():
a=uart.readline().decode.strip()
b=int(a)
print(b)
接收到a代表的数据,用b输出,decode为字符串,无回车换行,但是一般有回车换行简单些,那就要在输入的时候写上。
IO口通信接收指令
p_out = Pin('P7', Pin.OUT_PP)#设置p_out为输出引脚
p_out.high()#设置p_out引脚为高
p_in = Pin('P7', Pin.IN, Pin.PULL_UP)#设置p_in为输入引脚,并开启上拉电阻
串口接收
STM32是以中断的方式接收数据
#stm32串口接收是以中断的方式
void USART2_IRQHandler(void)
{
static uint8_t rebuf[8]={0},i=0;#中断子程序每进入一次,只会接收一个Byte的数据。也就是说接收完一帧数据需要进入8次中断才行。
if(USART_GetITStatus(USART2,USART_IT_RXNE) != RESET)#OpenMV_Rx_BUF是一个外部变量用于保存从openmv接收到的数据,中断子程序中,每当进入中断,会首先判断帧头,如果不是 帧头,会直接丢弃,直到等到帧头的到来。
{
rebuf[i++]=USART_ReceiveData(USART2);
if(rebuf[0]!=0x4000)#帧头
i=0;
if((i==2)&&(rebuf[1]!=0x4000))#判断帧头
i=0;
if(i>=7)#代表一帧数据完毕
{
memcpy(OpenMV_Rx_BUF,rebuf,i);
i = 0;
}
USART_ClearFlag(USART2,USART_FLAG_RXNE);
}
上面if(USART_GetITStatus(USART2,USART_IT_RXNE) != RESET)
OpenMV_Rx_BUF是一个外部变量用于保存从openmv接收到的数据,中断子程序中,每当进入中断,会首先判断帧头,如果不是 帧头,会直接丢弃,直到等到帧头的到来。
在openmv 中就可以用以下表示
FH = bytearray([0xb3,0xb3])#帧头
DF = bytearray([0xb4,0xb4])#帧尾
uart3.write(ujson.dumps(FH)+'\r\n')
uart3.write(ujson.dumps(cxy)+'\r\n')
uart3.write(ujson.dumps(DH)+'\r\n')
串口连接
openmv有uart1和uart3两个串口。
问题
1.蓝牙传递的指令对应的帧头帧尾还没有确定,还需更改。这个是需要用蓝牙模块通过USB转接口插在电脑上,用串口助手看,其中用手机上的SPP蓝牙软件传送,不知我这边是什么问题,线是对的,换手机和电脑都没用,蓝牙模块也是好的,已经给战友邮过去了,等待支援。
战友这里已解决,刚开始和我的问题是一样的,但是他那边多尝试了几遍就好了,但是又出现了输出乱码的情况,把波特率重置了一下就好了,感觉很可能是波特率的问题。
至于帧头帧尾,那不就是中括号的左右吗。。。
2.这个多次输入信息,不知道语法怎么表示了。
if b=[9]:#手动,这个多次输入信息,不知道语法怎么表示了
if b =[1]:
ch=[1]
uart3.write(ujson.dumps(FH)+'\r\n')
uart3.write(ujson.dumps(ch)+'\r\n')
uart3.write(ujson.dumps(DH)+'\r\n')
print("前进")
用了懒方法,若b不为a,则是手动,最省事的方法就是开始的时候只能输入自动[a]和前进等指令,如果输入的不是自动[a],则根据指令直接传给单片机。
else# b不为a,则是手动,最省事的方法就是开始的时候只能输入自动[a]和前进等指令,如果输入的不是自动[a],则根据指令直接传给单片机
if b =[1]:
ch=[1]
uart3.write(ujson.dumps(FH)+'\r\n')
uart3.write(ujson.dumps(ch)+'\r\n')
uart3.write(ujson.dumps(DF)+'\r\n')
print("前进")
当然,还可以用松键检测这种更为严谨的方法。
3.串口连接好,连上电脑,不亮灯。
线的接触问题。
4.可打开串口,但是电脑端接收不到数据。
是这个USB-TTL线和openmv的P4,P5接反了,所以,在这个时候不要怀疑世界,要先重新审视一下自己的装备。(蓝牙模块和USB-TTL线反接也很重要)
5.python语法错误
这个错误真的是弱爆了。还是平常自主写的太少了,比如
if:
elif:
else:
if a == [b] :
和c语言不一样,一定要加冒号,赋值的时候要是两个等号,还有缩进问题(还是最好在openmv ide里面编写程序,在记事本写的很悲伤)。
如果有语法错误,不知道在哪里,那就一行一行的看,一行一行注释,排除法找,最本质的方法是最有效的。
6.最花时间的一个问题,openmv只能发送数据,不能接收数据。
要是有示波器看看硬件问题还是程序问题就好了。
最后发现是openmv不能完美的接收数据,因为一接收数据,摄像头就不可以用了,是自身固件的问题,怪不得官网推荐用扩展板。
但是除了扩展板,还可以用单片机当中介,IO高低电平等多种方法,我们这边工具不够,再次邮寄。
最终是先拿openmv运行,只是输出数据,再拿esp32的蓝牙接收,
openmv
# Single Color RGB565 Blob Tracking Example
#
# This example shows off single color RGB565 tracking using the OpenMV Cam.
import sensor, image, time, math,pyb
from pyb import UART
from pyb import Pin
import ujson
threshold_index = 0 # 0 for red, 1 for green, 2 for blue
# Color Tracking Thresholds (L Min, L Max, A Min, A Max, B Min, B Max)
thresholds = [(30, 100, 15, 127, 15, 127)]
K=800#计算距离的辅助值
sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA)
sensor.skip_frames(time = 5000)
sensor.set_auto_gain(False) # must be turned off for color tracking
sensor.set_auto_whitebal(False) # must be turned off for color tracking
clock = time.clock()
uart3 = UART(3, 9600) #p4p5
uart1 = UART(1, 9600) #p2p3
uart1= UART(1, 9600, timeout_char=1000)
#蓝牙接收数据
#UART.init(baudrate=9600, bits=8, parity=None, stop=1)
#IO口通信接收指令
#p_out=Pin('P7',Pin.OUT_PP)#设置p_out为输出引脚
#p_out.high()#设置p_out引脚为高
#p_in=Pin('P7',Pin.IN,Pin.PULL_UP)#设置p_in为输入引脚,并开启上拉电阻
while(True):
p_out1 = Pin('P7', Pin.OUT_PP)#设置p_out为输出引脚
p_out1.high()#设置p_out引脚为高
p_in1 = Pin('P7', Pin.IN, Pin.PULL_UP)#设置p_in为输入引脚,并开启上拉电阻
value1 = p_in1.value()
p_out2 = Pin('P8', Pin.OUT_PP)#设置p_out为输出引脚
p_out2.high()#设置p_out引脚为高
p_in2 = Pin('P8', Pin.IN, Pin.PULL_UP)#设置p_in为输入引脚,并开启上拉电阻
value2 = p_in2.value()
#供单片机判断接收数据
FH = bytearray([0xb3,0xb3])#帧头
AH = bytearray([0x40])
DF = bytearray([0xb4,0xb4])#帧尾
HF = bytearray([0x40])
#手动
if value1==1 and value2==1:
ch=[1]
uart3.write(ujson.dumps(FH)+'\r\n')
uart3.write(ujson.dumps(ch)+'\r\n')
uart3.write(ujson.dumps(DF)+'\r\n')
print("前进")
clock.tick()
elif value1==1 and value2==0:
ch=[2]
uart3.write(ujson.dumps(FH)+'\r\n')
uart3.write(ujson.dumps(ch)+'\r\n')
uart3.write(ujson.dumps(DF)+'\r\n')
print("后退")
elif value1==0 and value2==1:
ch=[4]
uart3.write(ujson.dumps(FH)+'\r\n')
uart3.write(ujson.dumps(ch)+'\r\n')
uart3.write(ujson.dumps(DF)+'\r\n')
print("左转")
elif value1==0 and value2==0:
ch=[3]
uart3.write(ujson.dumps(FH)+'\r\n')
uart3.write(ujson.dumps(ch)+'\r\n')
uart3.write(ujson.dumps(DF)+'\r\n')
print("右转")
else:
img = sensor.snapshot()
for blob in img.find_blobs([thresholds[threshold_index]], pixels_threshold=200, area_threshold=200, merge=True):
# These values depend on the blob not being circular - otherwise they will be shaky.
img.draw_rectangle(blob.rect())
img.draw_cross(blob.cx(), blob.cy())
# Note - the blob rotation is unique to 0-180 only.
#if b == "[a]": #接收蓝牙指令为自动
# print(clock.fps())
# print(blob.cx(),blob.cy())
if ((blob.cx()-160)<(-10)) :
# 串口发送左
cxy=[4]
uart3.write(ujson.dumps(FH)+'\r\n')
uart3.write(ujson.dumps(cxy)+'\r\n')
uart3.write(ujson.dumps(DF)+'\r\n')
print("左转")
if ((blob.cx()-160)>10) :
# 串口发送右
cxy=[3]
uart3.write(ujson.dumps(FH)+'\r\n')
uart3.write(ujson.dumps(cxy)+'\r\n')
uart3.write(ujson.dumps(DF)+'\r\n')
print("右转")
if ((blob.cy()-120)<(-30)) :
# 串口发送前进
cxy=[1]
uart3.write(ujson.dumps(FH)+'\r\n')
uart3.write(ujson.dumps(cxy)+'\r\n')
uart3.write(ujson.dumps(DF)+'\r\n')
print("前进")
if ((blob.cy()-120)>30) :
# 串口发送后退
cxy=[2]
uart3.write(ujson.dumps(FH)+'\r\n')
uart3.write(ujson.dumps(cxy)+'\r\n')
uart3.write(ujson.dumps(DF)+'\r\n')
print("后退")
esp32
#include "BluetoothSerial.h"
#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED)
#error Bluetooth is not enabled! Please run `make menuconfig` to and enable it
#endif
BluetoothSerial SerialBT; //定义蓝牙对象
//esp32有三个串口,分别为Serial、Serial1、Serial2,其中Serial为默认串口,可用来下载程序。
HardwareSerial mySerial1(1); //定义Serial1对象
HardwareSerial mySerial2(2); //定义Serial2对象
unsigned char btrxdata[4]; //蓝牙接收数组
unsigned char btrxcount=0; //蓝牙接收标志位
unsigned char omvrxdata[4]; //openmv接收数组
unsigned char omvrxcount=0; //openmv接收标志位
unsigned char wordmode=0; //工作模式,0为手动模式即仅能通过蓝牙控制,1为自动模式可通过openmv控制 ,二者切换通过蓝牙控制
void setup() {
pinMode(21, INPUT); //初始化io21,输入模式,用于检测hc05是否有连接。本程序中未使用
mySerial1.begin(9600,SERIAL_8N1,32,33); //初始化Serial1,波特率9600 rx为io32 tx为io33
mySerial2.begin(9600,SERIAL_8N1,18,19); //同上
Serial.begin(9600); //初始化Serial,仅填波特率即可,也可映射到任意io,参数格式同上
SerialBT.begin("dog"); //初始化蓝牙,蓝牙名字为dog
}
void loop() {
while(Serial.available()) //如果串口接收缓冲区有数据,就全部读取
{
omvrxdata[omvrxcount++]=Serial.read();
if(wordmode == 1) //如果是自动模式就转发数据,否则丢弃
{
if((omvrxdata[omvrxcount-3]=='[')&&(omvrxdata[omvrxcount-1]==']'))
{
mySerial1.write(omvrxdata[0]);
mySerial1.write(omvrxdata[1]);
mySerial1.write(omvrxdata[2]);
omvrxcount = 0;
memset(omvrxdata,0,sizeof(omvrxdata)); //清空数组
}
}
if(omvrxcount == 3)
{
omvrxcount = 0;
memset(omvrxdata,0,sizeof(omvrxdata));
}
}
while(SerialBT.available()) //如果蓝牙接收缓冲区有数据,就全部读取
{
btrxdata[btrxcount++]=SerialBT.read();
if((btrxdata[btrxcount-2]==0x0a)&&(btrxdata[btrxcount-1]==']'))
{
btrxcount = 0; //检测接收到的数据是否有控制数据 如果有则执行 若无则转发
memset(btrxdata,0,sizeof(btrxdata));
wordmode = 1;
}
if((btrxdata[btrxcount-2]==0x0b)&&(btrxdata[btrxcount-1]==']'))
{
btrxcount = 0;
memset(btrxdata,0,sizeof(btrxdata));
wordmode = 0;
}
if((btrxdata[btrxcount-2]==0x0c)&&(btrxdata[btrxcount-1]==']'))
{
btrxcount = 0;
memset(btrxdata,0,sizeof(btrxdata));
}
if((btrxdata[btrxcount-3]=='[')&&(btrxdata[btrxcount-1]==']'))
{
mySerial1.write(btrxdata[0]);
mySerial1.write(btrxdata[1]);
mySerial1.write(btrxdata[2]);
btrxcount = 0;
memset(btrxdata,0,sizeof(btrxdata));
}
if(btrxcount == 3)
{
btrxcount = 0;
memset(btrxdata,0,sizeof(btrxdata));
}
}
}