本文来自极术社区聆思CSK6视觉AI开发套件试用活动文章。作者用聆思CSK6芯片支持的手势识别能力结合8X8点阵实现一款剪子包袱锤的游戏。
一 开发环境搭建
1.1 硬件环境
如下图所示,本次产品有聆思的CSK6011-NanoKit视觉开发套件和8*8点阵组成,CSK6011-NanoKit负责手势的识别,点阵负责图形的显示,两者通过SPI总线连接在一起。
1.2 软件环境
软件开发环境搭建可以参考CSK6环境搭建,聆思很贴心的提供了完整的打包开发环境,利用lisa工具可以完成项目的创建、编译和下载,此外厂商还基于VSCODE插件的方式提供了完整的IDE开发环境。
二 点阵的使用
2.1 硬件连接
8x8点阵的主控是GC7219(完全兼容MAX7219),其典型的应用图如下所示:
芯片可以通过GPIO或者SPI来驱动,官方提供了SPI的参考demo,本次将基于其实现对点阵的控制。将GC7219(点阵)与CSK6011的SPI0连接,利用板载的3.3V管脚供电,相关管脚的连接示意图如下:
2.2 图标建模
由于CSK6011目前支持5种手势,分别为LIKE()、OK()、STOP()、YES()、SIX(),采用相似原则,取LIKE=锤,STOP=包袱,YES=剪刀。相关示图标建模(共阴)如下:
2.3 驱动开发
2.3.1 建立SPI开发工程
参见SPI参考工程的实现,搭建SPI驱动开发工程。
2.3.2 GC7219的适配
由GC7219的手册可知,其支持MSB模式,且最高频率只有10M,因此spi的Config需要做如下修改。
/* spi master 8bit, LSB first*/ spi_cfg.operation = SPI_WORD_SET(8) | SPI_OP_MODE_MASTER | SPI_TRANSFER_LSB; spi_cfg.frequency = 10 * 1000000UL;
改为:
/* spi master 8bit, MSB first*/ spi_cfg.operation = SPI_WORD_SET(8) | SPI_OP_MODE_MASTER | SPI_TRANSFER_MSB; spi_cfg.frequency = 5 * 1000000UL;
2.3.3 添加点阵驱动
如图2.2所示,GC7219支持共阴点阵,各图像的数组定义如下代码片段。
unsigned char jiandao_table[8][2] = { {0x01,0x24},{0x02,0x24},{0x03,0x24},{0x04,0x7E}, {0x05,0x7E},{0x06,0x7E},{0x07,0x7E},{0x08,0x00} }; unsigned char shitou_table[8][2] = { {0x01,0x00},{0x02,0x40},{0x03,0x40},{0x04,0x7C}, {0x05,0x7C},{0x06,0x7C},{0x07,0x7C},{0x08,0x00} }; unsigned char bu_table[8][2] = { {0x01,0x08},{0x02,0x1C},{0x03,0x1E},{0x04,0x1E}, {0x05,0x5E},{0x06,0x7E},{0x07,0x7E},{0x08,0x00} };
由zephr的API调用可知,其发送函数spi_write需要传入一个数据链表,然后会按照列表逐一发送相关数据,完整的代码如下:
/* * SPDX-License-Identifier: Apache-2.0 */ #include#include #include #include #include #include #include unsigned char work_state[2]={0x0C, 0x1}; // normal work mode unsigned char test_state[2]={0x0F, 0x0}; // no test mode unsigned char decode_cfg[2]={0x09, 0x0}; // no decode unsigned char scan_range[2]={0x0B, 0x7}; // scan 0-7 unsigned char jiandao_table[8][2] = { {0x01,0x24},{0x02,0x24},{0x03,0x24},{0x04,0x7E}, {0x05,0x7E},{0x06,0x7E},{0x07,0x7E},{0x08,0x00} }; unsigned char shitou_table[8][2] = { {0x01,0x00},{0x02,0x40},{0x03,0x40},{0x04,0x7C}, {0x05,0x7C},{0x06,0x7C},{0x07,0x7C},{0x08,0x00} }; unsigned char bu_table[8][2] = { {0x01,0x08},{0x02,0x1C},{0x03,0x1E},{0x04,0x1E}, {0x05,0x5E},{0x06,0x7E},{0x07,0x7E},{0x08,0x00} }; #define TX_PACKAGE_MAX_CNT 8 void main(void) { int idx=0; const struct device *spi; struct spi_config spi_cfg = {0}; struct spi_buf_set tx_set; unsigned char digit[2]={0}; printk("spi master example "); spi = DEVICE_DT_GET(DT_NODELABEL(spi0)); if (!device_is_ready(spi)) { printk("SPI device %s is not ready ", spi->name); return; } /* spi master 8bit, LSB first*/ spi_cfg.operation = SPI_WORD_SET(8) | SPI_OP_MODE_MASTER | SPI_TRANSFER_MSB; spi_cfg.frequency = 5 * 1000000UL; /* Make spi transaction package buffers */ struct spi_buf *tx_package = k_calloc(TX_PACKAGE_MAX_CNT, sizeof(struct spi_buf)); if (tx_package == NULL) { printk("tx_package calloc failed "); return; } /* Init 7219 */ tx_package[0].buf = work_state; tx_package[0].len = 2; tx_package[1].buf = test_state; tx_package[1].len = 2; tx_package[2].buf = decode_cfg; tx_package[2].len = 2; tx_package[3].buf = scan_range; tx_package[3].len = 2; tx_set.buffers = tx_package; tx_set.count = 4; printk("Init 7219 ... "); spi_write(spi, &spi_cfg, &tx_set); do { k_msleep(1000); printk("spi master sending jiandao_table data ... "); for (idx=0; idx<8; idx++) { digit[0]=jiandao_table[idx][0]; digit[1]=jiandao_table[idx][1]; tx_package[0].buf = digit; tx_package[0].len = 2; tx_set.buffers = tx_package; tx_set.count = 1; spi_write(spi, &spi_cfg, &tx_set); } k_msleep(1000); printk("spi master sending shitou_table data ... "); for (idx=0; idx<8; idx++) { digit[0]=shitou_table[idx][0]; digit[1]=shitou_table[idx][1]; tx_package[0].buf = digit; tx_package[0].len = 2; tx_set.buffers = tx_package; tx_set.count = 1; spi_write(spi, &spi_cfg, &tx_set); } k_msleep(1000); printk("spi master sending bu_table data ... "); for (idx=0; idx<8; idx++) { digit[0]=bu_table[idx][0]; digit[1]=bu_table[idx][1]; tx_package[0].buf = digit; tx_package[0].len = 2; tx_set.buffers = tx_package; tx_set.count = 1; spi_write(spi, &spi_cfg, &tx_set); } } while (1); }
2.3.4 搭建AI工程
参考文档AI能力-视觉的相关步骤搭建AI工程,这里主要说明一下遇到的几个问题和注意事项。
1)因为此处使用的是最新git工程,所以打印可能与文档有出入,git版本和打印对应如下:
2)如果直接下载git工程编译升级,PC端工具无法正常使用,需要执行如下两条命令,参考连接一键拉取-sample-和-sdk-异常解决方法,然后再执行编译烧写操作。
lisa zep init-app lisa zep update
3)基于Edge浏览器如果直接打开在线PC工具,点击"Windows系统"会出现404错误,所以建议直接下载pc工具工程到本地离线使用。
git clone https://cloud.listenai.com/zephyr/applications/csk_view_finder_spd.git
4)执行"lisa zep flash"后如果立即执行如下资源下载命令可能会失败,这时候建议拔插一下DAP口或者检查一下串口是否被占用。
经过上述步骤以后,通过PC端工具查看效果如下:
2.3.5 识别和显示
将SPI-GC7219的工程和AI手势识别的工程融合在一起,程序流程如下:
三 效果展示
效果如下,机器会根据人类的出拳来出拳,用来给做简单的演示还是挺有意思的。
四 总结
整体体验下来,感觉聆思在SOM的易用性、接口的完整性、文档的丰富度、和支持的及时性上做的都不错,按照文档一步步做下来,很快就可以入门做一些简单的产品。美中不足的是目前聆思的AI训练和调参工具还没有面向大众开放,可能是因为技术性比较强,但因此少了一部分趣味性,在手势AI识别的demo中也能够感觉到光照和距离对识别的准确性影响很大,但是在如此低的功耗和性能下做到这样的程度已经很棒了。最后祝聆思科技的产品越做越棒,极术社区越做越大带给广大开发兴趣人员更多丰富的活动。
转自 | 安谋科技学堂
审核编辑:汤梓红
全部0条评论
快来发表一下你的评论吧 !