1、前言

本来以为jetson nano就是一台小型计算机而已,把模型复制到上面运行就可以了,可实际操作起来遇到了很多问题,踩了很多坑,现在整理一下。

2、项目简介

不知道大家是否观察过:很多学生都习惯趴着写作业、看书,还有的学生喜欢把头甚至身体歪向一侧。这样的行为对脊柱发育非常不好,同时会因为坐姿问题导致视力下降。

本项目通过实时监测学生坐姿,并及时提醒学生纠正错误坐姿,实现预防近视的目的。

3、jetson nano开发板组装

  1. 看到别人发的图片亚克力板是透明的,而我的不是透明的。研究了半天才发现亚克力板两边都粘了保护纸,把保护纸撕掉就变成透明的了。
  2. 刚开始组装时把螺丝拧得很紧,结果有一个侧边一直向上翘,结果反复拆装了好几次才不翘了。
  3. 风扇方向问题:看到有大佬发的项目里的风扇“创乐博”的标志在上面,向外吹风,于是我就照着装了。后来在网上搜了一下,有人说“创乐博”的标志应该在下面,紧挨着散热器,于是我把风扇卸下来仔细观察了一下,发现“创乐博”的标志确实应该在下面,因为如果“创乐博”的标志在上面的话螺丝拧好后是凸出来的,而“创乐博”的标志在下面的话,螺丝孔那里有个小坑,拧好后是与风扇是平齐的。
  4. 摄像头安装:
  • 注意:在安装摄像头的时候需要断电
  • 首先把Nano的这个CSI接口的这个销子轻轻拔起,注意要小心,千万别拔断
  • 然后插入CSI摄像头的排线线缆,注意方向和正反,别插反了
  • 接下来把刚才拔起来的销子压下去固定好
  • 别忘记把摄像头的保护贴膜去掉

组装好后是这样的:

android ORD 坐姿识别算法开发 坐姿检测功能_VMware

4、 烧录

第1步:安装虚拟机文件。

本来想安装jetson nano上提供的VMware-workstation-full-15.5.6-16341506.exe文件,结果出现了“检测到不支持的CPU”提示:

android ORD 坐姿识别算法开发 坐姿检测功能_paddle_02

在网上查了一下,说是“VMware Workstation 14.x ,15.x ,16.x ……之后的版本仅仅支持使用 2011 年之后上市或更高版本的CPU (处理器)”。

网上给出的解决办法:

  • 更换CPU,还有就是貌似VMware Workstation16.x之后的虚拟机版本仅仅支持win8、win10……之后的操作系统,所以限制不是单一的,一个是硬件限制,还有一个是系统版本限制,
  • 除此之外就只能下载安装低版本的VM虚拟机

更换CPU,重装系统太麻烦,还费钱,于是我从网上下安装了12.5.9版本的VMware安装上了。(注意,不要装VirtualBox,它不支持.vmx格式。)

然后加载clb_jetson时又出现不兼容提示:

android ORD 坐姿识别算法开发 坐姿检测功能_paddle_03

解决办法:

  1. 打开clb_jetson.vmx文件,找到virtualHWVersion,将数值改为当前使用的版本,修改virtualHW.version = “12”,保存。
  2. 打开clb_jetson.vmdk文件,找到ddb.virtualHWVersion,修改ddb.virtualHWVersion = “12”,保存。

改好之后就可以加载clb_jetson了

android ORD 坐姿识别算法开发 坐姿检测功能_1024程序员节_04

点击“启动此虚拟机”进入以下画面:

android ORD 坐姿识别算法开发 坐姿检测功能_命令行_05

这个密码是:123456,输入密码后,就可以进入这个画面了:

android ORD 坐姿识别算法开发 坐姿检测功能_命令行_06

然后就可以按照教程进行烧录了。

第2步:设置烧写模式

用跳线连接Nano主板的2、3针脚,既设置烧写模式,如下图所示:

android ORD 坐姿识别算法开发 坐姿检测功能_paddle_07

第3步:连接数据线

连接PC机的USB口和Nano的Micro USB口,如下图所示:

android ORD 坐姿识别算法开发 坐姿检测功能_paddle_08

第4步:上电

上电,如下图所示。

android ORD 坐姿识别算法开发 坐姿检测功能_VMware_09

此时虚拟机会自动弹出检测到USB设备。选择连接到虚拟机。

android ORD 坐姿识别算法开发 坐姿检测功能_1024程序员节_10

第5步:开始烧录eMMC

在PC端的虚拟机内,用鼠标右键点击 进入命令行:

android ORD 坐姿识别算法开发 坐姿检测功能_1024程序员节_11

输入“sudo ./flash.sh -r jetson-nano-devkit-emmc mmcblk0p1”后回车运行,并输入密码,这里为“nvidia”(没有引号),即可开始烧录。

android ORD 坐姿识别算法开发 坐姿检测功能_1024程序员节_12

由于电脑比较老,速度有点慢,郁闷的事情发生了:

android ORD 坐姿识别算法开发 坐姿检测功能_VMware_13

