# gsd
 
野生动物管理前端设备, 统一采用docker镜像 + docker-compose的部署方式, 为了更好管理软件版本, 仓库会进行各类细分, 主要分为部署仓库、应用层开发仓库、算法层开发仓库.

## 1.软件仓库

目前硬件平台有寒武纪、Jetson TX2-NX, 软件仓库部分不通用。

**寒武纪mlu220:**

| 仓库 | 地址 |
| --- | --- |
| 部署 | http://git.siwill.com/lishengyin/gsd_cn.git |
| 应用层 | http://git.siwill.com/lishengyin/gsd.git |
| 算法层 | http://git.siwill.com/lishengyin/cnstream.git | 

**Jetson TX2-NX:**

| 仓库 | 地址 |
| --- | --- |
| 部署 | http://git.siwill.com/lishengyin/gsd_nv.git |
| 应用层 | http://git.siwill.com/lishengyin/gsd_dsm.git |
| 算法层 | http://git.siwill.com/lishengyin/gsd_dma.git | 

## 2.自动化运维

因为大多数设备与服务器之间都是使用VPN组网, 结合gitlab、harbor则可以实现真正意义上的自动化部署, 这时就涉及到多机的管理, 采用的[spug](https://www.spug.cc/), 各机场搭建位置不同, spug功能上主要包含**自动化运维、应用层配置文件管理**等.

| 机场 | 地址 | 网络结构 |
| --- | --- | --- |
| 成都、兰州、大兴、首都、白云、乌鲁木齐  | http://47.112.106.146:9090/ | VPN组网 |
| 合肥机场 | http://192.168.1.228:9090 | 自组内网 |
| 深圳机场 | http://10.94.207.1:9090  | 机场内部组网 | 

spug账号密码统一为: admin sunwin2021 

## 3.软件框架

> TODO

## 4.配置文件

配置文件主要分为应用层配置文件、算法层配置文件。应用层配置文件存放于SPUG中, 通过HTTP接口查询获取, 而算法配置文件则存放于本地部署文件中。

### 4.1 应用层配置

应用层配置主要包含Netty服务地址、过滤器配置、SPUG地址、与Netty端通信的标识符、mysql地址.

### 4.1.1 配置详解

**配置文件Json格式如下:**
```json
{
  "usr": "addBirdWarning5",  // 与Netty通讯的账号
  "pwd": "sunwin20200507",   // 密码
  "dockerio": "10.8.0.113:8080",  // dockerhub的地址
  "com_port": "/dev/ttyUSB0",  // 驱鸟器的控制串口
  "ClearPastRecords": "1",   // 弃用
  "bboxSize": "400.0",  // 过滤小于这个大小的目标
  "vpn": "1",  // 是否启动vpn
  "TimeOut": "360000",  // 超时时间
  "sensitivity": "2",   // 弃用
  "NettyPort": "84",  // netty端口
  "NettyIP": "47.112.106.146", // netty地址
  "NettyHttpPort": "8860", // netty的http接口
  "mysql_port": "3306",  
  "mysql_IP": "127.0.0.1",
  "LowVersion": "1",  // 低版本使能
  "interval": "2000",  // 发送鸟情数据的间隔时间ms
  "InferDataRetentionTime": "3", // 弃用
  "HardDiskCleanupTime": "3", // 弃用
  "getHistoryVideoFlag": "0",  // 弃用
  "filterLevel": "2", // 过滤器等级
  "ExpelInterval": "10000",  // 驱鸟器的控制间隔
  "DiskUsageThreshold": "0.90", // 内存阈值
  "Debug": "1" // 日志调试
}
```

**配置说明:**

| 配置项 | 作用 |
| --- | --- | 
| LowVersion | 低版本使能, 低版本下兼容公网47.112.106.146上的服务, 高版本则是可以使用http接口获取相关数据以及相关逻辑控制 |
| filterLevel | 过滤等级, 0 - 不过滤  1 - 相似度对比过滤  2 - 时间间隔与相似度条件并行过滤 3 - 记录每一条数据, 数据存在消亡时间, 数据来了与历史数据进行对比, 如相识则过滤 |
| ExpelInterval | 驱鸟器的控制间隔, 避免如煤气瓶这种一直发现鸟情一直开炮的情况 |
| Debug | 启动相关的日志记录, 方便调试 |

**注意:** 应用层配置文件主要保存于SPUG中, 所以应用层程序启动时, 需要先配置**SPUG地址和端口**和**SPUG的应用标识**, 而其他配置默认采用SPUG的配置, **配置文件存放** 地址为 **/etc/gsd/config.ini**, **spug应用标识**的物理存放地址为 **/etc/gsd/gsdApp**.

#### 4.1.2 spug应用标识规则

```shell
sunwin@sunwin:~$ cat /etc/gsd/gsdApp 
gsd_PKX
```
应用标识: gsd_机场三字码, 如: 大兴机场 gsd_PKX
机场三字码查询地址: https://airportcode.bmcx.com/

#### 4.1.3 设备端SNCode编码规则

0331 + mac地址最两位 + 生成日期(21A05 2021年1月5日) + 成品批次(01) + 硬件代号(01:杰和工控机 02：华为软件相机 03：凌华工控机 04：英伟达Nano 05：英伟达TX2 06:英伟达AGX) + 批次中的生产序号(0001)

> 0331FE21A0501010001

### 4.2 算法层配置

**1.CNStream配置文件**

基础文件结构:

```shell
├── bin
│   └── main
├── config
│   ├── detection_config.json  # 整体结构的配置文件
│   ├── detection_test.json # 测试配置文件
│   ├── file.list_video_test   
│   └── files.list_video_rtsp # 视频流源地址
├── configs
│   ├── coco_pose_mlu220.json
│   ├── coco_pose_mlu270.json
│   ├── decode_config.json
│   ├── InfineFilter.json  # 过滤器配置
│   ├── kafka.json
│   ├── license_plate_detection_and_recognition_mlu220.json
│   ├── license_plate_detection_and_recognition_mlu270.json
│   ├── locus.json  # 轨迹模块
│   ├── object_tracking_mlu220.json
│   ├── object_tracking_mlu270.json
│   ├── osd_configs
│   │   ├── osd_label_map.json
│   │   └── osd_synset_words.json
│   ├── recorder.json # 记录模块
│   ├── resnet_classification_mlu220.json
│   ├── resnet_classification_mlu270.json
│   ├── sinker_configs
│   │   ├── display.json
│   │   ├── encode_jpeg.json
│   │   ├── encode_video.json
│   │   ├── kafka.json
│   │   └── rtsp.json
│   ├── udp.json # 通讯模块
│   ├── vehicle_cts_mlu270.json
│   ├── yolov3_object_detection_mlu220.json
│   ├── yolov3_object_detection_mlu270.json
│   ├── yolov5_object_detection_mlu220.json # 推理模块配置
│   ├── yolov5_object_detection_mlu270.json
│   └── yolov5_object_test.json
├── data
│   ├── models
│   │   ├── label_map_gsd.txt
│   │   ├── yolov5_4c4b_rgb_220.cambricon
│   │   ├── yolov5m_best6_b_b_insect_s3_int8_0828_4b_4c.cambricon
│   │   ├── yolov5m_best6_b_b_insect_s4_firstconv_int16_0911_4b_4c.cambricon
│   │   ├── yolov5m_best6_b_b_insect_s4_int16_0910_4b_4c.cambricon
│   │   ├── yolov5m_best6_b_b_insect_s4_small_int16_0916_4b_4c.cambricon
│   │   └── yolov5m_best6_b_b_insect_s5_int16_0924_4b_4c.cambricon
│   ├── videos
│   │   └── cars.mp4
│   └── wqy_zenhei.ttf
├── lib

```

CNStream程序通过**detection_config.json**配置整体结构, 其中包含不同的模块, 各模块的配置文件则是在configs/, 具体资料请参考[CNStream用户手册](https://www.cambricon.com/docs/cnstream_new/6.3.0/user_guide/index.html). 其中包含一些自研的模块:

| 模块 | 作用 |
| --- | --- |
| InfineFilter | 推理数据过滤模块, 内部包含比例过滤器、异物过滤器、比例过滤器, 为降低误识别率 | 
| locus | 描绘识别物体轨迹(已弃用) |
| recorder | 记录识别结果视频 | 
| udp | 通讯模块, 只传输识别结果不传输图片 |

- InfineFilter 模块配置文件说明

> InfineFilter 模块主要为过滤器, 其中异物过滤器则需指定目标和异物类型

| 配置 | 示例 | 作用 |
| --- | --- | --- |
| labels  | 0  | 目标id |
| AlienLabels | 2 | 异物Id
| Proportion_th | 0.5 | 异物过滤器的阈值, 如异物占整个比例0.5以上, 则认为其他目标也为异物  |
| files | /home/GSD/video/filter/ | 过滤器一些过滤结果保存 |
| saveFilterResult | true | 是否保存结果 |
| Night_Filter | true | 是否启动夜间过滤器 |
| lock_period | {"start": 20,"end": 4 } | 指定夜间的时间范围, 作用于夜间过滤器 |

- recorder 模块配置文件说明

| 配置 | 示例 | 作用 |
| --- | --- | --- |
| dst_width | 960 | 保存结果宽度 | 
| dst_height | 540 | 保存结果高度 |
| frame_rate | 20 | 视频帧数 |
| videoMaxTime | 120 | 视频最大秒数量, 避免产生过大的视频 |
| cacheTime | 3 | 指缓存3s内的图片数据 |
| enc_type | ".mp4" | 封装格式和后缀名 |
| outputDir | /home/GSD/video/ | 视频保存位置 |

- udp 模块配置文件说明

> UDP模块 主要用于算法层与应用层通讯, 用于驱鸟器控制, 分出一个独立模块负责, 避免kafka数据处理延迟的问题.  

| 配置 | 示例 | 作用 |
| --- | --- | --- |
| sendSockerIP | "127.0.0.1" | sockerIP | 
| sendPort | 7777 | 发送端口

**2.Deepstream配置文件**

```txt
[property]
gpu-id=0
net-scale-factor=0.0039215697906911373
#0=RGB, 1=BGR
model-color-format=0
# custom-network-config=yolov3-tiny.cfg
# model-file=yolov3-tiny.weights
model-engine-file=../data/INT8/yolov5m.engine # 指定模型
labelfile-path=labels.txt
process-mode=1
batch-size=12
## 0=FP32, 1=INT8, 2=FP16 mode
network-mode=1
num-detected-classes=80
gie-unique-id=1
network-type=0
#is-classifier=0
output-blob-names=prob
## 0=Group Rectangles, 1=DBSCAN, 2=NMS, 3= DBSCAN+NMS Hybrid, 4 = None(No clustering)
cluster-mode=2
interval=0
maintain-aspect-ratio=1
parse-bbox-func-name=NvDsInferParseCustomYoloV5
custom-lib-path=../lib/libnvdsinfer_custom_impl_Yolo.so
engine-create-func-name=NvDsInferYoloCudaEngineGet
#scaling-filter=0
#scaling-compute-hw=0

[class-attrs-all]
nms-iou-threshold=0.5
pre-cluster-threshold=0.4
```

## 5.部署流程

部署过程参考Ones上gsd设备部署资料,注意的点在于要提前配置好**gsdApp、gsdinfo、files.list_video_rtsp**,还有config.ini主要要配置好spug的地址和端口, 保存路径均在**/etc/gsd/**.

## 6.CI/CD说明

CI/CD这部分, 现阶段用的比较多的SPUG + gitlab的方案, 但是我也提供了gitlab的CI/CD的方案, gitlab的CI/CD方案没用起来的原因还是大部分机场用的还是运营商网络(流量卡 + CPE)的方案, 网络环境并稳定. 经过几轮测试后, 决定还是使用SPUG + gitlab的方案, 核心思路在利用spug实现多机执行脚本, git拉下部署文件, 形成本地、云端代码的备份, 并且docker容器迭代原则**兼容前代环境**, 所以这套方案就能实现, 包含快速迭代、快速回滚、多层次备份等优点. spug本来也有自动化部署工具, 但是还要**讲究好资料再用**, 里面包含一些坑点.

## 7.算法部署方面

目前寒武纪方面的模型转换都是由算法工程师来弄, NVDIA的模型则可以参考[tensorttx](https://github.com/wang-xinyu/tensorrtx), **CNStream**和**Deepstream**则也需要自行去学习了.

## 8.后期展望

目前居多的设备还是工控机+mlu220的形态, 后期就会更换层Jetson TX2-NX,前期受到mlu220性能的困扰, 更换后Jetson系列后, 实现一个高可用的产品形态变成了可能, 设备节点进行细分, 数据保存到数据节点, 算法节点就单独的算法节点, 即使算法节点挂了, 也能自动把服务转到另外一个算法节点上, 具体的话可以引入K8s到这个项目, 从而实现真正意义的自动化运维、高可用。。。

## 9.部署简要说明

- 首先检查检查docekr、docker-compose服务

- 构建 **gsd** 设备基础配置文件, 存储路径位于 **/etc/gsd/**, 主要包含 **config.ini、files.list_video_rtsp、gsdApp、gsdinfo** , 具体参考配置文件模板.

| 配置文件 |  作用 |
| --- | --- | --- | 
| config.ini | 应用层配置( **主要指定spug地址和端口, 其他配置都是以spug上的配置为准** ) |
| gsdApp | spug配置文件标识 |
| files.list_video_rtsp | 算法分析的视频流地址 |
| gsdinfo | 设备sncode |

- 拉取部署镜像

**注意: 环境变量文件, 因为要更方便指定dockerhub地址和摄像头IP, 所以使用环境变量来管理, 启动前需要先配置好环境变量**

```shell
sunwin@sunwin:~$ sudo cat /etc/profile.d/gsdProfile.sh 
[sudo] sunwin 的密码： 
export dockerio="10.8.0.113:8080"
sunwin@sunwin:~$ sudo cat /etc/profile.d/rtsp.sh 
export rtspip="192.168.1.130
```

- 拉取部署文件

- 配置定时检查脚本

定时检查脚本, 主要应用于检查各类服务, 如vpn、rtsp摄像头、加速卡温度这些服务, 定时器统一使用crontab管理.

```shell
sunwin@sunwin:/opt/GSD$ cat /etc/crontab 
# /etc/crontab: system-wide crontab
# Unlike any other crontab you don't have to run the `crontab'
# command to install the new version when you edit this file
# and files in /etc/cron.d. These files also have username fields,
# that none of the other crontabs do.

SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

# m h dom mon dow user  command
17 *    * * *   root    cd / && run-parts --report /etc/cron.hourly
25 6    * * *   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )
47 6    * * 7   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )
52 6    1 * *   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )
#

*/1 * * * * root /opt/GSD/check_tacks/check_network.sh
*/1 * * * * root /opt/GSD/check_tacks/check_rtsp.sh
0 0 */2 * * root /opt/GSD/stop/reboot_System.sh
* * * * * root /opt/datas/temp.sh
sunwin@sunwin:/opt/GSD$ 
```

- 开机自启动

采用**sysv-rc-conf**, 主要将部署文件中**start_System.sh**, 放置到 **/etc/init.d/** 目录下.

```shell
sysv-rc-conf start_System.sh on  # 开启
sysv-rc-conf start_System.sh off # 关闭
```
