撸狗初体验 | 手把手教你上手 HuskyLens 哈士奇人工智能摄像头-程序员宅基地

技术标签: 掌控板  人工智能  摄像头  图像识别  Arduino  

视频封面
直接上视频听我 BB:

https://www.bilibili.com/video/av75675708

下面开始编故事……

某个周末,走在去加班的路上,脚底突然被某个东西咯噔一下,抬脚一看,竟然是……
踩到哈士奇
捡起来一看……
哈士奇
哈士奇!哈士奇!哈士奇!

竟然是 DF 还在预售的 HuskyLens 人工智能摄像头(中文名:哈士奇) !

这个故事告诉我们:喜欢加班的创客,运气不会太差。

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 的特性:ClickLearn & Play

总之:简单、易用、真香!

这么香的工具,到底该怎么玩呢?请继续往下看。

注意:以下章节偏技术性,是对体验视频的文字性详细描述,会略微无聊,请收藏后慢慢阅读。

HuskyLens 数据读取测试

由于 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 个串口,分别是 SerialSerial1Serial2Serial 我们一般用来下载程序, Serial1 默认使用了 GPIO 9GPIO 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 模式原理一样,此处不再赘述。

我们来看一下它的数据格式,可以看到它是以0x550xAA开头的一串数据,紧接着是它的通信地址 Address、数据长度 Data Length、命令代码 Command,以及我们最关心的数据 Data。最后是一个校验位。
哈士奇通信协议
每个数据的含义如下:

Block 模式:
哈士奇通信协议说明Block模式

Arrow 模式:
哈士奇通信协议说明Arrow模式

上面两个表格中红框框出来的是相应的数据 Data 1 ~ Data n,其中:

  • X Center 表示方框 Block 的几何中心的 X 坐标;
  • Y Center 表示方框 Block 的几何中心的 Y 坐标;
  • Width 表示方框 Block 的宽度;
  • Height 表示方框 Block 的高度;
  • LearnedIndex 表示识别目标的编号。

我们根据通信协议,编写程序来读取一下 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
  • 0xA30x00 分别为 X Center 的低 8 位和高 8 位,0x00A3 换算后为 163,代表 X 坐标为 163;
  • 0x7B0x00 为 Y Center 的低 8 位和高 8 位,0x007B 换算后为 123,代表 Y 坐标为 123;
  • 0x460x00 为 Width 的低 8 位和高 8 位,0x0046 换算后为 70,代表方框宽度为 70;
  • 0x460x00 为 Height 的低 8 位和高 8 位,0x0046 换算后为 70,代表方框高度为 70;
  • 0x010x00 为 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 数据的简单读取。

但是每次都要这么去读取数据,然后再进行手工计算么?这还怎么做人工智能项目啊?

当然不是的,我们发现,读取这些数据就是都是一件件重复的事情,而程序最擅长的就是做重复的事情了。

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()

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;
}

getX()

getY()

getWidthOrXTarget()

getHeightOrYTarget()

getLearnedIndex()

这 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

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/ironpandaaa/article/details/103152368

智能推荐

Spring Boot 获取 bean 的 3 种方式!还有谁不会?,Java面试官_springboot2.7获取bean-程序员宅基地

文章浏览阅读1.2k次,点赞35次,收藏18次。AutowiredPostConstruct 注释用于在依赖关系注入完成之后需要执行的方法上,以执行任何初始化。此方法必须在将类放入服务之前调用。支持依赖关系注入的所有类都必须支持此注释。即使类没有请求注入任何资源,用 PostConstruct 注释的方法也必须被调用。只有一个方法可以用此注释进行注释。_springboot2.7获取bean

Logistic Regression Java程序_logisticregression java-程序员宅基地