烧录失败了,换个USB口连接Nano主板,重复上面的步骤(在命令行输入“sudo ./flash.sh -r jetson-nano-devkit-emmc mmcblk0p1”后回车运行,并输入密码,这里为“nvidia”(没有引号),即可开始烧录),这次成功了:

android ORD 坐姿识别算法开发 坐姿检测功能_VMware_14

此时可以退出虚拟机:

第6步:烧录SD卡

在PC上安装 Balena Etcher 烧录工具balenaEtcher-Setup-1.7.7.exe。

然后,将SD卡放入读卡器,并插入PC。

此后的SD卡烧录方法与原厂套件的烧录方法相同。

运行软件,出现如下界面:

android ORD 坐姿识别算法开发 坐姿检测功能_paddle_15

此时,选择以下文件:

android ORD 坐姿识别算法开发 坐姿检测功能_1024程序员节_16


android ORD 坐姿识别算法开发 坐姿检测功能_1024程序员节_17

选择如下:

android ORD 坐姿识别算法开发 坐姿检测功能_VMware_18


点击Flash 开始烧录SD卡

android ORD 坐姿识别算法开发 坐姿检测功能_1024程序员节_19

烧录中:

android ORD 坐姿识别算法开发 坐姿检测功能_paddle_20

烧录完成:

android ORD 坐姿识别算法开发 坐姿检测功能_paddle_21

【注意】写入 SD 卡的数据以 Linux 的 ext4 格式存在,因此在 Windows 下面是无法识别的,请 Windows 使用者无需惊慌(有遇到不少用户在 Windows 下看不到数据,还以为自己没有安装成功)。

第7步:启动前的准备

【注意】一定要先拔掉Nano的电源,然后再把SD卡插入到Nano上。

【还要注意】再次上电之前,需要将跳线拔掉。

第8步:启动Nano

把Nano连接到显示器,再接上鼠标键盘,就可以上电启动了。

android ORD 坐姿识别算法开发 坐姿检测功能_VMware_22

5、扩充磁盘空间,增加虚拟内存 swapfile

  1. 扩充磁盘空间

在SD卡写入系统后,默认会有一部分可用磁盘空间是被隐藏的,因此我们需要把它释放出来。

操作方法很简单,在Nano上直接安装 gparted 工具(sudo apt-get install gparted),运行工具后找到SD卡(一般为/dev/sda1) 右击已分配的分区,resize,拖到很靠右又不是全部在右边的地方,然后就可以开始了。

这里有官方视频教程,请大家参考。

  1. 增加虚拟内存

Jetson Nano 2GB 的内存相对弱势,所幸 Linux 提供了一种 SWAP 技术,能将存储设备空间作为虚拟内存使用,性能虽然不如物理内存,但也能支撑更多深度学习的计算。

官方提供的操作方法在这里的“4.1增加交换空间大小”章节,如法炮制即可。

6、开发环境搭建

  1. 建议移除LibreOffice
    这会为系统省很多空间,而且这个软件对做深度学习和计算机视觉算法也没什么用。

sudo apt-get purge libreoffice

sudo apt-get clean

  1. 下载并安装与Jetpack版本对应的PaddlePaddle

查看Jetpack版本:

cat /etc/nv_tegra_release

这是大佬的图片:

android ORD 坐姿识别算法开发 坐姿检测功能_1024程序员节_23

我看了半天也没看出来上边的6.1怎么和下边的4.6对应上的,然后就下错版本了,无法安装成功,期间升级python到3.7也没安装成功,然后反复折腾,最后重新烧录SD卡,下载paddlepaddle_gpu-2.3.0-cp36-cp36m-linux_aarch64.whl版本安装成功。

7、程序部署

  1. 获取导出后的mobilenet_v3_small模型
    本文将采用mobilenet_v3_small模型,实时监测学生坐姿。

关于模型的生产过程,请移步这里:用飞桨实时监测学生坐姿,预防近视

其中,导出好的模型,保存在本项目的此目录下:

/home/nvidia/zzjk

android ORD 坐姿识别算法开发 坐姿检测功能_命令行_24

需要说明的是,由于此模型数据集是自己在固定位置,用少量样本电脑截图创建的,数据量少,而b01摄像头位置不好固定,与电脑截图分辨率等参数不一致等因素,因此准确度不高。感兴趣的同学可以自行收集更多数据,参考原文重新训练。

为了让风扇运转可以使用

$ sudo sh -c ‘echo 200 > /sys/devices/pwm-fan/target_pwm’

进行调节,其中200的位置可以是0~255任意整数,越大风扇转速越高

  1. 程序主要代码:
import argparse
import numpy as np
import matplotlib.pyplot as plt
# 引用 paddle inference 推理库
import paddle.inference as paddle_infer

import cv2
import paddle.vision.transforms as T
import time
from playsound import playsound
                         
