虽然铁人赛已暂告一个段落,但在[Day 27] Edge Impulse + BLE Sense实现影像分类(上)有提到采购的OV760(无FIFO)摄影机模组尚未到手,所以只能暂以预先准备好的影像集上传来做实验。上周拿到後就急忙进行实验,结果一波N折,处处碰壁,直到昨晚(2021/10/20)才算初步搞定,所以今天补上这篇方便大家可以测试一下。
原先Edge Impulse官网推荐Arduino Nano 33 BLE Sense(以下简称BLE Sense)搭配OV7675来做视觉相关应用。而OV7670(无FIFO)摄影机模组取像规格相近,也满常用於Arduino其它产品上,价格相当便宜,且使用M12镜头可手动调整焦距,更方便应用於各种视觉应用,所以决定改用OV7670来连接BLE Sense再上传到Edge Impulse。
如果大家用Google搜寻BLE Sense如何连接到OV7670,大概通常都会找到这篇Machine vision with low-cost camera modules,本来想跟着做一遍就收工,无奈老天给了我更多的考验,以下就让我缓缓道来到底遇到什麽问题吧。
首先当然要把OV7670和BLE Sense连接起来,通常网路上的范例都是用面包板和杜邦线连结,为了後续实验更方便,这里采用直接焊洞洞板的方式完成,并令摄影机模组板和BLE Sense板呈90度连接,方便更替,大家可自行决定用那种方式连接。完整接线图如图31-1所示,或参考Table 33-1。在[Day 27]有提及OV7675的PEN/RST(Pin 19), PWDN/PDN(Pin20)是对应到OV7670的Pin 17, 18,但经查阅相关资料後得知,不接亦可。
Tabel 33-1 OV7670和Arduino Nano 33 BLE Sense接线对照表
OV7670 Pin Name | OV7670 Pin Number | BLE Sense Pin Name | 备注 |
---|---|---|---|
3.3V | 01 | 3.3V | |
GND | 02 | GND | 任一个GND皆可 |
SCL | 03 | SCL/A5 (P0.02) | |
SDA | 04 | SDA/A4 (P0.31) | |
VS | 05 | D8 (P0.21) | |
HS | 06 | A1 (P0.05) | |
PCLK | 07 | A0 (P0.04) | |
XCLK | 08 | D9 (P0.27) | |
D7 | 09 | D4 (P1.15) | |
D6 | 10 | D8 (P1.14) | |
D5 | 11 | D5 (P1.13) | |
D4 | 12 | D3 (P1.12) | |
D3 | 13 | D2 (P1.11) | |
D2 | 14 | D0/RX (P1.10) | |
D1 | 15 | D1/TX (P1.03) | |
D0 | 16 | D10 (P1.02) | |
RESET | 17 | A2 (P0.30) | 可不接 |
PWDN | 18 | A3 (P0.29) | 可不接 |
Fig. 31-1 Arduino Nano 33 BLE Sense连接OV7670摄影机模组(无FIFO)之参考线路图。(OmniXRI整理绘制, 2021/10/21)
由於BLE Sense上并没有显示元件(如LCD),所以由OV7670取得的影像必须以二进制(16bit, RGB565)格式数值,经由虚拟串列埠(Virtual COM)传送到电脑上显示。为了测试OV7670是否能正确取像,首先要在Arduino IDE安装必要程序库。点击主选单[草稿码]-[汇入程序库]-[管理程序库...],再输入「OV7670」,选择「Arduino_OV767x」,按下安装即可。
接着点击主选单[档案]-[范例],结果发现「Arduino_OV767x」竟然被归类在不相容的函式库中,正在一头雾水时,回头检查「开发板」设定时,发现原先选用的是「Arduino Mbed OS Nano Boards」下的「Arduino Nano 33 BLE」,而另一个「Arduino Mbed OS Boards」下也有一个同名的「Arduino Nano 33 BLE」,经更换成後者後,「Arduino_OV767x」就正确回到「第三方程序库的范例」中了。点击「CameraCaptureRawBytes」就可开启测试OV7670的范例了。完整程序如图Fig. 31-2所示。
Fig. 31-2 Arduino IDE OV7670程序库安装及开启范例。(OmniXRI整理绘制, 2021/10/21)
/*
OV767X - Camera Capture Raw Bytes
点击Arduino IDE主选单[范例]-[Arduino_OV767x]-[CameraCaptureRawBytes]得到此范例
电路连接:
- Arduino Nano 33 BLE board
- OV7670 camera module:
- 3.3 connected to 3.3
- GND connected GND
- SIOC connected to A5
- SIOD connected to A4
- VSYNC connected to 8
- HREF connected to A1
- PCLK connected to A0
- XCLK connected to 9
- D7 connected to 4
- D6 connected to 6
- D5 connected to 5
- D4 connected to 3
- D3 connected to 2
- D2 connected to 0 / RX
- D1 connected to 1 / TX
- D0 connected to 10
*/
#include <Arduino_OV767X.h> // 导入OV767x程序库头文件
int bytesPerFrame; // 宣告一张影像所需Byte数量
byte data[320 * 240 * 2]; // 宣告存放QVGA解析度RGB565格式(16bit)之彩色影像之缓冲区
// 设定脚位用途及模组初始化(只在电源启动或重置时执行一次)
void setup() {
Serial.begin(9600); // 宣告虚拟串列埠传输速度为9600bps,可自行调整。
while (!Serial); // 若开启不成功就一直等待。
// 初始化摄影机模组为QVGA解析度(320x240),RGB565彩色格式,取像速度为1秒1张。
// 解析度可自行调整为VGA(640x480), QVGA(320x240), QQVGA(160x120), CIF(352x240), QCIF(176x144)。
// 彩色影像格式可自行调整为YUV422, RGB444, RGB565, GRAYSCALE(8bit灰阶)。
// 取像速度可设定为 1, 5, 10, 20FPS, 但由於BLE Sense CPU速度仅有64MHz,所以建议设定为1FPS为佳,以免来不及处理。
if (!Camera.begin(QVGA, RGB565, 1)) {
Serial.println("Failed to initialize camera!"); // 若初始化失败则回传错误讯息
while (1); // 令程序卡在这一行,表示程序结束。
}
bytesPerFrame = Camera.width() * Camera.height() * Camera.bytesPerPixel(); // 依实际初始化结果计算出所需回传的Byte数量。
// Optionally, enable the test pattern for testing
// Camera.testPattern(); // 选择性输出,若删除注解符号,则会一直输出八色彩条图,不理会实际摄影机模组拍摄到的内容。可作为测试传输用。
}
// 设定无穷循环程序 (会一直依序重覆执行)
void loop() {
Camera.readFrame(data); // 从摄影机读取一个影格资料
Serial.write(data, bytesPerFrame); // 从虚拟串列埠回传读到的影像二进制资料
}
原则上,以上程序可直接烧录到BLE Sense中,不用修改。这只是为了测试硬体线路用,不用太在意取像速度只有1 FPS。
刚才有提到,BLE Sense并没有显示功能,而透过虚拟串列埠传送出来的值,也不是电脑显示用的格式(如BMP),所以需要有另一个程序来解读,这里推荐使用Processing来接收并显示。Processing是一种开源的程序语言,专门用来创作电子艺术和视觉互动设计。其架构是建立在Java语言之上,其整合开发环境(IDE)操作上很像Arduino IDE。
Processing不需要安装,只需到下载页面下载适合的作业系统的版本即可,最新的版本为4.0 beta2,亦可选用3.x版稳定版本。下载完成後只需解压缩,不必安装,直接执行Processing.exe(Windows版)即可。这里并没有要教大家如何写程序,只需把下列范例程序复制贴上即可。其主要操作介面如图Fig. 31-3所示。
其中有几个小地方要手动修改一下。
/*
This sketch reads a raw Stream of RGB565 pixels
from the Serial port and displays the frame on
the window.
Use with the Examples -> CameraCaptureRawBytes Arduino sketch.
This example code is in the public domain.
范例程序来源:https://raw.githubusercontent.com/arduino-libraries/Arduino_OV767X/master/extras/CameraVisualizerRawBytes/CameraVisualizerRawBytes.pde
*/
import processing.serial.*;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
Serial myPort; // 宣告一串列埠
// 以下宣告值必须符合BLE Sense上传的影像大小
final int cameraWidth = 320; // 摄影机取得影像宽度
final int cameraHeight = 240; // 摄影机取得影像高度
final int cameraBytesPerPixel = 2; // 影像像素占用Byte数
final int bytesPerFrame = cameraWidth * cameraHeight * cameraBytesPerPixel; // 影格影像所需Byte数量
PImage myImage; // 宣告一个显示用影像
byte[] frameBuffer = new byte[bytesPerFrame]; // 宣告影像资料缓冲区
// 设定系统相关参数,只执行一次
void setup()
{
size(320, 240); // 指定显示视窗尺寸,需搭配取像尺寸修改
// if you have only ONE serial port active
//myPort = new Serial(this, Serial.list()[0], 9600); // if you have only ONE serial port active
// 请依不同作业系统、埠号及传输速度自行修改,这里以Windows, COM3, 9600bps为例
myPort = new Serial(this, "COM3", 9600); // Windows
//myPort = new Serial(this, "/dev/ttyACM0", 9600); // Linux
//myPort = new Serial(this, "/dev/cu.usbmodem14401", 9600); // Mac
// 等待接收到足够的Byte数量
myPort.buffer(bytesPerFrame);
myImage = createImage(cameraWidth, cameraHeight, RGB); // 创建一张RGB格式影像
}
// 绘图函式,更新接收到的资料到视窗上
void draw()
{
image(myImage, 0, 0); // 绘制影像到视窗上
}
// 处理串列埠事件
void serialEvent(Serial myPort) {
// 从串列埠读取原始资料到缓冲区
myPort.readBytes(frameBuffer);
// 处理原始资料透过缓冲区
ByteBuffer bb = ByteBuffer.wrap(frameBuffer);
bb.order(ByteOrder.BIG_ENDIAN);
int i = 0;
// 当资料还没读完
while (bb.hasRemaining()) {
// 读取一个像素资料(16bit, RBG565)
short p = bb.getShort();
// 将RGB565格式转换成RGB888(24bit)格式
int r = ((p >> 11) & 0x1f) << 3;
int g = ((p >> 5) & 0x3f) << 2;
int b = ((p >> 0) & 0x1f) << 3;
// 将转换好的像素颜色绘到影像指定位置
myImage .pixels[i++] = color(r, g, b);
}
myImage .updatePixels(); // 更新影像中像素内容
}
原本以为贴上程序,按下左上角【Play】键就能看到完美影像,没想到只得到一片黑呼呼的视窗,检查了老半天,还是找不出问题,最後不得已只好换上另一个OV7670,结果就有一堆奇怪的方块产生,感觉好像有拍到影像,但却很破碎。於是把BLE Sense的「Camera.testPattern();」那行注解取消掉来检查,照道理应该会得到如图Fig. 31-3右上的彩条图,但却得到右下角那个歪斜的影像,感觉上好像是资料每隔一段时间就落後一些时间造成。经上网努力查找,最後得到一个解决方式,就是移到Ubuntu(Linux)下测试就不会有这个问题产生了。果然,在Ubuntu上安装完Processing并执行同一段程序就OK了。不过第一颗OV7670还是黑画面,猜想可能已经报销了。於是把BLE Sense的程序改回,重新把「Camera.testPattern();」加上注解。终於可以在Processing上看到OV7670取到的影像了。但不知为何取得的影像转了90度,只好先将就点用。
Fig. 31-3 Processing显示BLE Sense上传之资料。(OmniXRI整理绘制, 2021/10/21)
完成上面测试後,依Edge Impulse官网「Adding sight to your sensors」说明,应该把Edge Impulse提供的标准韧体(arduino-nano-33-ble-sense.ino.bin)使用「flash_windows.bat」(Windows版本)重新烧回BLE Sense开发板就可以了。但执行「edge-impulse-daemon --clean」将开发板连线後,但进到「资料撷取(Data Acquisition)」页面後,在「感测器(Sensor)」栏位,却只能看到「Build-in Accelerometer」和「Build-in Micphone」,没看到摄影机相关选项。
在网路上查找了许久一直没有答案,结果不小心在某个教学影片中发现,「arduino-nano-33-ble-sense.ino.bin」的日期是2021/9,而我的却是2021/5的版本。於是死马当活马医,重新下载官网提供的韧体,再次烧录并启动,果然,「感测器(Sensor)」栏位多了两个选项「Camera (160x120)」、「Camera (128x96)」,且萤幕上也能呈现摄影机即时拍到的内容,虽然Processing在Windows上依旧不正常,但不影响取像结果。当按下【Start Sampling】钮,果然可以拍下影像,并上传到系统,如此就能建立实拍的资料集了。
Fig. 31-4 Edge Impulse连接OV7670取像结果。(OmniXRI整理绘制, 2021/10/21)
虽然经历OV7670损坏一组、Processing在Windows上无法正常显示BLE Sense上传影像及Edge Impulse Firmware版本不对等问题,花了一个多星期终於搞定,还好不是在比赛期间,不然为了这个问题无法完赛,就有点可惜了。希望藉由这篇文章可以补齐原来[Day 27]、[Day 28]还没说完的故事。
参考连结
[Day 27] Edge Impulse + BLE Sense实现影像分类(上)
[Day 28] Edge Impulse + BLE Sense实现影像分类(下)
Edge Impulse Document - Tutorials - Adding sight to your sensors
Edge Impulse Document - Development Boards - Arduino Nano 33 BLE Sense
Machine vision with low-cost camera modules
<<: “Work Smart” vs “Work Hard”? (单选题)
>>: 操作授权 (Authorization to Operate:ATO)
“He is terribly afraid of dying because he hasn’t...
学习进度 Android Studio (以下功能皆为自学) RelativeLayout Date...
ERP是「 企业资源计划 」的缩写 (Enterprise resource planning ER...
APP 开发 组别 https://wolkesau.medium.com/app-开发-组别-49...
本篇内容要介绍Button元件, 除了认识Button的语法、属性外, 同时也要为按钮设置监听及触发...