技术标签: 掌控板 人工智能 摄像头 图像识别 Arduino
直接上视频听我 BB:
https://www.bilibili.com/video/av75675708
下面开始编故事……
某个周末,走在去加班的路上,脚底突然被某个东西咯噔一下,抬脚一看,竟然是……
捡起来一看……
哈士奇!哈士奇!哈士奇!
竟然是 DF 还在预售的 HuskyLens 人工智能摄像头(中文名:哈士奇) !
这个故事告诉我们:喜欢加班的创客,运气不会太差。
HuskyLens 是什么?
这里简单截取官网介绍的一部分:
HuskyLens 是一款简单易用的人工智能摄像头(视觉传感器),内置 6 种功能:人脸识别、物体追踪、物体识别、巡线追踪、颜色识别、标签(二维码)识别。仅需一个按键即可完成 AI 训练,摆脱繁琐的训练和复杂的视觉算法,让你更加专注于项目的构思和实现。
详细介绍,可以查看官网说明: https://www.dfrobot.com.cn/goods-2050.html
哈士奇官方介绍视频,请直接跳转 B 站:
http://player.bilibili.com/player.html?aid=66695069&cid=115655109
用 3 个单词就可以概括 HuskyLens 的特性:Click、Learn & Play。
总之:简单、易用、真香!
这么香的工具,到底该怎么玩呢?请继续往下看。
注意:以下章节偏技术性,是对体验视频的文字性详细描述,会略微无聊,请收藏后慢慢阅读。
由于 HuskyLens 目前还没有正式上市,所以关于它的资料非常少,DF 暂时也没有放出 HuskyLens 对应的函数库,更不用说在 Mind+ 等图形化编程工具中调用了。不过相信不久,我们就可以在 Mind+ 中看到它了,到那时,它的使用就会更加简单、更加小白了!
暂时我们只能根据它的通信协议,徒手来撸代码了。
HuskyLens 默认采用串口通信,当然可以在它的设置中改成 I2C 通信。默认的串口波特率为 57600 bps,格式为 8N1( 8 位数据位、无校验、1位停止位 ),默认通信地址为 0x11
。本文中,我带领大家使用掌控板来读取 HuskyLens 的数据。
当然你也可以选择使用 Arduino、Raspberry Pi、LattePanda、micro:bit 等控制器来读取 HuskyLens 的数据,原理都是一样的,就留作课后作业吧,看文本文后,你能不能用其他主控板来读取 HuskyLens 的数据呢?
电路连接图如下:
关于掌控板串口的补充说明:
掌控板的主控芯片是 ESP32,ESP32 有 3 个串口,分别是
Serial
、Serial1
、Serial2
。Serial
我们一般用来下载程序,Serial1
默认使用了GPIO 9
和GPIO 10
,但是 ESP32 的GPIO 6~11
一般用于连接外部 Flash 芯片,所以我们这里使用Serial2
与 HuskyLens 连接通信。另外,ESP32 可以将串口 RX 映射到几乎所有 IO 口上,TX 映射到GPIO 0~31
上(此处没有进行验证)。所以,这里我们将掌控板
Serial2
的 RX 映射到 P14 引脚,将 TX 映射到 P13 引脚。参考资料: https://blog.csdn.net/Naisu_kun/article/details/86004049
我们来看一下 HuskyLens 的通信协议。它主要有两种模式,正如视频中看到的那样,大部分情况下, HuskyLens 屏幕上会显示一个方框(Block 模式),在巡线模式下,它会显示一个箭头(Arrow 模式)。这两种模式下,数据的长度和格式基本是一致的,这里我们以 Block 模式为例进行讲解,Arrow 模式原理一样,此处不再赘述。
我们来看一下它的数据格式,可以看到它是以0x55
和0xAA
开头的一串数据,紧接着是它的通信地址 Address、数据长度 Data Length、命令代码 Command,以及我们最关心的数据 Data。最后是一个校验位。
每个数据的含义如下:
Block 模式:
Arrow 模式:
上面两个表格中红框框出来的是相应的数据 Data 1 ~ Data n,其中:
我们根据通信协议,编写程序来读取一下 HuskyLens 返回的数据。
首先打开 Mixly 自带的 Arduino IDE,选择 Arduino HandBit (掌控板)进行编程。
最新版 Mixly 1.0 下载地址: https://mixly.readthedocs.io/zh_CN/latest/basic/02Installation-update.html
程序如下:
void setup()
{
Serial.begin(57600);
Serial2.begin(57600, SERIAL_8N1, P14, P13);
}
void loop()
{
if (Serial2.available() > 0) {
Serial.println(Serial2.read(), HEX);
}
}
将程序上传到掌控板,打开串口监视器,可以看到会返回类似下图中的数据:
但是这些数据代表着什么意思呢?我们将关键数据圈出来:0x55、0xAA、0x11、0x0A、0x10、0xA3、0x00、0x7B、0x00、0x46、0x00、0x46、0x00、0x01、0x00、0xD5。其中:
0x55
为 Header;0xAA
为 Header 2;0x11
为 Address;0x0A
为 Data Length;0x10
为 Command,Block 模式下为 0x10
,Arrow 模式下为 0x11
;0xA3
、0x00
分别为 X Center 的低 8 位和高 8 位,0x00A3
换算后为 163,代表 X 坐标为 163;0x7B
、0x00
为 Y Center 的低 8 位和高 8 位,0x007B
换算后为 123,代表 Y 坐标为 123;0x46
、0x00
为 Width 的低 8 位和高 8 位,0x0046
换算后为 70,代表方框宽度为 70;0x46
、0x00
为 Height 的低 8 位和高 8 位,0x0046
换算后为 70,代表方框高度为 70;0x01
、0x00
为 LearnedIndex 的低 8 位和高 8 位,0x0001
换算后为 1,代表识别物体的编号为 1;0xD5
为 Checksum 的低 8 位,我们将上面所有数据相加求和:0x55 + 0xAA + 0x11 + 0x0A + 0x10 + 0xA3 + 0x00 + 0x7B + 0x00 + 0x46 + 0x00 + 0x46 + 0x00 + 0x01 + 0x00 =0x02D5
,低 8 位是 0xD5
说明校验通过。至此,我们就完成了 HuskyLens 数据的简单读取。
但是每次都要这么去读取数据,然后再进行手工计算么?这还怎么做人工智能项目啊?
当然不是的,我们发现,读取这些数据就是都是一件件重复的事情,而程序最擅长的就是做重复的事情了。
我们将上面的程序简单调整一下,duang~ 就完成了!(程序源代码详见文末下载链接,建议配套代码一起阅读下文)
我们先定义了一些变量,用来存放数据。这些变量的名字,基本可以自解释其含义,此处不再赘述说明。
#define LENG 15 // 0x55 + 15 bytes equal to 16 bytes
unsigned char buf[LENG];
int xCenterOrXOrigin = 0;
int yCenterOrYOrigin = 0;
int widthOrXTarget = 0;
int heightOrYTarget = 0;
int learnedIndex = 0;
在 setup()
中,主要是对两个串口进行初始化:
void setup()
{
Serial.begin(57600);
Serial2.begin(57600, SERIAL_8N1, P14, P13);
}
然后在 loop()
中,不断去读取掌控板串口 2(Serial2)中返回的数据。首先要判断第 1 个读到的数据是否是默认的 Header 0x55
,我们用了find()
函数:
// Header
// Read data until get the first header of data packet 0x55
if (Serial2.find(0x55))
{
// ......
}
如果读取到0x55
,那么就把剩下的 15 个数据都读取进来,并存储到 buf
变量中。因为一个有效的通信命令共16个数据,大家可以在通信协议中数一下。
// Read the next 15 data
Serial2.readBytes(buf, LENG);
接着去检查第 2 个数据是否是默认的 Header 2 0xAA
。这里需要注意的是,我们并没有把第 1 个 Header 数据 0x55
存储到 buf
变量中,所以 buf[0]
不是 0x55
,而是 0xAA
。
// Header 2
// Check the second header of data packet 0xAA
if (buf[0] == 0xAA)
{
// ......
}
如果第 2 个数据也是默认的包头的话,再去对剩下的数据进行校验,这里调用校验和函数 checkSum()
,具体这个函数怎么实现的,下面再讲。
// Checksum
if (checkSum(buf, LENG))
{
// ......
} else {
Serial.println("Checksum Errorrrrr!");
}
校验和通过后,就可以对数据进行处理和计算了。在下面的程序中,我们先把原始数据打印出来:
// print the command list
Serial.print(0x55, HEX);
Serial.print(" ");
for (int i = 0; i < LENG; i++)
{
Serial.print(buf[i], HEX);
Serial.print(" ");
}
Serial.println();
然后通过 5 个函数分别去计算 Data 中的几个值。最后再将这些数据在串口监视器中打印出来。
// get the values
xCenterOrXOrigin = getX(buf);
yCenterOrYOrigin = getY(buf);
widthOrXTarget = getWidthOrXTarget(buf);
heightOrYTarget = getHeightOrYTarget(buf);
learnedIndex = getLearnedIndex(buf);
// print the values
Serial.print("x: ");
Serial.print(xCenterOrXOrigin);
Serial.print(" ");
Serial.print("y: ");
Serial.print(yCenterOrYOrigin);
Serial.print(" ");
Serial.print("width: ");
Serial.print(widthOrXTarget);
Serial.print(" ");
Serial.print("height: ");
Serial.print(heightOrYTarget);
Serial.print(" ");
Serial.print("learnedIndex: ");
Serial.print(learnedIndex);
Serial.print(" ");
Serial.println();
Serial.println("-----------------------------");
Serial.println();
这样我们就把数据读取出来啦。
checkSum()
函数的功能就是校验读取到的数据是否正确。只要简单讲读到的数据相加,并最终取和的低 8 位,检查是否和读到的最后一个数据相等即可。相等的话,将标记变量 receiveflag
赋值为 1 即可,否则赋值为 0,并返回 receiveflag
的结果。
// check sum
char checkSum(unsigned char *buf, char leng)
{
char receiveflag = 0;
int sum = 0;
int sumLow = 0;
for (int i = 0; i < (leng - 1); i++)
{
sum = sum + buf[i];
}
sum = sum + 0x55;
sumLow = sum & 0x00FF;
if (sumLow == buf[leng - 1])
{
sum = 0;
receiveflag = 1;
}
return receiveflag;
}
这 5 个函数的原理基本一致,其函数名基本可以自解释含义,此处也不再赘述解释每个函数的功能。
这里以第 1 个函数 getX()
为例,介绍这几个函数内部的原理。
通过查看通信协议,我们可以知道,X 坐标的数值,分别存储在 buf
变量中的第 5 个和第 6 个(实际是完整数据的 6 个和第 7 个数据,但是 buf
变量中没有存储第 1 个数据 0x55
),所以这里取 buf[4]
和 buf[5]
来进行计算即可。 由于是 16 进制的数据,所以可以通过移位进行计算,当然这里的 << 8
等价为 * 256
。最后将计算出来的值返回即可。
// X Center of Block [Block mode]
// or X Origin of Arrow [Arrow mode: Line tracking mode]
int getX(unsigned char *thebuf)
{
int xCenterValue;
// calculate X Center of Block value
xCenterValue = ((thebuf[5] << 8) + thebuf[4]);
return xCenterValue;
}
其他几个数据,也是同样道理,只要取对应的数据位进行计算即可。
通过这一章节,我们根据 HuskyLens 的通信协议,把 HuskyLens 返回的数据都读取出来了。那么我们可以利用这些数据做一些什么有趣好玩的事情呢?
物体追踪,人脸识别,物体识别,巡线追踪,颜色识别,标签识别等功能,要怎么用呢?
交互手势控制、自主机器人、智能门禁、交互式玩具等又要怎么实现呢?
我们下期见!
请到知识星球下载本教程对应的源代码:https://t.zsxq.com/RB6EaYf
文章浏览阅读1.6k次,点赞5次,收藏20次。【有害垃圾】:电池(1 号、2 号、5 号)、过期药品或内包装等;【可回收垃圾】:易拉罐、小号矿泉水瓶;【厨余垃圾】:小土豆、切过的白萝卜、胡萝卜,尺寸为电池大小;【其他垃圾】:瓷片、鹅卵石(小土豆大小)、砖块等。文件结构|----classes.txt # 标签种类|----data-txt\ # 数据集文件集合|----images\ # 数据集图片|----labels\ # yolo标签。_垃圾回收数据集
文章浏览阅读272次。之前写到 通过封装的API 已经可以做到使用redis进行缓存天气信息但是这一操作每次都由客户使用时才进行更新 不友好 所以应该自己实现半小时的定时存入redis 使用quartz框架 首先添加依赖build.gradle中// Quartz compile('org.springframework.boot:spring-boot-starter-quartz'..._cityid=101280803
文章浏览阅读1.8k次,点赞2次,收藏8次。对于使用触发事件来反应的按钮传递参数如下:可以通过lambda对function的参数传递:t.Bind(wx.EVT_BUTTON, lambda x, textctrl=t: self.input_fun(event=x, textctrl=textctrl))前提需要self.input_fun(self,event,t):传入参数而同时两个Frame之间的参数传..._wxpython frame.bind
文章浏览阅读1.9k次。最近接到一个任务要开发消消乐小游戏,当然首先就想到乐cocosCreator来作为开发工具。开发本身倒没有多少难点。消消乐的开发官网发行的书上有专门讲到。下面主要总结一下开发中遇到的问题以及解决方法屏幕适配由于设计尺寸是750*1336,如果适应高度,则在iphonX下,内容会超出屏幕宽度。按宽适应,iphon4下内容会超出屏幕高度。所以就需要根据屏幕比例来动态设置适配策略。 onLoad..._750*1336
文章浏览阅读745次,点赞21次,收藏21次。web项目的框架,通常更简单的数据源。21世纪的今天,随着社会的不断发展与进步,人们对于信息科学化的认识,已由低层次向高层次发展,由原来的感性认识向理性认识提高,管理工作的重要性已逐渐被人们所认识,科学化的管理,使信息存储达到准确、快速、完善,并能提高工作管理效率,促进其发展。论文主要是对银行贷款管理系统进行了介绍,包括研究的现状,还有涉及的开发背景,然后还对系统的设计目标进行了论述,还有系统的需求,以及整个的设计方案,对系统的设计以及实现,也都论述的比较细致,最后对银行贷款管理系统进行了一些具体测试。_vue3重构信贷管理系统
文章浏览阅读774次。题目描述原题目戳这里小明过生日的时候,爸爸送给他一副乌龟棋当作礼物。乌龟棋的棋盘是一行 NNN 个格子,每个格子上一个分数(非负整数)。棋盘第 111 格是唯一的起点,第 NNN 格是终点,游戏要求玩家控制一个乌龟棋子从起点出发走到终点。乌龟棋中 MMM 张爬行卡片,分成 444 种不同的类型( MMM 张卡片中不一定包含所有 444 种类型的卡片,见样例),每种类型的卡片上分别标有 1,2,3,41, 2, 3, 41,2,3,4 四个数字之一,表示使用这种卡片后,乌龟棋子将向前爬行相应的格子数
文章浏览阅读1.5k次。吐槽内存泄露 ? 内存暴涨 ? OOM ?首先提一下我自己曾经历过多次内存泄露,到底有几次? 我自己心里悲伤的回想了下,造成线上影响的内存泄露事件有将近5次了,没上线就查出内存暴涨次数可能更多。这次不是最惨,相信也不会是最后的内存的泄露。有人说,内存泄露对于程序员来说,是个好事,也是个坏事。 怎么说? 好事在于,技术又有所长进,经验有所心得…. 毕竟不是所有程序员都写过OOM的服务…. 坏事..._python内存泄露
文章浏览阅读747次。1.sensor typeTYPE_ACCELEROMETER=1 TYPE_MAGNETIC_FIELD=2 (what's value mean at x and z axis)TYPE_ORIENTATION=3TYPE_GYROSCOPE=4 TYPE_LIGHT=5(in )TYPE_PRESSURE=6TYPE_TEMPERATURE=7TYPE_PRO_draft sensor
文章浏览阅读581次。/* * Copyright (c) 2009 湖南师范大学数计院 一心飞翔项目组 * All Right Reserved * * 文件名:matrix.cpp 定义Point、Node、Matrix类的各个方法 * 摘 要:定义矩阵类,包括矩阵的相关信息和方法 * * 作 者:刘 庆 * 修改日期:2009年7月19日21:15:12 **/
文章浏览阅读1.7w次,点赞6次,收藏20次。HTML不再推荐页面中使用框架集,因此HTML5删除了<frameset>、<frame>和<noframes>这三个元素。不过HTML5还保留了<iframe>元素,该元素可以在普通的HTML页面中使用,生成一个行内框架,可以直接放在HTML页面的任意位置。除了指定id、class和style之外,还可以指定如下属性:src 指定一个UR..._iframe allow-top-navigation
文章浏览阅读785次,点赞29次,收藏12次。Zipkin 是 Twitter 的一个开源项目,它基于 Google Dapper 实现,它致力于收集服务的定时数据,以解决微服务架构中的延迟问题,包括数据的收集、存储、查找和展现。我们可以使用它来收集各个服务器上请求链路的跟踪数据,并通过它提供的 REST API 接口来辅助我们查询跟踪数据以实现对分布式系统的监控程序,从而及时地发现系统中出现的延迟升高问题并找出系统性能瓶颈的根源。除了面向开发的 API 接口之外,它也提供了方便的 UI 组件来帮助我们直观的搜索跟踪信息和分析请求链路明细,
文章浏览阅读358次。“随着天网工程的建设,中国已经建成世界上规模最大的视频监控网,摄像头总 数超过2000万个,成为世界上最安全的国家。视频图像及配套数据已经应用在反恐维稳、治安防控、侦查破案、交通行政管理、服务民生等各行业各领域。烁博科技视频安全核心能力:精准智能数据采集能力:在建设之初即以应用需求为导向,开展点位选择、设备选型等布建工作,实现前端采集设备的精细化部署。随需而动的AI数据挖掘能力:让AI所需要的算力、算法、数据、服务都在应用需求的牵引下实现合理的调度,实现解析能力的最大化。完善的数据治理能力:面_2018年8月由于某知名视频监控厂商多款摄像机存在安全漏洞