文章浏览阅读2.1k次。理论介绍 节点定义package logistic;public class Instance { public int label; public double[] x; public Instance(){} public Instance(int label,double[] x){ this.label = label; th_logisticregression java

linux文件误删除该如何恢复?,2024年最新Linux运维开发知识点-程序员宅基地

文章浏览阅读981次,点赞21次,收藏18次。本书是获得了很多读者好评的Linux经典畅销书**《Linux从入门到精通》的第2版**。下面我们来进行文件的恢复,执行下文中的lsof命令,在其返回结果中我们可以看到test-recovery.txt (deleted)被删除了,但是其存在一个进程tail使用它,tail进程的进程编号是1535。我们看到文件名为3的文件,就是我们刚刚“误删除”的文件,所以我们使用下面的cp命令把它恢复回去。命令进入该进程的文件目录下,1535是tail进程的进程id,这个文件目录里包含了若干该进程正在打开使用的文件。

流媒体协议之RTMP详解-程序员宅基地

文章浏览阅读10w+次,点赞12次,收藏72次。RTMP(Real Time Messaging Protocol)实时消息传输协议是Adobe公司提出得一种媒体流传输协议,其提供了一个双向得通道消息服务,意图在通信端之间传递带有时间信息得视频、音频和数据消息流,其通过对不同类型得消息分配不同得优先级,进而在网传能力限制下确定各种消息得传输次序。_rtmp

微型计算机2017年12月下,2017年12月计算机一级MSOffice考试习题(二)-程序员宅基地

文章浏览阅读64次。2017年12月的计算机等级考试将要来临!出国留学网为考生们整理了2017年12月计算机一级MSOffice考试习题,希望能帮到大家,想了解更多计算机等级考试消息,请关注我们,我们会第一时间更新。2017年12月计算机一级MSOffice考试习题(二)一、单选题1). 计算机最主要的工作特点是( )。A.存储程序与自动控制B.高速度与高精度C.可靠性与可用性D.有记忆能力正确答案:A答案解析:计算...

20210415web渗透学习之Mysqludf提权(二)(胃肠炎住院期间转)_the provided input file '/usr/share/metasploit-fra-程序员宅基地

文章浏览阅读356次。在学MYSQL的时候刚刚好看到了这个提权,很久之前用过别人现成的,但是一直时间没去细想, 这次就自己复现学习下。 0x00 UDF 什么是UDF? UDF (user defined function),即用户自定义函数。是通过添加新函数,对MySQL的功能进行扩充,就像使..._the provided input file '/usr/share/metasploit-framework/data/exploits/mysql

随便推点

webService详细-程序员宅基地

文章浏览阅读3.1w次,点赞71次,收藏485次。webService一 WebService概述1.1 WebService是什么WebService是一种跨编程语言和跨操作系统平台的远程调用技术。Web service是一个平台独立的,低耦合的,自包含的、基于可编程的web的应用程序,可使用开放的XML(标准通用标记语言下的一个子集)标准...

Retrofit(2.0)入门小错误 -- Could not locate ResponseBody xxx Tried: * retrofit.BuiltInConverters_已添加addconverterfactory 但是 could not locate respons-程序员宅基地

文章浏览阅读1w次。前言照例给出官网:Retrofit官网其实大家学习的时候,完全可以按照官网Introduction,自己写一个例子来运行。但是百密一疏,官网可能忘记添加了一句非常重要的话,导致你可能出现如下错误:Could not locate ResponseBody converter错误信息:Caused by: java.lang.IllegalArgumentException: Could not l_已添加addconverterfactory 但是 could not locate responsebody converter

一套键鼠控制Windows+Linux——Synergy在Windows10和Ubuntu18.04共控的实践_linux 18.04 synergy-程序员宅基地

文章浏览阅读1k次。一套键鼠控制Windows+Linux——Synergy在Windows10和Ubuntu18.04共控的实践Synergy简介准备工作(重要)Windows服务端配置Ubuntu客户端配置配置开机启动Synergy简介Synergy能够通过IP地址实现一套键鼠对多系统、多终端进行控制,免去了对不同终端操作时频繁切换键鼠的麻烦,可跨平台使用,拥有Linux、MacOS、Windows多个版本。Synergy应用分服务端和客户端,服务端即主控端,Synergy会共享连接服务端的键鼠给客户端终端使用。本文_linux 18.04 synergy

nacos集成seata1.4.0注意事项_seata1.4.0 +nacos 集成-程序员宅基地

文章浏览阅读374次。写demo的时候遇到了很多问题,记录一下。安装nacos1.4.0配置mysql数据库,新建nacos_config数据库,并根据初始化脚本新建表,使配置从数据库读取,可单机模式启动也可以集群模式启动,启动时 ./start.sh -m standaloneapplication.properties 主要是db部分配置## Copyright 1999-2018 Alibaba Group Holding Ltd.## Licensed under the Apache License,_seata1.4.0 +nacos 集成

iperf3常用_iperf客户端指定ip地址-程序员宅基地

文章浏览阅读833次。iperf使用方法详解 iperf3是一款带宽测试工具,它支持调节各种参数,比如通信协议,数据包个数,发送持续时间,测试完会报告网络带宽,丢包率和其他参数。 安装 sudo apt-get install iperf3 iPerf3常用的参数: -c :指定客户端模式。例如:iperf3 -c 192.168.1.100。这将使用客户端模式连接到IP地址为192.16..._iperf客户端指定ip地址

浮点性(float)转化为字符串类型 自定义实现和深入探讨C++内部实现方法_c++浮点数 转 字符串 精度损失最小-程序员宅基地

文章浏览阅读7.4k次。 写这个函数目的不是为了和C/C++库中的函数在性能和安全性上一比高低,只是为了给那些喜欢探讨函数内部实现的网友,提供一种从浮点性到字符串转换的一种途径。 浮点数是有精度限制的,所以即使我们在使用C/C++中的sprintf或者cout 限制,当然这个精度限制是可以修改的。比方在C++中,我们可以cout.precision(10),不过这样设置的整个输出字符长度为10,而不是特定的小数点后1_c++浮点数 转 字符串 精度损失最小

推荐文章

热门文章

相关标签