def main():
    args = parse_args()

    # 创建 config
    config = paddle_infer.Config(args.model_file, args.params_file)

    # 根据 config 创建 predictor
    predictor = paddle_infer.create_predictor(config)

    # 获取输入的名称
    input_names = predictor.get_input_names()
    input_handle = predictor.get_input_handle(input_names[0])
    transform = T.Compose([
                            T.Resize([240,240]),
                            T.CenterCrop(224),
                            T.Normalize(mean=[127.5, 127.5, 127.5],std=[127.5, 127.5, 127.5], data_format='HWC'),
                            T.ToTensor(),
                             ])    
    # 设置输入

    cap= cv2.VideoCapture("nvarguscamerasrc ! video/x-raw(memory:NVMM), width=3264, height=1848, format=NV12, framerate=28/1 ! nvvidconv flip-method=0 ! videoconvert ! video/x-raw, format=BGR ! appsink")
   
    while True:
           
        ret,img=cap.read()
        img=np.float32(img)
        img= transform(img)
        img=img.numpy()
      

        fake_input=np.expand_dims(img,0)
        input_handle.reshape([args.batch_size, 3, 224, 224])
        input_handle.copy_from_cpu(fake_input)
        
        # 运行predictor
        predictor.run()

        # 获取输出
        output_names = predictor.get_output_names()
        output_handle = predictor.get_output_handle(output_names[0])
        output_data = output_handle.copy_to_cpu() # numpy.ndarray类型
        output_data=softmax(output_data)  #######

        
        pred_label = output_data[0].argmax()
        gl=output_data[0][pred_label].item()


        if labels[pred_label]=='眼睛离书本近':      #这一部分声音要和标签对应,新建1个wav文件夹存放声音,可以录自己的声音提配,也可以用paddlespeech生成语音。
            PlaySound('./wav/0.wav',flags=1) 
            time.sleep(3)                #暂停3秒是为了把语音读完
        elif labels[pred_label]=='趴着写字':
            PlaySound('./wav/1.wav',flags=1) 
            print('趴着写字')
            time.sleep(3)
        elif labels[pred_label]=='坐姿正确':
            print('趴着写字')
        else:
            pass   


def parse_args():
    parser = argparse.ArgumentParser()
    parser.add_argument("--model_file", type=str,default='./model/save_dir.pdmodel', help="model filename")
    parser.add_argument("--params_file", type=str,default='./model/save_dir.pdiparams', help="parameter filename")
    return parser.parse_args()
    
def softmax(x):
    row_max=np.max(x)
    x=x-row_max
    x_exp=np.exp(x)
    x_sum=np.sum(x_exp)
    s=x_exp/x_sum
    return s

if __name__ == "__main__":
    main()
  1. 程序运行

命令行下运行:

cd zzjk

python3 zzjk.py

android ORD 坐姿识别算法开发 坐姿检测功能_1024程序员节_25

android ORD 坐姿识别算法开发 坐姿检测功能_1024程序员节_26

  1. 效果示意图

android ORD 坐姿识别算法开发 坐姿检测功能_paddle_27

8、总结与升华

远程历险记
  1. 我最开始是接到电视上了,由于电视和电脑不在一个屋,加上对Nano不熟悉,需要不停地跑来跑去在电脑与Nano上切换鼠标、键盘进行操作,太麻烦了。
  2. 于是下载了一个todesk,结果还下错版本了,折腾了半天,最后下载了“todesk-v4.3.1.0-arm64.deb”(注意最后应该是arm64,而不是amd64),在命令行下输入sudo apt-get install ./todesk-v4.3.1.0-arm64.deb进行安装。后来发现todesk离不开电视(显示屏),也就是说Nano只有接到电视上才能用todesk,无法移到其它地方。
  3. 后来安装了VNC,电脑上安装了VNC Viewer,这个不需要显示器,但是没有声音。
  4. 安装了虚拟显示器,又切回todesk,可以不需要电视直接登录Nano了,由于Nano没有外接音响,播放不了声音。
  5. 用VNC和todesk都不能与电脑交互复制文件,于是又装了xrdp,在windows上运行mstsc.exe进行远程连接。
  6. 用VNC和todesk屏幕显示是一样的,xrdp显示与前两者不一样,三个远程同时打开的话,用VNC和todesk的操作可以在mstsc的屏幕上显示出来。
声音历险记
  1. Nano没有音频接口,导致有音响无法使用。
  2. 用高清线接到电视上有声音,但是Nano只能连到电视上,无法移到其它地方。
  3. 家里有小度蓝牙音响,找到一个蓝牙接收器,Nano不能识别,百度了几天,装了一堆东西,也没能让Nano接到蓝牙音响。
  4. 网上搜了半天,说todesk和xrdp可以在本地播放远程声音,装了一堆东西,试了几天,也没成功。
  5. 最后,想到了这个项目用paddleocr打造一款“盗幕笔记”,在此项目的基础上修改了一下代码,在Nano上print出坐姿类别,在电脑上用paddleocr进行文字识别,识别完后,在本地电脑上播放对应的声音提示,问题得以暂时解决。

由于安装了3个远程(todesk,vnc,xrdp)和一堆乱七八糟的东西,Nano运行速度有点慢,有待进一步优化。

请点击此处查看本环境基本用法.

Please click here for more detailed instructions.