diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..69e9da2dc473a8b5ee07fa705de6c112bccf5276 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +# Build Temp + +build +lockzhiner_vision_module_sdk* +opencv-mobile-4.10.0-lockzhiner-vision-module* +.vscode \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..261eeb9e9f8b2b4b0d119366dda99c6fd7d35c64 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.en.md b/README.en.md deleted file mode 100644 index 22562caa74a1c6b19fc98887a716bb0579080e24..0000000000000000000000000000000000000000 --- a/README.en.md +++ /dev/null @@ -1,36 +0,0 @@ -# LockzhinerVisionModule - -#### Description -{**When you're done, you can delete the content in this README and update the file with details for others getting started with your repository**} - -#### Software Architecture -Software architecture description - -#### Installation - -1. xxxx -2. xxxx -3. xxxx - -#### Instructions - -1. xxxx -2. xxxx -3. xxxx - -#### Contribution - -1. Fork the repository -2. Create Feat_xxx branch -3. Commit your code -4. Create Pull Request - - -#### Gitee Feature - -1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md -2. Gitee blog [blog.gitee.com](https://blog.gitee.com) -3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore) -4. The most valuable open source project [GVP](https://gitee.com/gvp) -5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help) -6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) diff --git a/README.md b/README.md index 9037ee0c76be49be38cc21086c5e12a59d03f9ac..733af2325cc34f43d0618eb789fbfaa08d23969f 100644 --- a/README.md +++ b/README.md @@ -1,39 +1,84 @@ -# LockzhinerVisionModule +

Lockzhiner Vision Module

-#### 介绍 -{**以下是 Gitee 平台说明,您可以替换此简介** -Gitee 是 OSCHINA 推出的基于 Git 的代码托管平台(同时支持 SVN)。专为开发者提供稳定、高效、安全的云端软件开发协作平台 -无论是个人、团队、或是企业,都能够用 Gitee 实现代码托管、项目管理、协作开发。企业项目请看 [https://gitee.com/enterprises](https://gitee.com/enterprises)} +Lockzhiner Vision Module 是福州市凌睿智捷电子有限公司倾力打造的一款高集成度人工智能视觉模块,专为边端人工智能和机器视觉应用而设计,其特色包括: -#### 软件架构 -软件架构说明 +* 卓越的计算能力:Lockzhiner Vision Module 搭载单核 ARM Cortex-A7 处理器,并集成了 NEON 和 FPU,以更出色地处理 SIMD 和浮点计算。同时,该模块支持 Int8 量化,内置 0.5 TOPs 的 NPU,足以应对绝大多数的视觉应用场景。 +* 广泛的开源适配:Lockzhiner Vision Module 与 PaddleClas、PaddleDetection、PaddleSeg、PaddleOCR 等基于 Paddle 框架的视觉场景库完美适配,并内置了一键启动脚本。配合 AIStudio,用户可以实现一键训练、一键部署,从而极大地减轻了部署负担。 +## 🔄 最新日志 -#### 安装教程 -1. xxxx -2. xxxx -3. xxxx +## 💡 入门学习教程 -#### 使用说明 +这一部分教程旨在为你提供一个系统化的学习路径,帮助你快速上手 Lockzhiner Vision Module。通过一系列详细的教程,你将学会如何烧录镜像、连接设备、搭建开发环境和编写简单的程序。 -1. xxxx -2. xxxx -3. xxxx +* [烧录镜像指南](./docs/introductory_tutorial/burn_image.md) +* [连接设备指南](./docs/introductory_tutorial/connect_device_using_ssh.md) -#### 参与贡献 +如果你需要开发 Python 程序,请参考以下教程搭建开发环境: -1. Fork 本仓库 -2. 新建 Feat_xxx 分支 -3. 提交代码 -4. 新建 Pull Request +* [Python 开发环境搭建指南](./docs/introductory_tutorial/python_development_environment.md) +如果你需要开发 C++ 程序,请参考以下教程搭建开发环境: -#### 特技 +* [C++ 开发环境搭建指南](./docs/introductory_tutorial/cpp_development_environment.md) +* [基于 C++ 编写 Hello World 程序](./example/hello_world/README.md) -1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md -2. Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com) -3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目 -4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目 -5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help) -6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) +## 🔌 外设控制教程 + +Lockzhiner Vision Module 拥有丰富的 IO 接口,其接口图片如下图所示: + +![](images/periphery.png) + +为了帮助你快速上手教程,我们提供了一系列的外设控制例程,你可以点击链接快速学习 + +* [串口使用指南](./example/periphery/usart/README.md) +* [ADC 使用指南](./example/periphery/adc/README.md) +* [PWM 使用指南](./example/periphery/pwm/README.md) +* [GPIO 使用指南](./example/periphery/gpio/README.md) +* [摄像头使用指南](./example/periphery/capture/README.md) + +## 🧠 深度学习视觉部署教程 + +这一部分教程将引导你从零开始训练并部署各种深度学习模型,包括分类模型、检测模型、分割模型和 OCR 模型。通过这些实战教程,你将学习到如何利用 Lockzhiner Vision Module 的高性能计算能力以及借助 Paddle 生态系统的丰富资源,轻松实现视觉任务的训练和部署。 + +* [分类模型部署指南](./example/vision/classification/README.md) +* [检测模型部署指南(支持中)]() +* [分割模型部署指南(支持中)]() +* [OCR 模型部署指南(支持中)]() + +## 👍 特色模型部署教程 + +* [手写数字检测部署指南(支持中)]() +* [人脸佩戴口罩检测部署指南(支持中)]() +* [二维码识别与检测部署指南(支持中)]() + +## 🐛 Bug反馈 + +如果您遇到问题,您可以前往 [Lockzhiner Vision Module Issues](https://gitee.com/LockzhinerAI/LockzhinerVisionModule/issues) 并点击已完成按钮查看其他用户反馈且我们已经解决的 Bug。 + +![](images/issues_completed.png) + +如果查找不到对应的解决方案,可点击新建 Issues 来反馈您的 Bug,我们将尽快与您沟通并及时解决 Bug。 + +![](images/issues_feedback.png) + +## 🔧 使用到的开源仓库 + +开源是推动技术进步和创新的重要力量,我们采用了多个开源仓库来增强功能、提升效率。 + +* [OnnxSlim](https://github.com/inisis/OnnxSlim) +* [OpenCV Mobile](https://github.com/nihui/opencv-mobile) +* [Paddle2ONNX](https://github.com/PaddlePaddle/Paddle2ONNX) +* [PaddleClas](https://github.com/PaddlePaddle/PaddleClas) +* [PaddleDetection](https://github.com/PaddlePaddle/PaddleDetection) +* [PaddleOCR](https://github.com/PaddlePaddle/PaddleOCR) +* [PaddleSeg](https://github.com/PaddlePaddle/PaddleSeg) +* [readerwriterqueue](https://github.com/cameron314/readerwriterqueue) +* [RKNN Toolkit 2](https://github.com/airockchip/rknn-toolkit2) + +## 😊 致谢 + +## 📜 开源协议 + +Lockzhiner Vision Module 全系列仓库遵循 [Apache License Version 2.0](./LICENSE)。 \ No newline at end of file diff --git a/configs/LZ-MobileNetV2_x0_25.yaml b/configs/LZ-MobileNetV2_x0_25.yaml new file mode 100644 index 0000000000000000000000000000000000000000..851af257274d299cefd2c826144af8fe8879273a --- /dev/null +++ b/configs/LZ-MobileNetV2_x0_25.yaml @@ -0,0 +1,25 @@ +config: + mean: + - 0.5 + - 0.5 + - 0.5 + std: + - 0.5 + - 0.5 + - 0.5 + +load_onnx: + inputs: + - x + input_size_list: + - + - 1 + - 3 + - 224 + - 224 + outputs: + - p2o.save_infer_model/scale_0.tmp_0.0 + +build: + do_quantization: false + dataset: \ No newline at end of file diff --git a/configs/LZ-MobileNetV2_x0_5.yaml b/configs/LZ-MobileNetV2_x0_5.yaml new file mode 100644 index 0000000000000000000000000000000000000000..851af257274d299cefd2c826144af8fe8879273a --- /dev/null +++ b/configs/LZ-MobileNetV2_x0_5.yaml @@ -0,0 +1,25 @@ +config: + mean: + - 0.5 + - 0.5 + - 0.5 + std: + - 0.5 + - 0.5 + - 0.5 + +load_onnx: + inputs: + - x + input_size_list: + - + - 1 + - 3 + - 224 + - 224 + outputs: + - p2o.save_infer_model/scale_0.tmp_0.0 + +build: + do_quantization: false + dataset: \ No newline at end of file diff --git a/configs/LZ-MobileNetV2_x1_0.yaml b/configs/LZ-MobileNetV2_x1_0.yaml new file mode 100644 index 0000000000000000000000000000000000000000..851af257274d299cefd2c826144af8fe8879273a --- /dev/null +++ b/configs/LZ-MobileNetV2_x1_0.yaml @@ -0,0 +1,25 @@ +config: + mean: + - 0.5 + - 0.5 + - 0.5 + std: + - 0.5 + - 0.5 + - 0.5 + +load_onnx: + inputs: + - x + input_size_list: + - + - 1 + - 3 + - 224 + - 224 + outputs: + - p2o.save_infer_model/scale_0.tmp_0.0 + +build: + do_quantization: false + dataset: \ No newline at end of file diff --git a/configs/LZ-MobileNetV3_small_x0_35.yaml b/configs/LZ-MobileNetV3_small_x0_35.yaml new file mode 100644 index 0000000000000000000000000000000000000000..851af257274d299cefd2c826144af8fe8879273a --- /dev/null +++ b/configs/LZ-MobileNetV3_small_x0_35.yaml @@ -0,0 +1,25 @@ +config: + mean: + - 0.5 + - 0.5 + - 0.5 + std: + - 0.5 + - 0.5 + - 0.5 + +load_onnx: + inputs: + - x + input_size_list: + - + - 1 + - 3 + - 224 + - 224 + outputs: + - p2o.save_infer_model/scale_0.tmp_0.0 + +build: + do_quantization: false + dataset: \ No newline at end of file diff --git a/configs/LZ-MobileNetV3_small_x0_5.yaml b/configs/LZ-MobileNetV3_small_x0_5.yaml new file mode 100644 index 0000000000000000000000000000000000000000..851af257274d299cefd2c826144af8fe8879273a --- /dev/null +++ b/configs/LZ-MobileNetV3_small_x0_5.yaml @@ -0,0 +1,25 @@ +config: + mean: + - 0.5 + - 0.5 + - 0.5 + std: + - 0.5 + - 0.5 + - 0.5 + +load_onnx: + inputs: + - x + input_size_list: + - + - 1 + - 3 + - 224 + - 224 + outputs: + - p2o.save_infer_model/scale_0.tmp_0.0 + +build: + do_quantization: false + dataset: \ No newline at end of file diff --git a/configs/LZ-MobileNetV3_small_x0_75.yaml b/configs/LZ-MobileNetV3_small_x0_75.yaml new file mode 100644 index 0000000000000000000000000000000000000000..851af257274d299cefd2c826144af8fe8879273a --- /dev/null +++ b/configs/LZ-MobileNetV3_small_x0_75.yaml @@ -0,0 +1,25 @@ +config: + mean: + - 0.5 + - 0.5 + - 0.5 + std: + - 0.5 + - 0.5 + - 0.5 + +load_onnx: + inputs: + - x + input_size_list: + - + - 1 + - 3 + - 224 + - 224 + outputs: + - p2o.save_infer_model/scale_0.tmp_0.0 + +build: + do_quantization: false + dataset: \ No newline at end of file diff --git a/configs/LZ-MobileNetV3_small_x1_0.yaml b/configs/LZ-MobileNetV3_small_x1_0.yaml new file mode 100644 index 0000000000000000000000000000000000000000..851af257274d299cefd2c826144af8fe8879273a --- /dev/null +++ b/configs/LZ-MobileNetV3_small_x1_0.yaml @@ -0,0 +1,25 @@ +config: + mean: + - 0.5 + - 0.5 + - 0.5 + std: + - 0.5 + - 0.5 + - 0.5 + +load_onnx: + inputs: + - x + input_size_list: + - + - 1 + - 3 + - 224 + - 224 + outputs: + - p2o.save_infer_model/scale_0.tmp_0.0 + +build: + do_quantization: false + dataset: \ No newline at end of file diff --git a/docs/introductory_tutorial/burn_image.md b/docs/introductory_tutorial/burn_image.md new file mode 100644 index 0000000000000000000000000000000000000000..5b6602e55aa7ee36953096c6907bce8765d804c2 --- /dev/null +++ b/docs/introductory_tutorial/burn_image.md @@ -0,0 +1,73 @@ +

烧录镜像指南

+ +发布版本:V0.0.1 + +日期:2024-08-30 + +文件密级:□绝密 □秘密 □内部资料 ■公开 + +--- + +**免责声明** + +本文档按**现状**提供,福州凌睿智捷电子有限公司(以下简称**本公司**)不对本文档中的任何陈述、信息和内容的准确性、可靠性、完整性、适销性、适用性及非侵权性提供任何明示或暗示的声明或保证。本文档仅作为使用指导的参考。 + +由于产品版本升级或其他原因,本文档可能在未经任何通知的情况下不定期更新或修改。 + +**读者对象** + +本教程适用于以下工程师: + +- 技术支持工程师 +- 软件开发工程师 + +**修订记录** + +| **日期** | **版本** | **作者** | **修改说明** | +| :--------- | -------- | -------- | ------------ | +| 2024/08/30 | 0.0.0 | 黄展坤 | 初始版本 | +| 2024/08/30 | 0.0.1 | 郑必城 | 优化文档 | + +## 1 简介 + +在本章节中,您将学习到如何使用镜像烧录工具将镜像文件成功烧录到目标设备中。 + +## 2 前期准备 + +在开始烧录前,我们需要做一些前期的准备: + +* 请准备一张 **64G 容量以下**的 SD 卡,这里我们选用的是 16G 的 SD 卡。请将 SD 卡插入读卡器并正确连接电脑。 +* 请正确下载 Lockzhiner Vision Module 的镜像软件包到你喜欢的位置。 + +## 3 开始烧录 + +使用解压工具(这里选用的是 Bandzip)解压 Lockzhiner Vision Module 的镜像压缩包到你喜欢的位置 + +![](images/burn_image/zip.png) + +前往解压的压缩包目录,在 download_tools 目录下,打开 SocToolKit.exe 软件,这是一个镜像烧写工具 + +![](images/burn_image/tools_dir.jpg) + +弹出的界面中选择 RV1106 + +![](images/burn_image/select_toolkit.jpg) + +按照下图顺序,依次点击 **SD卡启动** -> **选择USB磁盘** -> **选择启动文件** + +![](images/burn_image/select_image_0.png) + +弹出的窗口中 **找到 rv1106_img 目录** -> **选择除了 update.img 以外的所有文件** -> **点击打开按钮** + +![](images/burn_image/select_image_1.png) +![](images/burn_image/select_image_2.png) + +> 注意,这里的启动文件**不包括 update.img** + +点击创建 SD 卡 + +![](images/burn_image/create_sd.png) + +## 4 验证是否烧录成功 + +烧录完成后,请将 SD 卡插入 Lockzhiner Vision Module,并参考 [连接设备指南](./connect_device_using_ssh.md) 来连接设备并输出 Hello World \ No newline at end of file diff --git a/docs/introductory_tutorial/connect_device_using_ssh.md b/docs/introductory_tutorial/connect_device_using_ssh.md new file mode 100644 index 0000000000000000000000000000000000000000..3ded352831d9af84f41c89b61b1b12a0f5099938 --- /dev/null +++ b/docs/introductory_tutorial/connect_device_using_ssh.md @@ -0,0 +1,104 @@ +

连接设备指南

+ +发布版本:V0.0.1 + +日期:2024-08-28 + +文件密级:□绝密 □秘密 □内部资料 ■公开 + +--- + +**免责声明** + +本文档按**现状**提供,福州凌睿智捷电子有限公司(以下简称**本公司**)不对本文档中的任何陈述、信息和内容的准确性、可靠性、完整性、适销性、适用性及非侵权性提供任何明示或暗示的声明或保证。本文档仅作为使用指导的参考。 + +由于产品版本升级或其他原因,本文档可能在未经任何通知的情况下不定期更新或修改。 + +**读者对象** + +本教程适用于以下工程师: + +- 技术支持工程师 +- 软件开发工程师 + +**修订记录** + +| **日期** | **版本** | **作者** | **修改说明** | +| :--------- | -------- | -------- | ------------ | +| 2024/08/01 | 0.0.0 | 杨宁 | 初始版本 | +| 2024/08/28 | 0.0.1 | 郑必城 | 修复文档错误 | + +## 1 简介 + +SSH 是一种用于在不安全网络上安全地访问和传输数据的协议,Lockzhiner Vision Module 使用 SSH 来让用户和设备进行通信。在本章节中,你将学会如何使用 SSH 连接设备并在屏幕上输出 Hello World。 + +## 2 下载并安装 electerm (可选) + +[electerm](https://github.com/electerm/electerm) 是一款跨平台的 (linux, mac, win) 开源终端客户端,支持 ssh/sftp 等多种通信方式。我们默认使用 electerm 进行 SSH 和 FTP 通信,当然你也可以自由的选择其他的客户端来完成通信。 + +前往 [electerm sourceforge](https://sourceforge.net/projects/electerm.mirror/files/) 并点击 **Download Latest Version** 按钮来下载 electerm。 + +![](images/connect_device_using_ssh/electerm_sourceforge.png) + +打开你下载的软件,一直点击下一步即可完成安装。 + +![](images/connect_device_using_ssh/electerm_install.png) + +## 3 设置本机 IP 地址 + +要想使用 SSH 就必须保证本机和虚拟网口处在同一个 IP 下。请将设备连接上电脑并按照你的操作系统,按顺序执行以下步骤: + +### 3.1 Win11 设置本机 IP 地址 + +键盘按下 **Win + Q** 呼出搜索框 -> 输入并点击设置 + +![](images/connect_device_using_ssh/open_setting.png) + +点击 **网络和 Internet** -> 点击 **以太网** + +![](images/connect_device_using_ssh/setting_internet.png) + +点击 **编辑** 并配置 IP 地址。这里将 IPV4 地址设置为 **10.1.1.155**,子网掩码设置为 **255.0.0.0**。 + +![](images/connect_device_using_ssh/click_internet_edit.png) +![](images/connect_device_using_ssh/set_internet.png) + +填完完成后点击 **保存**,你的界面应该如下图所示: + +![](images/connect_device_using_ssh/true_internet_config.png) + +### 3.2 Win10 设置本机 IP 地址 + +待补充 + +## 4 使用 SSH 连接设备 + +为了方便大家使用,Lockzhiner Vision Module 在开机时默认启动 SSH 服务器并虚拟化一个网口。Lockzhiner Vision Module 的 SSH 详细信息如下: + +``` +登录账号:root +登录密码:lzdz +静态IP地址:10.1.1.144 +``` + +打开 electerm 或者你本地的 SSH 编辑器,打开网络配置,将 IP、用户名、密码分别进行以下配置 + +![](images/connect_device_using_ssh/ssh_config.png) + +点击保存并连接来连接到设备 + +![](images/connect_device_using_ssh/connect_to_device.png) + +屏幕上将出现以下界面 + +![](images/connect_device_using_ssh/ssh_success.png) + +## 5 在屏幕上打印 Hello World + +我们使用 Linux 命令行,输入以下命令在屏幕上打印 Hello World + +```bash +echo "Hello World" +``` + +![](images/connect_device_using_ssh/ssh_hello_world.png) \ No newline at end of file diff --git a/docs/introductory_tutorial/cpp_development_environment.md b/docs/introductory_tutorial/cpp_development_environment.md new file mode 100644 index 0000000000000000000000000000000000000000..5a93ae30c2497c65dbf23f1a7204de35966deee4 --- /dev/null +++ b/docs/introductory_tutorial/cpp_development_environment.md @@ -0,0 +1,262 @@ +

C++ 开发环境搭建指南

+ +发布版本:V0.0.2 + +日期:2024-09-11 + +文件密级:□绝密 □秘密 □内部资料 ■公开 + +--- + +**免责声明** + +本文档按**现状**提供,福州凌睿智捷电子有限公司(以下简称**本公司**)不对本文档中的任何陈述、信息和内容的准确性、可靠性、完整性、适销性、适用性及非侵权性提供任何明示或暗示的声明或保证。本文档仅作为使用指导的参考。 + +由于产品版本升级或其他原因,本文档可能在未经任何通知的情况下不定期更新或修改。 + +**读者对象** + +本教程适用于以下工程师: + +- 技术支持工程师 +- 软件开发工程师 + +**修订记录** + +| **日期** | **版本** | **作者** | **修改说明** | +| :--------- | -------- | -------- | ------------ | +| 2024/08/29 | 0.0.0 | 郑必城 | 初始版本 | +| 2024/09/07 | 0.0.1 | 郑必城 | 统一配置开发环境 | +| 2024/09/11 | 0.0.2 | 郑必城 | 优化文档 | + +## 1 简介 + +Lockzhiner Vision Module 的 C++ 开发依赖 Ubuntu 系统,但是大多数用户仍然希望能在 Windows 系统上进行开发,因此我们特地推出了在 Windows 上使用 Docker 来进行开发的方法。在进行开发之前,我们需要创建 Docker 容器并安装开发必备的软件,主要分为以下几步进行: + +* 安装 Docker Destop +* 读取镜像并创建和配置容器 +* 安装交叉编译工具链 + +## 2 安装 Docker Destop + +前往 [Docker 官网](https://www.docker.com/)下载 Docker Destop 安装包 + +![](images/development_environment/download_docker_by_web.png) + +打开安装包,按照以下顺序进行安装并重启电脑 + +![](images/development_environment/config_docker.png) + +![](images/development_environment/Snipaste_2024-08-29_09-55-48.png) + +重启电脑后,打开 Docker Destop,按顺序点击以下按钮 + +![](images/development_environment/Snipaste_2024-08-29_09-57-28.png) + +![](images/development_environment/Snipaste_2024-08-29_09-57-47.png) + +![](images/development_environment/Snipaste_2024-08-29_09-58-08.png) + +![](images/development_environment/Snipaste_2024-08-29_09-58-31.png) + +![](images/development_environment/Snipaste_2024-08-29_09-59-40.png) + +安装完成后将会自动打开 Docker Destop,如下图 + +![](images/development_environment/docker_destop.png) + +## 3 创建 Lockzhiner Vision Module 工作目录 + +打开磁盘,选择合适的位置准备创建 Lockzhiner Vision Module 工作目录。注意,工作目录存放的绝对路径请不要包含任何中文字符。 + +接下来**右键鼠标** -> **新建** -> **文件夹**,文件夹名字取名为 **LockzhinerVisionModuleWorkSpace** + +![](images/development_environment/new_dir.png) + +进入新建的文件夹,先点击地址栏检查地址是否包含中文路径。 + +![](images/development_environment/dir_url.png) + +## 4 使用 Docker 加载镜像 + +接下来使用 **Shift + 鼠标右键** -> **在此处打开 PowerShell 窗口** + +![](images/development_environment/click_powershell.png) + +在 PowerShell 中输入以下命令来下载并安装 ubuntu-22.04 镜像: + +```bash +wget https://gitee.com/LockzhinerAI/LockzhinerVisionModule/releases/download/v0.0.0/ubuntu-22.04.tar -Outfile ubuntu-22.04.tar +docker load -i ubuntu-22.04.tar +``` + +![](images/development_environment/docker_load.png) + +> 注意: +> +> 如果执行 **docker load** 时报错 **The system cannot find the file specified.** 请检查 Docker Destop 是否已经正常开启。 + +## 5 使用 Docker 创建并配置容器 + +在 PowerShell 中继续输入以下命令来创建并进入 Docker 容器,挂载容器时会将当前的工作目录映射到容器的 **/LockzhinerVisionModuleWorkSpace** 目录下 + +```bash +docker run -it --name LockzhinerVisionModule -v ${PWD}:/LockzhinerVisionModuleWorkSpace ubuntu:jammy /bin/bash +``` + +![](images/development_environment/docker_container.png) + +执行以下命令来更新 Apt 源 + +```bash +# 配置中科大软件源 +sed -i 's@//.*archive.ubuntu.com@//mirrors.ustc.edu.cn@g' /etc/apt/sources.list +# 更新 Apt 源 +apt update +``` + +![](images/development_environment/apt_update.png) + +执行以下命令来下载并安装命令行补全工具 + +```bash +# 安装 bash-completion +apt-get install -y bash-completion + +# 运行这行命令后输入 no,并按回车 +dpkg-reconfigure dash + +# 运行 bash_completion +cd /usr/share/bash-completion +chmod +x bash_completion +./bash_completion +``` + +![](images/development_environment/install_bash-completion.png) + +![](images/development_environment/dpkg-reconfigure.png) + +![](images/development_environment/bash_completion.png) + +执行以下命令来退出容器 + +```bash +exit +``` + +![](images/development_environment/exit.png) + +## 6 配置项目编译环境 + +安装完 Docker 环境后,我们需要在容器中配置项目的编译环境。每一次在 Pwoershell 中使用命令来打开容器比较麻烦,这里我们使用 Docker Destop 来打开容器: + +* 打开 **Docker Destop** +* 点击 **Containers** +* 点击运行按钮 +* 点击 **LockzhinerVisionModule** 容器 +* 点击 Exec 按钮进入命令行界面 + +![](images/development_environment/docker_run_container.png) + +![](images/development_environment/docker_exec.png) + +### 6.1 下载必备软件包 + +在 Docker 容器中输入以下命令来安装交叉编译工具所需的依赖工具包 + +```bash +apt install -y cmake git wget unzip +``` + +![](images/development_environment/install_cmake_git.png) + +### 6.2 下载交叉编译工具链 + +为了将 C++ 代码编译为在 Lockzhiner Vision Module 上运行的程序,我们需要在 Docker 容器中下载并安装交叉编译工具。 + +执行以下代码,进入 Lockzhiner Vision Module 工作目录并下载交叉编译工具 + +```bash +cd /LockzhinerVisionModuleWorkSpace/ +git clone https://gitee.com/LockzhinerAI/arm-rockchip830-linux-uclibcgnueabihf.git +``` + +![](images/development_environment/cd_work_dir.png) + +![](images/development_environment/install_arm-rockchip830-linux-uclibcgnueabihf.png) + +### 6.3 下载/更新 LockzhinerVisionModule 仓库 + +如果是首次配置环境,执行以下命令 + +```bash +cd /LockzhinerVisionModuleWorkSpace +git clone https://gitee.com/LockzhinerAI/LockzhinerVisionModule.git +cd LockzhinerVisionModule +mkdir -p third_party +``` + +如果是为了更新 LockzhinerVisionModule 仓库,执行以下命令 + +```bash +cd /LockzhinerVisionModuleWorkSpace/LockzhinerVisionModule +git pull +``` + +### 6.4 下载/更新 OpenCV Mobile 库 + +执行以下命令来安装最新的 OpenCV Mobile 库(会删除旧版本) + +```bash +cd /LockzhinerVisionModuleWorkSpace/LockzhinerVisionModule +rm -rf opencv-mobile-4.10.0-lockzhiner-vision-module.zip +wget https://gitee.com/LockzhinerAI/opencv-mobile/releases/download/v0.0.0/opencv-mobile-4.10.0-lockzhiner-vision-module.zip +unzip -qo opencv-mobile-4.10.0-lockzhiner-vision-module.zip -d third_party +``` + +### 6.5 下载/更新 LockzhinerVisionModule SDK + +执行以下命令来安装最新的 LockzhinerVisionModule SDK(会删除旧版本) + +```bash +cd /LockzhinerVisionModuleWorkSpace/LockzhinerVisionModule +rm -rf lockzhiner_vision_module_sdk.zip +wget https://gitee.com/LockzhinerAI/LockzhinerVisionModule/releases/download/v0.0.0/lockzhiner_vision_module_sdk.zip +unzip -qo lockzhiner_vision_module_sdk.zip -d third_party +``` + +参考[连接设备指南](./connect_device_using_ssh.md)打开 Electerm 并连接设备,点击 **Sftp** 按钮。 + +![](images/development_environment/update_lockzhiner_vision_module_0.png) + +使用任务管理器打开 **LockzhinerVisionModuleWorkSpace** 文件夹,按以下顺序操作来找到 SDK 存放目录: + +* 打开 LockzhinerVisionModule +* 打开 third_party + +![](images/development_environment/update_lockzhiner_vision_module_1.png) + +点击地址栏并复制地址,如下图 + +![](images/development_environment/update_lockzhiner_vision_module_2.png) + +回到 Electerm 将复制的地址粘贴到地址栏中并跳转到该目录,如下图: + +![](images/development_environment/update_lockzhiner_vision_module_3.png) + +选中 SDK ,单击鼠标右键并点击 **上传** 将 SDK 传输到 Lockzhiner Vision Module + +![](images/development_environment/update_lockzhiner_vision_module_4.png) + +点击 **Ssh** 回到 Lockzhiner Vision Module 命令行执行界面,运行以下命令拷贝动态库到系统中: + +```bash +cd lockzhiner_vision_module_sdk +bash install-sh.sh +``` + +![](images/development_environment/update_lockzhiner_vision_module_5.png) + +## 7 验证开发环境 + +请参考 [编写第一个 Hello World 程序](../../example/hello_world/README.md) 来验证开发环境是否能够正常使用 \ No newline at end of file diff --git a/docs/introductory_tutorial/images/burn_image/create_sd.png b/docs/introductory_tutorial/images/burn_image/create_sd.png new file mode 100644 index 0000000000000000000000000000000000000000..8a5c6aafb89b09e2f9a536379944b8a65a5a31cf Binary files /dev/null and b/docs/introductory_tutorial/images/burn_image/create_sd.png differ diff --git a/docs/introductory_tutorial/images/burn_image/select_image_0.png b/docs/introductory_tutorial/images/burn_image/select_image_0.png new file mode 100644 index 0000000000000000000000000000000000000000..0352978e450d041e3188c15877e82689091b0e15 Binary files /dev/null and b/docs/introductory_tutorial/images/burn_image/select_image_0.png differ diff --git a/docs/introductory_tutorial/images/burn_image/select_image_1.png b/docs/introductory_tutorial/images/burn_image/select_image_1.png new file mode 100644 index 0000000000000000000000000000000000000000..a557aabe806aa8c82fee900f064ae48ecd95ec6d Binary files /dev/null and b/docs/introductory_tutorial/images/burn_image/select_image_1.png differ diff --git a/docs/introductory_tutorial/images/burn_image/select_image_2.png b/docs/introductory_tutorial/images/burn_image/select_image_2.png new file mode 100644 index 0000000000000000000000000000000000000000..32c42911e42cf5f8ca6b1b94a956c06b02971fac Binary files /dev/null and b/docs/introductory_tutorial/images/burn_image/select_image_2.png differ diff --git a/docs/introductory_tutorial/images/burn_image/select_toolkit.jpg b/docs/introductory_tutorial/images/burn_image/select_toolkit.jpg new file mode 100644 index 0000000000000000000000000000000000000000..78de0e435cd940996cb32e92faeee1d9bec5613f Binary files /dev/null and b/docs/introductory_tutorial/images/burn_image/select_toolkit.jpg differ diff --git a/docs/introductory_tutorial/images/burn_image/tools_dir.jpg b/docs/introductory_tutorial/images/burn_image/tools_dir.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ac85867735fe2cab1dc9abb7d50d7ee392f149dd Binary files /dev/null and b/docs/introductory_tutorial/images/burn_image/tools_dir.jpg differ diff --git a/docs/introductory_tutorial/images/burn_image/zip.png b/docs/introductory_tutorial/images/burn_image/zip.png new file mode 100644 index 0000000000000000000000000000000000000000..6a820c054d35a1b0bb593bfaa75f436ffafd60f0 Binary files /dev/null and b/docs/introductory_tutorial/images/burn_image/zip.png differ diff --git a/docs/introductory_tutorial/images/connect_device_using_ssh/click_internet_edit.png b/docs/introductory_tutorial/images/connect_device_using_ssh/click_internet_edit.png new file mode 100644 index 0000000000000000000000000000000000000000..cc195ef80e145ae49f257044d6fe5234c25b87e0 Binary files /dev/null and b/docs/introductory_tutorial/images/connect_device_using_ssh/click_internet_edit.png differ diff --git a/docs/introductory_tutorial/images/connect_device_using_ssh/connect_to_device.png b/docs/introductory_tutorial/images/connect_device_using_ssh/connect_to_device.png new file mode 100644 index 0000000000000000000000000000000000000000..70cd21408717cf813187dbc53a56edb37ad410d5 Binary files /dev/null and b/docs/introductory_tutorial/images/connect_device_using_ssh/connect_to_device.png differ diff --git a/docs/introductory_tutorial/images/connect_device_using_ssh/electerm_install.png b/docs/introductory_tutorial/images/connect_device_using_ssh/electerm_install.png new file mode 100644 index 0000000000000000000000000000000000000000..82fea6f776c6ad9303671fece9678b715110258d Binary files /dev/null and b/docs/introductory_tutorial/images/connect_device_using_ssh/electerm_install.png differ diff --git a/docs/introductory_tutorial/images/connect_device_using_ssh/electerm_sourceforge.png b/docs/introductory_tutorial/images/connect_device_using_ssh/electerm_sourceforge.png new file mode 100644 index 0000000000000000000000000000000000000000..6bb5f8043d577584f51221a965e74cc42dbcb237 Binary files /dev/null and b/docs/introductory_tutorial/images/connect_device_using_ssh/electerm_sourceforge.png differ diff --git a/docs/introductory_tutorial/images/connect_device_using_ssh/open_setting.png b/docs/introductory_tutorial/images/connect_device_using_ssh/open_setting.png new file mode 100644 index 0000000000000000000000000000000000000000..d97e3b94e94c6fb49f0d763489276028e3fdec05 Binary files /dev/null and b/docs/introductory_tutorial/images/connect_device_using_ssh/open_setting.png differ diff --git a/docs/introductory_tutorial/images/connect_device_using_ssh/set_internet.png b/docs/introductory_tutorial/images/connect_device_using_ssh/set_internet.png new file mode 100644 index 0000000000000000000000000000000000000000..78f9363924d03bf7c145729ae4fc7f619652471a Binary files /dev/null and b/docs/introductory_tutorial/images/connect_device_using_ssh/set_internet.png differ diff --git a/docs/introductory_tutorial/images/connect_device_using_ssh/setting_internet.png b/docs/introductory_tutorial/images/connect_device_using_ssh/setting_internet.png new file mode 100644 index 0000000000000000000000000000000000000000..8cff08253efd7728ee2de7c6dae4b05907930682 Binary files /dev/null and b/docs/introductory_tutorial/images/connect_device_using_ssh/setting_internet.png differ diff --git a/docs/introductory_tutorial/images/connect_device_using_ssh/ssh_config.png b/docs/introductory_tutorial/images/connect_device_using_ssh/ssh_config.png new file mode 100644 index 0000000000000000000000000000000000000000..40db4ce51d4f53d08c6129163ec576324679fce7 Binary files /dev/null and b/docs/introductory_tutorial/images/connect_device_using_ssh/ssh_config.png differ diff --git a/docs/introductory_tutorial/images/connect_device_using_ssh/ssh_hello_world.png b/docs/introductory_tutorial/images/connect_device_using_ssh/ssh_hello_world.png new file mode 100644 index 0000000000000000000000000000000000000000..e48236231c2587a923cca5791dc6661802798692 Binary files /dev/null and b/docs/introductory_tutorial/images/connect_device_using_ssh/ssh_hello_world.png differ diff --git a/docs/introductory_tutorial/images/connect_device_using_ssh/ssh_success.png b/docs/introductory_tutorial/images/connect_device_using_ssh/ssh_success.png new file mode 100644 index 0000000000000000000000000000000000000000..8d078c272ae36a9b4a7e657557dc5e4781cf2c0e Binary files /dev/null and b/docs/introductory_tutorial/images/connect_device_using_ssh/ssh_success.png differ diff --git a/docs/introductory_tutorial/images/connect_device_using_ssh/true_internet_config.png b/docs/introductory_tutorial/images/connect_device_using_ssh/true_internet_config.png new file mode 100644 index 0000000000000000000000000000000000000000..ae797710874a116a8555a3e4f0def63b681d2835 Binary files /dev/null and b/docs/introductory_tutorial/images/connect_device_using_ssh/true_internet_config.png differ diff --git a/docs/introductory_tutorial/images/development_environment/Snipaste_2024-08-29_09-55-48.png b/docs/introductory_tutorial/images/development_environment/Snipaste_2024-08-29_09-55-48.png new file mode 100644 index 0000000000000000000000000000000000000000..eefeacbfe6b4b531fc08137d8f90f10b607e104b Binary files /dev/null and b/docs/introductory_tutorial/images/development_environment/Snipaste_2024-08-29_09-55-48.png differ diff --git a/docs/introductory_tutorial/images/development_environment/Snipaste_2024-08-29_09-57-28.png b/docs/introductory_tutorial/images/development_environment/Snipaste_2024-08-29_09-57-28.png new file mode 100644 index 0000000000000000000000000000000000000000..3870da258699713f2deac75bdb6fa1a2e0a6cb3a Binary files /dev/null and b/docs/introductory_tutorial/images/development_environment/Snipaste_2024-08-29_09-57-28.png differ diff --git a/docs/introductory_tutorial/images/development_environment/Snipaste_2024-08-29_09-57-47.png b/docs/introductory_tutorial/images/development_environment/Snipaste_2024-08-29_09-57-47.png new file mode 100644 index 0000000000000000000000000000000000000000..9a2b52e4351589aa5bff1ae62a39f6f810e02914 Binary files /dev/null and b/docs/introductory_tutorial/images/development_environment/Snipaste_2024-08-29_09-57-47.png differ diff --git a/docs/introductory_tutorial/images/development_environment/Snipaste_2024-08-29_09-58-08.png b/docs/introductory_tutorial/images/development_environment/Snipaste_2024-08-29_09-58-08.png new file mode 100644 index 0000000000000000000000000000000000000000..1123d612eaadac82eca48300f1cc013900f58e2d Binary files /dev/null and b/docs/introductory_tutorial/images/development_environment/Snipaste_2024-08-29_09-58-08.png differ diff --git a/docs/introductory_tutorial/images/development_environment/Snipaste_2024-08-29_09-58-31.png b/docs/introductory_tutorial/images/development_environment/Snipaste_2024-08-29_09-58-31.png new file mode 100644 index 0000000000000000000000000000000000000000..a706f7b276099f8ca606d5560b51c3224f78e2e4 Binary files /dev/null and b/docs/introductory_tutorial/images/development_environment/Snipaste_2024-08-29_09-58-31.png differ diff --git a/docs/introductory_tutorial/images/development_environment/apt_update.png b/docs/introductory_tutorial/images/development_environment/apt_update.png new file mode 100644 index 0000000000000000000000000000000000000000..438fd3da4b1f2e2fe7c7c5172842fb58eba5a845 Binary files /dev/null and b/docs/introductory_tutorial/images/development_environment/apt_update.png differ diff --git a/docs/introductory_tutorial/images/development_environment/bash_completion.png b/docs/introductory_tutorial/images/development_environment/bash_completion.png new file mode 100644 index 0000000000000000000000000000000000000000..73ae24863ccd621455e381a4a70e41d044caa929 Binary files /dev/null and b/docs/introductory_tutorial/images/development_environment/bash_completion.png differ diff --git a/docs/introductory_tutorial/images/development_environment/cd_work_dir.png b/docs/introductory_tutorial/images/development_environment/cd_work_dir.png new file mode 100644 index 0000000000000000000000000000000000000000..8ee305587ac92b248128cc999b2f8f31093d2120 Binary files /dev/null and b/docs/introductory_tutorial/images/development_environment/cd_work_dir.png differ diff --git a/docs/introductory_tutorial/images/development_environment/click_powershell.png b/docs/introductory_tutorial/images/development_environment/click_powershell.png new file mode 100644 index 0000000000000000000000000000000000000000..f46b31ad6ae742a5dd5d00d1c5f5256995a656df Binary files /dev/null and b/docs/introductory_tutorial/images/development_environment/click_powershell.png differ diff --git a/docs/introductory_tutorial/images/development_environment/config_docker.png b/docs/introductory_tutorial/images/development_environment/config_docker.png new file mode 100644 index 0000000000000000000000000000000000000000..d094874a02b0c66d5b72be32d742dc3f2f3055cf Binary files /dev/null and b/docs/introductory_tutorial/images/development_environment/config_docker.png differ diff --git a/docs/introductory_tutorial/images/development_environment/dir_url.png b/docs/introductory_tutorial/images/development_environment/dir_url.png new file mode 100644 index 0000000000000000000000000000000000000000..600320ce948f8a21c586f46181b3f039b9282e2b Binary files /dev/null and b/docs/introductory_tutorial/images/development_environment/dir_url.png differ diff --git a/docs/introductory_tutorial/images/development_environment/docker_container.png b/docs/introductory_tutorial/images/development_environment/docker_container.png new file mode 100644 index 0000000000000000000000000000000000000000..f60ce9ea19a278895f7d6d2eede6cebe4c4d9459 Binary files /dev/null and b/docs/introductory_tutorial/images/development_environment/docker_container.png differ diff --git a/docs/introductory_tutorial/images/development_environment/docker_destop.png b/docs/introductory_tutorial/images/development_environment/docker_destop.png new file mode 100644 index 0000000000000000000000000000000000000000..97a66c2bf79e131bc5e5a2f386638314235d7ce8 Binary files /dev/null and b/docs/introductory_tutorial/images/development_environment/docker_destop.png differ diff --git a/docs/introductory_tutorial/images/development_environment/docker_exec.png b/docs/introductory_tutorial/images/development_environment/docker_exec.png new file mode 100644 index 0000000000000000000000000000000000000000..79b84fe81b551b590dcdc40ded5eb35d426d4e02 Binary files /dev/null and b/docs/introductory_tutorial/images/development_environment/docker_exec.png differ diff --git a/docs/introductory_tutorial/images/development_environment/docker_load.png b/docs/introductory_tutorial/images/development_environment/docker_load.png new file mode 100644 index 0000000000000000000000000000000000000000..e0b99e5679a25cc6ac04f90897455611b5d58c53 Binary files /dev/null and b/docs/introductory_tutorial/images/development_environment/docker_load.png differ diff --git a/docs/introductory_tutorial/images/development_environment/docker_run_container.png b/docs/introductory_tutorial/images/development_environment/docker_run_container.png new file mode 100644 index 0000000000000000000000000000000000000000..59d0dd0e61968c16025e53b5e43d7dbcb5f15d80 Binary files /dev/null and b/docs/introductory_tutorial/images/development_environment/docker_run_container.png differ diff --git a/docs/introductory_tutorial/images/development_environment/download_docker_by_web.png b/docs/introductory_tutorial/images/development_environment/download_docker_by_web.png new file mode 100644 index 0000000000000000000000000000000000000000..920949f1514a4aa6481adcf51abc433b3d2d2f7b Binary files /dev/null and b/docs/introductory_tutorial/images/development_environment/download_docker_by_web.png differ diff --git a/docs/introductory_tutorial/images/development_environment/dpkg-reconfigure.png b/docs/introductory_tutorial/images/development_environment/dpkg-reconfigure.png new file mode 100644 index 0000000000000000000000000000000000000000..bfbdfce7ea3074f3612edce5c5aac2aaa877a337 Binary files /dev/null and b/docs/introductory_tutorial/images/development_environment/dpkg-reconfigure.png differ diff --git a/docs/introductory_tutorial/images/development_environment/exit.png b/docs/introductory_tutorial/images/development_environment/exit.png new file mode 100644 index 0000000000000000000000000000000000000000..5acb49004a159591fcf9d84b60cb3f8abf5b8dd7 Binary files /dev/null and b/docs/introductory_tutorial/images/development_environment/exit.png differ diff --git a/docs/introductory_tutorial/images/development_environment/install_arm-rockchip830-linux-uclibcgnueabihf.png b/docs/introductory_tutorial/images/development_environment/install_arm-rockchip830-linux-uclibcgnueabihf.png new file mode 100644 index 0000000000000000000000000000000000000000..e47d4ea23e97af01645e7a8b16ce024661f5209e Binary files /dev/null and b/docs/introductory_tutorial/images/development_environment/install_arm-rockchip830-linux-uclibcgnueabihf.png differ diff --git a/docs/introductory_tutorial/images/development_environment/install_bash-completion.png b/docs/introductory_tutorial/images/development_environment/install_bash-completion.png new file mode 100644 index 0000000000000000000000000000000000000000..5c089e021104e9e91dbb0890a61eb416c9383706 Binary files /dev/null and b/docs/introductory_tutorial/images/development_environment/install_bash-completion.png differ diff --git a/docs/introductory_tutorial/images/development_environment/install_cmake_git.png b/docs/introductory_tutorial/images/development_environment/install_cmake_git.png new file mode 100644 index 0000000000000000000000000000000000000000..328ccbeb57b3e251b14c4e97b73e9dcbbbcf91bf Binary files /dev/null and b/docs/introductory_tutorial/images/development_environment/install_cmake_git.png differ diff --git a/docs/introductory_tutorial/images/development_environment/new_dir.png b/docs/introductory_tutorial/images/development_environment/new_dir.png new file mode 100644 index 0000000000000000000000000000000000000000..6435ebdfe5da33358876b87676d9e863f61a07f3 Binary files /dev/null and b/docs/introductory_tutorial/images/development_environment/new_dir.png differ diff --git a/docs/introductory_tutorial/images/development_environment/python_update_lockzhiner_vision_module_0.png b/docs/introductory_tutorial/images/development_environment/python_update_lockzhiner_vision_module_0.png new file mode 100644 index 0000000000000000000000000000000000000000..34d9d7f63cdf435f9546fbba6127d5e3cb79e834 Binary files /dev/null and b/docs/introductory_tutorial/images/development_environment/python_update_lockzhiner_vision_module_0.png differ diff --git a/docs/introductory_tutorial/images/development_environment/python_update_lockzhiner_vision_module_1.png b/docs/introductory_tutorial/images/development_environment/python_update_lockzhiner_vision_module_1.png new file mode 100644 index 0000000000000000000000000000000000000000..6275b65cb28b567452c2c92ea512a6d0236d10a5 Binary files /dev/null and b/docs/introductory_tutorial/images/development_environment/python_update_lockzhiner_vision_module_1.png differ diff --git a/docs/introductory_tutorial/images/development_environment/python_update_lockzhiner_vision_module_2.png b/docs/introductory_tutorial/images/development_environment/python_update_lockzhiner_vision_module_2.png new file mode 100644 index 0000000000000000000000000000000000000000..acbf5780a920bd432804a24ba3e6a6cd5312bf01 Binary files /dev/null and b/docs/introductory_tutorial/images/development_environment/python_update_lockzhiner_vision_module_2.png differ diff --git a/docs/introductory_tutorial/images/development_environment/update_lockzhiner_vision_module_0.png b/docs/introductory_tutorial/images/development_environment/update_lockzhiner_vision_module_0.png new file mode 100644 index 0000000000000000000000000000000000000000..f991d64ed544dcc73a9a7dad70e9555998830b75 Binary files /dev/null and b/docs/introductory_tutorial/images/development_environment/update_lockzhiner_vision_module_0.png differ diff --git a/docs/introductory_tutorial/images/development_environment/update_lockzhiner_vision_module_1.png b/docs/introductory_tutorial/images/development_environment/update_lockzhiner_vision_module_1.png new file mode 100644 index 0000000000000000000000000000000000000000..46c699fd16d601fcf79ff72c2ff6b9d0f38cc26c Binary files /dev/null and b/docs/introductory_tutorial/images/development_environment/update_lockzhiner_vision_module_1.png differ diff --git a/docs/introductory_tutorial/images/development_environment/update_lockzhiner_vision_module_2.png b/docs/introductory_tutorial/images/development_environment/update_lockzhiner_vision_module_2.png new file mode 100644 index 0000000000000000000000000000000000000000..34a5f870523341a15d37c5c18b5528786268bf74 Binary files /dev/null and b/docs/introductory_tutorial/images/development_environment/update_lockzhiner_vision_module_2.png differ diff --git a/docs/introductory_tutorial/images/development_environment/update_lockzhiner_vision_module_3.png b/docs/introductory_tutorial/images/development_environment/update_lockzhiner_vision_module_3.png new file mode 100644 index 0000000000000000000000000000000000000000..8c80d3b892fbf33faa4e07aeb774b691e906c6d3 Binary files /dev/null and b/docs/introductory_tutorial/images/development_environment/update_lockzhiner_vision_module_3.png differ diff --git a/docs/introductory_tutorial/images/development_environment/update_lockzhiner_vision_module_4.png b/docs/introductory_tutorial/images/development_environment/update_lockzhiner_vision_module_4.png new file mode 100644 index 0000000000000000000000000000000000000000..5af10057805f2f079925173866be2439def92750 Binary files /dev/null and b/docs/introductory_tutorial/images/development_environment/update_lockzhiner_vision_module_4.png differ diff --git a/docs/introductory_tutorial/images/development_environment/update_lockzhiner_vision_module_5.png b/docs/introductory_tutorial/images/development_environment/update_lockzhiner_vision_module_5.png new file mode 100644 index 0000000000000000000000000000000000000000..beddc978beb49aec8b7ac868aa1c836bb335707f Binary files /dev/null and b/docs/introductory_tutorial/images/development_environment/update_lockzhiner_vision_module_5.png differ diff --git a/docs/introductory_tutorial/python_development_environment.md b/docs/introductory_tutorial/python_development_environment.md new file mode 100644 index 0000000000000000000000000000000000000000..1399a45b723945daea41728ec641bb49566956b1 --- /dev/null +++ b/docs/introductory_tutorial/python_development_environment.md @@ -0,0 +1,68 @@ +

Python 开发环境搭建指南

+ +发布版本:V0.0.0 + +日期:2024-09-11 + +文件密级:□绝密 □秘密 □内部资料 ■公开 + +--- + +**免责声明** + +本文档按**现状**提供,福州凌睿智捷电子有限公司(以下简称**本公司**)不对本文档中的任何陈述、信息和内容的准确性、可靠性、完整性、适销性、适用性及非侵权性提供任何明示或暗示的声明或保证。本文档仅作为使用指导的参考。 + +由于产品版本升级或其他原因,本文档可能在未经任何通知的情况下不定期更新或修改。 + +**读者对象** + +本教程适用于以下工程师: + +- 技术支持工程师 +- 软件开发工程师 + +**修订记录** + +| **日期** | **版本** | **作者** | **修改说明** | +| :--------- | -------- | -------- | ------------ | +| 2024/09/11 | 0.0.0 | 郑必城 | 初始版本 | + +## 1 简介 + +Lockzhiner Vision Module 的 Python 开发不需要像 C++ 一样的交叉编译操作,因此你只需要将 Lockzhiner Module SDK 正确安装即可。 + +## 2 下载/更新 LockzhinerVisionModule SDK + +点击 [Lockzhiner Vision Module SDK 下载链接](https://gitee.com/LockzhinerAI/LockzhinerVisionModule/releases/download/v0.0.0/lockzhiner_vision_module_sdk.zip) 下载 Lockzhiner Vision Module SDK。解压到本地后,请使用解压软件解压 SDK,一般我们推荐使用 Bandzip。 + +![](images/development_environment/python_update_lockzhiner_vision_module_0.png) + +参考[连接设备指南](./connect_device_using_ssh.md)打开 Electerm 并连接设备,点击 **Sftp** 按钮。 + +![](images/development_environment/update_lockzhiner_vision_module_0.png) + +接下来我们使用文件管理器打开 SDK 解压后存放的文件夹,找到 **lockzhiner_vision_module_sdk** 目录,点击地址栏并复制地址: + +![](images/development_environment/python_update_lockzhiner_vision_module_1.png) + +回到 Electerm 将复制的地址粘贴到地址栏中并跳转到该目录,选中 SDK,单击鼠标右键并点击 **上传** 将 SDK 传输到 Lockzhiner Vision Module + +![](images/development_environment/python_update_lockzhiner_vision_module_2.png) + +点击 **Ssh** 回到 Lockzhiner Vision Module 命令行执行界面,运行以下命令拷贝动态库到系统中: + +```bash +cd lockzhiner_vision_module_sdk +bash install-sh.sh +``` + +![](images/development_environment/update_lockzhiner_vision_module_5.png) + +## 3 验证开发环境 + +使用 Electerm 连接到 Lockzhiner Vision Module,执行以下命令来验证 python 开发环境: + +```bash +python +print("Hello World") +``` \ No newline at end of file diff --git a/example/hello_world/CMakeLists.txt b/example/hello_world/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..d9f014c1575fadcf8f7f27fca09762caf696a420 --- /dev/null +++ b/example/hello_world/CMakeLists.txt @@ -0,0 +1,13 @@ +# CMake最低版本要求 +cmake_minimum_required(VERSION 3.10) + +# 设置项目名称和版本 +project(HelloWorld VERSION 1.0) + +# 指定C++标准 +set(CMAKE_CXX_STANDARD 11) # 设置C++11为标准 +set(CMAKE_CXX_STANDARD_REQUIRED True) # 要求必须支持C++11标准 + +# 添加可执行文件 +# hello.cpp是源文件,HelloWorld是生成的可执行文件名 +add_executable(HelloWorld hello_world.cpp) \ No newline at end of file diff --git a/example/hello_world/README.md b/example/hello_world/README.md new file mode 100644 index 0000000000000000000000000000000000000000..92c665d425fc54f2d4a6e559361b2ed0698dec5c --- /dev/null +++ b/example/hello_world/README.md @@ -0,0 +1,119 @@ +

基于 C++ 编写 Hello World 程序

+ +发布版本:V0.0.0 + +日期:2024-09-11 + +文件密级:□绝密 □秘密 □内部资料 ■公开 + +--- + +**免责声明** + +本文档按**现状**提供,福州凌睿智捷电子有限公司(以下简称**本公司**)不对本文档中的任何陈述、信息和内容的准确性、可靠性、完整性、适销性、适用性及非侵权性提供任何明示或暗示的声明或保证。本文档仅作为使用指导的参考。 + +由于产品版本升级或其他原因,本文档可能在未经任何通知的情况下不定期更新或修改。 + +**读者对象** + +本教程适用于以下工程师: + +- 技术支持工程师 +- 软件开发工程师 + +**修订记录** + +| **日期** | **版本** | **作者** | **修改说明** | +| :--------- | -------- | -------- | ------------ | +| 2024/09/11 | 0.0.0 | 郑必城 | 初始版本 | + +## 1 简介 + +Hello World 是软件工程师的入门第一课,很多人早就把代码倒背如流。和传统的 C++ 开发不同,开发在 Lockzhiner Vision Module 运行的 C++ 程序需要交叉编译。为了让多数没有接触过交叉编译的新手快速上手,我们特地准备了最简单的 Hello World 来让你快速上手。 + +> 注: +> +> 基于 Python 的 Hello World 例程网络上有非常多,如果你使用 Python 进行开发,请跳过这一章节。 + +## 2 前期准备 + +在开始这个章节前,请确保你已经按照 [开发环境搭建指南](../../docs/introductory_tutorial/cpp_development_environment.md) 正确配置了开发环境。 + +## 3 项目介绍 + +我们使用 CMake 构建项目,项目配置文件的内容如下 + +```cmake +# CMake最低版本要求 +cmake_minimum_required(VERSION 3.10) + +# 设置项目名称和版本 +project(HelloWorld VERSION 1.0) + +# 指定C++标准 +set(CMAKE_CXX_STANDARD 11) # 设置C++11为标准 +set(CMAKE_CXX_STANDARD_REQUIRED True) # 要求必须支持C++11标准 + +# 添加可执行文件 +# hello_world.cpp是源文件,HelloWorld是生成的可执行文件名 +add_executable(HelloWorld hello_world.cpp) +``` + +对应的 C++ 文件的内容如下 + +```cpp +#include + +int main() { + std::cout << "Hello, World!" << std::endl; + return 0; +} +``` + +为了让用户能快速配置交叉编译工具链,我们提供了 [arm-rockchip830-linux-uclibcgnueabihf.toolchain.cmake](../../toolchains/arm-rockchip830-linux-uclibcgnueabihf.toolchain.cmake)。你只需要在配置项目时将 **CMAKE_TOOLCHAIN_FILE** 参数指定为该文件路径即可让 cmake 快速检测到已经配置的交叉编译工具。 + +## 4 编译项目 + +使用 Docker Destop 打开 LockzhinerVisionModule 容器并执行以下命令来编译项目 + +```bash +# 进入 Demo 目录 +cd /LockzhinerVisionModuleWorkSpace/LockzhinerVisionModule/example/hello_world + +# 创建编译目录 +rm -rf build && mkdir build && cd build + +# 配置交叉编译工具链 +export TOOLCHAIN_ROOT_PATH=${PWD}/../../../../arm-rockchip830-linux-uclibcgnueabihf + +# 使用 cmake 配置项目 +cmake -DCMAKE_TOOLCHAIN_FILE=../../../toolchains/arm-rockchip830-linux-uclibcgnueabihf.toolchain.cmake \ + -DCMAKE_BUILD_TYPE=Release \ + .. + +# 执行编译 +make -j8 +``` + +![](images/build_example.png) + +## 5 执行 Hello World 程序 + +参考 [连接设备指南](../../docs/introductory_tutorial/connect_device_using_ssh.md) 正确连接 Lockzhiner Vision Module 设备。 + +![](../../docs/introductory_tutorial/images/connect_device_using_ssh/ssh_success.png) + +使用 SFTP 功能将软件上传到 Lockzhiner Vision Module + +![](images/sftp.png) + +在 Lockzhiner Vision Module 上运行以下代码来执行 Hello World 程序 + +```bash +# 给程序添加可执行权限 +chmod +x ./HelloWorld +# 运行程序 +./HelloWorld +``` + +![](images/HelloWorld.png) \ No newline at end of file diff --git a/example/hello_world/hello_world.cpp b/example/hello_world/hello_world.cpp new file mode 100644 index 0000000000000000000000000000000000000000..82db9796d63e9ad8c9b2170e23589fe7c50848f1 --- /dev/null +++ b/example/hello_world/hello_world.cpp @@ -0,0 +1,6 @@ +#include + +int main() { + std::cout << "Hello, World!" << std::endl; + return 0; +} \ No newline at end of file diff --git a/example/hello_world/images/HelloWorld.png b/example/hello_world/images/HelloWorld.png new file mode 100644 index 0000000000000000000000000000000000000000..a1ff0e0e999e8564e890a4148b3d784f078a7160 Binary files /dev/null and b/example/hello_world/images/HelloWorld.png differ diff --git a/example/hello_world/images/build_example.png b/example/hello_world/images/build_example.png new file mode 100644 index 0000000000000000000000000000000000000000..4245ed0ac498c372e1c0bd47d01ea52327c5ba80 Binary files /dev/null and b/example/hello_world/images/build_example.png differ diff --git a/example/hello_world/images/sftp.png b/example/hello_world/images/sftp.png new file mode 100644 index 0000000000000000000000000000000000000000..95b8877e9c45f9fb3b94d788d43043a266e2653b Binary files /dev/null and b/example/hello_world/images/sftp.png differ diff --git a/example/periphery/adc/CMakeLists.txt b/example/periphery/adc/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..e20fae0c956ae5efc1686b9b5a22bc61368eb904 --- /dev/null +++ b/example/periphery/adc/CMakeLists.txt @@ -0,0 +1,16 @@ +# CMake最低版本要求 +cmake_minimum_required(VERSION 3.10) + +project(test_adc) + +# 定义项目根目录路径 +set(PROJECT_ROOT_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../..") +# 定义 LockzhinerVisionModule SDK 路径 +set(LockzhinerVisionModule_ROOT_PATH "${PROJECT_ROOT_PATH}/third_party/lockzhiner_vision_module_sdk") +set(LockzhinerVisionModule_DIR "${LockzhinerVisionModule_ROOT_PATH}/lib/cmake/lockzhiner_vision_module") +find_package(LockzhinerVisionModule REQUIRED) + +# 配置 ADC 读取例程 +add_executable(Test-ADC test_adc.cc) +target_include_directories(Test-ADC PRIVATE ${LOCKZHINER_VISION_MODULE_INCLUDE_DIRS}) +target_link_libraries(Test-ADC PRIVATE ${LOCKZHINER_VISION_MODULE_LIBRARIES}) \ No newline at end of file diff --git a/example/periphery/adc/README.md b/example/periphery/adc/README.md new file mode 100644 index 0000000000000000000000000000000000000000..48b15138adcf319e96d0c061047c4b8027aacef9 --- /dev/null +++ b/example/periphery/adc/README.md @@ -0,0 +1,196 @@ +

ADC 使用指南

+ +发布版本:V0.0.0 + +日期:2024-08-30 + +文件密级:□绝密 □秘密 □内部资料 ■公开 + +--- + +**免责声明** + +本文档按**现状**提供,福州凌睿智捷电子有限公司(以下简称**本公司**)不对本文档中的任何陈述、信息和内容的准确性、可靠性、完整性、适销性、适用性及非侵权性提供任何明示或暗示的声明或保证。本文档仅作为使用指导的参考。 + +由于产品版本升级或其他原因,本文档可能在未经任何通知的情况下不定期更新或修改。 + +**读者对象** + +本教程适用于以下工程师: + +- 技术支持工程师 +- 软件开发工程师 + +**修订记录** + +| **日期** | **版本** | **作者** | **修改说明** | +| :--------- | -------- | -------- | ------------ | +| 2024/08/30 | 0.0.0 | 郑必城 | 初始版本 | + + +## 1 简介 + +作为连接模拟世界与数字世界的桥梁,ADC能够将连续的模拟信号(如温度、压力、声音等)转换为离散的数字信号,使得主控芯片能够处理和分析这些信号。本章节中,我们将教会你如何使用 Lockzhiner Vision Module 读取 ADC 数据。 + +## 2 前期准备 + +在开始这个章节前,请确保你已经按照 [开发环境搭建指南](../../../docs/introductory_tutorial/development_environment.md) 正确配置了开发环境。 + +## 3 API 文档 + +```c++ +/** + * @class ADC + * @brief 这是一个模数转换器(ADC)的抽象类,用于从模拟源读取数据。 + * + * 该类提供基本的ADC操作接口,包括打开ADC设备以及从ADC读取数据。 + * 注意:该ADC不得接入超过1.8V的电压,否则可能会损坏设备。 + */ +class ADC { + public: + /** + * @brief 默认构造函数。 + * + * 初始化ADC类的实例。 + */ + ADC() = default; + + /** + * @brief 默认析构函数。 + * + * 清理ADC类实例使用的资源。 + */ + ~ADC() = default; + + /** + * @brief 打开ADC设备。 + * + * 初始化ADC硬件并准备进行读取操作。 + * @return bool 如果设备成功打开则返回true,否则返回false。 + */ + bool Open(); + + /** + * @brief 从ADC读取数据。 + * + * 从ADC读取当前的模拟值(mV),并将其转换为浮点数形式。 + * 注意:确保ADC未接入超过1.8V的电压。 + * @param[out] adc_data 存储读取到的ADC数据的变量(以浮点数形式)。 + * @return bool 如果成功读取数据则返回true,否则返回false。 + */ + bool Read(float& adc_data); + + private: + float scale_ = 0.0; +}; +``` + +## 4 项目介绍 + +为了方便大家入手,我们做了一个简易的 ADC 例程。该例程可以输出当前的 ADC 数值。 + +```cmake +# CMake最低版本要求 +cmake_minimum_required(VERSION 3.10) + +project(test_adc) + +# 定义项目根目录路径 +set(PROJECT_ROOT_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../..") +# 定义 LockzhinerVisionModule SDK 路径 +set(LockzhinerVisionModule_ROOT_PATH "${PROJECT_ROOT_PATH}/third_party/lockzhiner_vision_module_sdk") +set(LockzhinerVisionModule_DIR "${LockzhinerVisionModule_ROOT_PATH}/lib/cmake/lockzhiner_vision_module") +find_package(LockzhinerVisionModule REQUIRED) + +# 配置 ADC 读取例程 +add_executable(Test-ADC test_adc.cc) +target_include_directories(Test-ADC PRIVATE ${LOCKZHINER_VISION_MODULE_INCLUDE_DIRS}) +target_link_libraries(Test-ADC PRIVATE ${LOCKZHINER_VISION_MODULE_LIBRARIES}) +``` + +读取 ADC 数据的核心代码如下: + +```cpp +#include + +#include + +int main() { + lockzhiner_vision_module::periphery::ADC adc; + if (!adc.Open()) { + std::cout << "Failed to open adc." << std::endl; + return 1; + } + + float adc_data; + if (!adc.Read(adc_data)) { + std::cout << "Failed to read adc data." << std::endl; + return 1; + } + std::cout << "adc_data is " << adc_data << "mv" << std::endl; + return 0; +} +``` + +## 5 编译项目 + +使用 Docker Destop 打开 LockzhinerVisionModule 容器并执行以下命令来编译项目 + +```bash +# 进入 Demo 目录 +cd /LockzhinerVisionModuleWorkSpace/LockzhinerVisionModule/example/periphery/adc + +# 创建编译目录 +rm -rf build && mkdir build && cd build + +# 配置交叉编译工具链 +export TOOLCHAIN_ROOT_PATH=${PWD}/../../../../../arm-rockchip830-linux-uclibcgnueabihf + +# 使用 cmake 配置项目 +cmake -DCMAKE_TOOLCHAIN_FILE=../../../../toolchains/arm-rockchip830-linux-uclibcgnueabihf.toolchain.cmake \ + -DCMAKE_BUILD_TYPE=Release \ + .. + +# 执行编译 +make -j8 +``` + +![](images/build_example.png) + +## 6 正确连接设备 + +> 注意: Lockzhiner Vision Module ADC 引脚最大可承载电压是 1.8V 切忌不要输入超过 1.8V 的电压,否则可能烧板子!!!! + +为了方便调试,我们这里使用 **信号源** 进行调试,请正确的将 Lockzhiner Vision Module 的引脚按照以下方式连接 + +* LockzhinerVisionModule ADC <-> Output IO +* LockzhinerVisionModule GND <-> Output GND + +板子上的引脚丝印较小,如果看不清引脚信息,可以参考下图 + +![](../../../images/periphery.png) + +信号源我们配置了 100mV 的电压,如下图所示 + +![](images/100mV.png) + +## 7 执行 ADC 测试程序 + +参考 [连接设备指南](../../../docs/introductory_tutorial/connect_device_using_ssh.md) 正确连接 Lockzhiner Vision Module 设备。 + +![](../../../docs/introductory_tutorial/images/connect_device_using_ssh/ssh_success.png) + +使用 SFTP 功能将软件上传到 Lockzhiner Vision Module + +![](images/sftp.png) + +在 Lockzhiner Vision Module 上运行以下代码来执行 ADC 测试程序 + +```bash +chmod +x ./Test-ADC +./Test-ADC +``` + +![](images/result.png) + +可以看到有一定的误差,误差一般在10mv以内 \ No newline at end of file diff --git a/example/periphery/adc/images/100mV.png b/example/periphery/adc/images/100mV.png new file mode 100644 index 0000000000000000000000000000000000000000..9f33cf20eb7a9a625af3a77213f94a4d035c3fbd Binary files /dev/null and b/example/periphery/adc/images/100mV.png differ diff --git a/example/periphery/adc/images/build_example.png b/example/periphery/adc/images/build_example.png new file mode 100644 index 0000000000000000000000000000000000000000..7c4a53fcf51fcfeaa8e76b77c11446e5d6749e44 Binary files /dev/null and b/example/periphery/adc/images/build_example.png differ diff --git a/example/periphery/adc/images/result.png b/example/periphery/adc/images/result.png new file mode 100644 index 0000000000000000000000000000000000000000..8087666a022575f09e0de2a9422178105dae8444 Binary files /dev/null and b/example/periphery/adc/images/result.png differ diff --git a/example/periphery/adc/images/sftp.png b/example/periphery/adc/images/sftp.png new file mode 100644 index 0000000000000000000000000000000000000000..4824f3a9b986ecc5b7d03904fe4f9112fe4bc2ce Binary files /dev/null and b/example/periphery/adc/images/sftp.png differ diff --git a/example/periphery/adc/test_adc.cc b/example/periphery/adc/test_adc.cc new file mode 100644 index 0000000000000000000000000000000000000000..733d873193b63b8cfd2f3e0b9bcdfa12251a86ae --- /dev/null +++ b/example/periphery/adc/test_adc.cc @@ -0,0 +1,19 @@ +#include + +#include + +int main() { + lockzhiner_vision_module::periphery::ADC adc; + if (!adc.Open()) { + std::cout << "Failed to open adc." << std::endl; + return 1; + } + + float adc_data; + if (!adc.Read(adc_data)) { + std::cout << "Failed to read adc data." << std::endl; + return 1; + } + std::cout << "adc_data is " << adc_data << "mV" << std::endl; + return 0; +} \ No newline at end of file diff --git a/example/periphery/capture/CMakeLists.txt b/example/periphery/capture/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..dac76fb6517b9b61e932880865b7a6a1c4b1ecd3 --- /dev/null +++ b/example/periphery/capture/CMakeLists.txt @@ -0,0 +1,21 @@ +# CMake最低版本要求 +cmake_minimum_required(VERSION 3.10) + +project(test_adc) + +# 定义项目根目录路径 +set(PROJECT_ROOT_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../..") +# 定义 OpenCV SDK 路径 +set(OpenCV_ROOT_PATH "${PROJECT_ROOT_PATH}/third_party/opencv-mobile-4.10.0-lockzhiner-vision-module") +set(OpenCV_DIR "${OpenCV_ROOT_PATH}/lib/cmake/opencv4") +find_package(OpenCV REQUIRED) +set(OPENCV_LIBRARIES "${OpenCV_LIBS}") +# 定义 LockzhinerVisionModule SDK 路径 +set(LockzhinerVisionModule_ROOT_PATH "${PROJECT_ROOT_PATH}/third_party/lockzhiner_vision_module_sdk") +set(LockzhinerVisionModule_DIR "${LockzhinerVisionModule_ROOT_PATH}/lib/cmake/lockzhiner_vision_module") +find_package(LockzhinerVisionModule REQUIRED) + +# 配置摄像头数据 +add_executable(Test-Capture test_capture.cc) +target_include_directories(Test-Capture PRIVATE ${LOCKZHINER_VISION_MODULE_INCLUDE_DIRS}) +target_link_libraries(Test-Capture PRIVATE ${OPENCV_LIBRARIES} ${LOCKZHINER_VISION_MODULE_LIBRARIES}) \ No newline at end of file diff --git a/example/periphery/capture/README.md b/example/periphery/capture/README.md new file mode 100644 index 0000000000000000000000000000000000000000..f8a5a5f2997785ddfabed41a06fa057c6a49a0a6 --- /dev/null +++ b/example/periphery/capture/README.md @@ -0,0 +1,257 @@ +

摄像头使用指南

+ +发布版本:V0.0.0 + +日期:2024-09-04 + +文件密级:□绝密 □秘密 □内部资料 ■公开 + +--- + +**免责声明** + +本文档按**现状**提供,福州凌睿智捷电子有限公司(以下简称**本公司**)不对本文档中的任何陈述、信息和内容的准确性、可靠性、完整性、适销性、适用性及非侵权性提供任何明示或暗示的声明或保证。本文档仅作为使用指导的参考。 + +由于产品版本升级或其他原因,本文档可能在未经任何通知的情况下不定期更新或修改。 + +**读者对象** + +本教程适用于以下工程师: + +- 技术支持工程师 +- 软件开发工程师 + +**修订记录** + +| **日期** | **版本** | **作者** | **修改说明** | +| :--------- | -------- | -------- | ------------ | +| 2024/09/04 | 0.0.0 | 郑必城 | 初始版本 | + +## 1 简介 + +Lockzhiner Vision Module 上自带了一个摄像头,该摄像头可以支持最大 **2304x1296(16:9)** 的分辨率。本章节中,我们将教会你如何使用 Lockzhiner Vision Module 读取 摄像头数据,并使用 Lockzhiner Vision Module 传输图片到本地,方便保存数据。 + +## 2 数据表 + +受限于解码能力,Lockzhiner Vision Module 在不同的分辨率下,摄像头的帧率是不一样的,具体可以参考如下表格: + +### 2.1 长宽比为 4:3 + +| 摄像头分辨率| FPS | +| :----: | :----: | +| 480x360(4:3) | 25 | +| 640x480(4:3) | 25 | +| 960x720(4:3) | 14 | +| 1280x960(4:3) | 13 | +| 1920x1440(4:3) | 13 | + +### 2.2 长宽比为 16:9 + +| 摄像头分辨率| FPS | +| :----: | :----: | +| 480x270(16:9) | 25 | +| 640x360(16:9) | 25 | +| 960x540(16:9) | 25 | +| 1280x720(16:9) | 15 | +| 1920x1080(16:9) | 12 | + +## 3 前期准备 + +在开始这个章节前,请确保: + +- 你已经按照 [开发环境搭建指南](../../../docs/introductory_tutorial/development_environment.md) 正确配置了开发环境。 +- 点击 [Lockzhiner Vision Module 图片获取助手下载地址](https://gitee.com/LockzhinerAI/LockzhinerVisionModule/releases/download/v0.0.0/LockzhinerVisionModuleImageFetcher_v0.0.0.exe) 下载 Lockzhiner Vision Module 图片获取助手。 + +## 4 API 文档 + +关于摄像头读取,请参考传统的 OpenCV 摄像头 API 来实现,需要注意的是: + +- 受限于运行内存,请使用我们编译的 [OpenCV Mobile](https://gitee.com/LockzhinerAI/opencv-mobile) 库来代替传统的 OpenCV 库 +- LockzhinerVisionModule 只有一个摄像头,因此在打开摄像头时,不管输入什么参数,都只会打开这个摄像头 +- 配置摄像头长宽时,请保证长和宽都是 8 的倍数 + +关于 Lockzhiner Vision Module 中的图片获取 API,请参考以下文档: + +```cpp +/** + * @brief Edit 类提供了对摄像头数据的控制接口。 + * + * 需要注意的是, Edit 传输的数据必须使用 Lockzhiner Vision Module 图片获取助手来接收 + */ +class Edit { + public: + Edit() = default; + ~Edit() = default; + + /** + * @brief 接收客户端连接 + * + * 此函数尝试阻塞等待客户端连接。 + * 成功时返回 true,失败时返回 false。 + * + * @return bool 指示操作是否成功。 + */ + bool StartAndAcceptConnection(); + + /** + * @brief 输出图片 + * + * 此函数尝试向客户端传输图片数据 + * 成功时返回 true,失败时返回 false。 + * + * @return bool 指示操作是否成功。 + */ + bool Print(const cv::Mat &mat); + + private: + int server_fd_; + int port_ = 6868; + int new_socket_; + + void BuildPacket(const cv::Mat &mat, uint8_t *buffer, uint64_t size); + bool Write(const void *buf, size_t len); +}; +``` + +## 5 项目介绍 + +为了方便大家入手,我们做了一个简易的图片传输例程。该例程接收 Lockzhiner Vision Module 图片获取助手的连接并向其传输图片数据。 + +```cmake +# CMake最低版本要求 +cmake_minimum_required(VERSION 3.10) + +project(test_adc) + +# 定义项目根目录路径 +set(PROJECT_ROOT_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../..") +# 定义 OpenCV SDK 路径 +set(OpenCV_ROOT_PATH "${PROJECT_ROOT_PATH}/third_party/opencv-mobile-4.10.0-lockzhiner-vision-module") +set(OpenCV_DIR "${OpenCV_ROOT_PATH}/lib/cmake/opencv4") +find_package(OpenCV REQUIRED) +set(OPENCV_LIBRARIES "${OpenCV_LIBS}") +# 定义 LockzhinerVisionModule SDK 路径 +set(LockzhinerVisionModule_ROOT_PATH "${PROJECT_ROOT_PATH}/third_party/lockzhiner_vision_module_sdk") +set(LockzhinerVisionModule_DIR "${LockzhinerVisionModule_ROOT_PATH}/lib/cmake/lockzhiner_vision_module") +find_package(LockzhinerVisionModule REQUIRED) + +# 配置摄像头数据 +add_executable(Test-Capture test_capture.cc) +target_include_directories(Test-Capture PRIVATE ${LOCKZHINER_VISION_MODULE_INCLUDE_DIRS}) +target_link_libraries(Test-Capture PRIVATE ${OPENCV_LIBRARIES} ${LOCKZHINER_VISION_MODULE_LIBRARIES}) +``` + +读取并传输摄像头数据的核心代码如下: + +```cpp +#include + +#include +#include +#include +#include + +int main(int argc, char *argv[]) { + int width = 640; + int height = 480; + if (argc == 3) { + width = atoi(argv[1]); + height = atoi(argv[2]); + } + + lockzhiner_vision_module::edit::Edit edit; + // 打开服务器并阻塞接收客户端连接 + if (!edit.StartAndAcceptConnection()) { + std::cout << "Failed to start and accept connection" << std::endl; + return 1; + } + std::cout << "Succeed to connect device" << std::endl; + + cv::VideoCapture cap; + // 设置摄像头长宽 + cap.set(cv::CAP_PROP_FRAME_WIDTH, width); + cap.set(cv::CAP_PROP_FRAME_HEIGHT, height); + // 打开摄像头 + cap.open(0); + + const int w = cap.get(cv::CAP_PROP_FRAME_WIDTH); + const int h = cap.get(cv::CAP_PROP_FRAME_HEIGHT); + cv::Mat temp_mat; + while (true) { + cap >> temp_mat; + // 判断获取的图片是否为空 + if (temp_mat.empty()) { + continue; + } + // 向客户端输出图片 + if (!edit.Print(temp_mat)) { + std::cout << "Failed to print to edit" << std::endl; + break; + } + } + return 0; +} +``` + +## 6 编译项目 + +使用 Docker Destop 打开 LockzhinerVisionModule 容器并执行以下命令来编译项目 + +```bash +# 进入 Demo 目录 +cd /LockzhinerVisionModuleWorkSpace/LockzhinerVisionModule/example/periphery/capture + +# 创建编译目录 +rm -rf build && mkdir build && cd build + +# 配置交叉编译工具链 +export TOOLCHAIN_ROOT_PATH=${PWD}/../../../../../arm-rockchip830-linux-uclibcgnueabihf + +# 使用 cmake 配置项目 +cmake -DCMAKE_TOOLCHAIN_FILE=../../../../toolchains/arm-rockchip830-linux-uclibcgnueabihf.toolchain.cmake \ + -DCMAKE_BUILD_TYPE=Release \ + .. + +# 执行编译 +make -j8 +``` + +![](images/build_example.png) + +## 7 执行摄像头测试程序 + +参考 [连接设备指南](../../../docs/introductory_tutorial/connect_device_using_ssh.md) 正确连接 Lockzhiner Vision Module 设备。 + +![](../../../docs/introductory_tutorial/images/connect_device_using_ssh/ssh_success.png) + +参考之前的例程,将 **Test-Capture** 传输到 Lockzhiner Vision Module 上 + +![](images/sftp.png) + +传输完成后执行以下代码 + +```bash +chmod +x ./Test-Capture +./Test-Capture +``` + +代码开启后程序将阻塞并等待摄像头连接 + +![](images/result_0.png) + +打开下载的 Lockzhiner Vision Module 图片获取助手,点击连接设备 + +![](images/result_1.png) + +成功连接设备后,将出现摄像头的画面 + +> 提示: +> 如果摄像头的画面不够清晰,请尝试轻轻转动摄像头来调整合适的焦距 + +![](images/result_2.png) + +点击拍照保存可以将图片保存到程序保存路径下的 **LockzhinerVisionModuleImages** 文件夹中 + +![](images/result_3.png) + +你可以点击**打开保存文件夹**按钮来快速打开这个文件夹 diff --git a/example/periphery/capture/images/build_example.png b/example/periphery/capture/images/build_example.png new file mode 100644 index 0000000000000000000000000000000000000000..8ccfeaa6f649b904acb6aa456531c4f0d36e81b3 Binary files /dev/null and b/example/periphery/capture/images/build_example.png differ diff --git a/example/periphery/capture/images/result_0.png b/example/periphery/capture/images/result_0.png new file mode 100644 index 0000000000000000000000000000000000000000..d2dd751e8d2b694b79d337972bc0611a8de288b9 Binary files /dev/null and b/example/periphery/capture/images/result_0.png differ diff --git a/example/periphery/capture/images/result_1.png b/example/periphery/capture/images/result_1.png new file mode 100644 index 0000000000000000000000000000000000000000..9566f2a6e060fcbbc8d17966c9e95c9a34b87460 Binary files /dev/null and b/example/periphery/capture/images/result_1.png differ diff --git a/example/periphery/capture/images/result_2.png b/example/periphery/capture/images/result_2.png new file mode 100644 index 0000000000000000000000000000000000000000..09dabc20e669a8758e19c6cd1fc09523f2b17670 Binary files /dev/null and b/example/periphery/capture/images/result_2.png differ diff --git a/example/periphery/capture/images/result_3.png b/example/periphery/capture/images/result_3.png new file mode 100644 index 0000000000000000000000000000000000000000..61e046f10ef2507be8db1f99d5774d8511a58c8d Binary files /dev/null and b/example/periphery/capture/images/result_3.png differ diff --git a/example/periphery/capture/images/sftp.png b/example/periphery/capture/images/sftp.png new file mode 100644 index 0000000000000000000000000000000000000000..2db3be29fc388d8994334f6a8a955fc4cbdd8c86 Binary files /dev/null and b/example/periphery/capture/images/sftp.png differ diff --git a/example/periphery/capture/test_capture.cc b/example/periphery/capture/test_capture.cc new file mode 100644 index 0000000000000000000000000000000000000000..f9309d00b27979373dd476131874d18e5a0ae144 --- /dev/null +++ b/example/periphery/capture/test_capture.cc @@ -0,0 +1,47 @@ +#include + +#include +#include +#include +#include + +int main(int argc, char *argv[]) { + int width = 640; + int height = 480; + if (argc == 3) { + width = atoi(argv[1]); + height = atoi(argv[2]); + } + + lockzhiner_vision_module::edit::Edit edit; + // 打开服务器并阻塞接收客户端连接 + if (!edit.StartAndAcceptConnection()) { + std::cout << "Failed to start and accept connection" << std::endl; + return 1; + } + std::cout << "Succeed to connect device" << std::endl; + + cv::VideoCapture cap; + // 设置摄像头长宽 + cap.set(cv::CAP_PROP_FRAME_WIDTH, width); + cap.set(cv::CAP_PROP_FRAME_HEIGHT, height); + // 打开摄像头 + cap.open(0); + + const int w = cap.get(cv::CAP_PROP_FRAME_WIDTH); + const int h = cap.get(cv::CAP_PROP_FRAME_HEIGHT); + cv::Mat temp_mat; + while (true) { + cap >> temp_mat; + // 判断获取的图片是否为空 + if (temp_mat.empty()) { + continue; + } + // 向客户端输出图片 + if (!edit.Print(temp_mat)) { + std::cout << "Failed to print to edit" << std::endl; + break; + } + } + return 0; +} \ No newline at end of file diff --git a/example/periphery/gpio/CMakeLists.txt b/example/periphery/gpio/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..e188f69bf11ebf5106f6337120f52ce4f22ca5ee --- /dev/null +++ b/example/periphery/gpio/CMakeLists.txt @@ -0,0 +1,21 @@ +# CMake最低版本要求 +cmake_minimum_required(VERSION 3.10) + +project(test_gpio) + +# 定义项目根目录路径 +set(PROJECT_ROOT_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../..") +# 定义 LockzhinerVisionModule SDK 路径 +set(LockzhinerVisionModule_ROOT_PATH "${PROJECT_ROOT_PATH}/third_party/lockzhiner_vision_module_sdk") +set(LockzhinerVisionModule_DIR "${LockzhinerVisionModule_ROOT_PATH}/lib/cmake/lockzhiner_vision_module") +find_package(LockzhinerVisionModule REQUIRED) + +# 配置 GPIO 输出 Demo +add_executable(Test-GPIO-Write test_gpio_write.cc) +target_include_directories(Test-GPIO-Write PRIVATE ${LOCKZHINER_VISION_MODULE_INCLUDE_DIRS}) +target_link_libraries(Test-GPIO-Write PRIVATE ${LOCKZHINER_VISION_MODULE_LIBRARIES}) + +# 配置 GPIO 读取 Demo +add_executable(Test-GPIO-Read test_gpio_read.cc) +target_include_directories(Test-GPIO-Read PRIVATE ${LOCKZHINER_VISION_MODULE_INCLUDE_DIRS}) +target_link_libraries(Test-GPIO-Read PRIVATE ${LOCKZHINER_VISION_MODULE_LIBRARIES}) \ No newline at end of file diff --git a/example/periphery/gpio/README.md b/example/periphery/gpio/README.md new file mode 100644 index 0000000000000000000000000000000000000000..3d7b28765de3adbe9c9f25033faf49519a8d9419 --- /dev/null +++ b/example/periphery/gpio/README.md @@ -0,0 +1,297 @@ +

GPIO 使用指南

+ +发布版本:V0.0.0 + +日期:2024-09-03 + +文件密级:□绝密 □秘密 □内部资料 ■公开 + +--- + +**免责声明** + +本文档按**现状**提供,福州凌睿智捷电子有限公司(以下简称**本公司**)不对本文档中的任何陈述、信息和内容的准确性、可靠性、完整性、适销性、适用性及非侵权性提供任何明示或暗示的声明或保证。本文档仅作为使用指导的参考。 + +由于产品版本升级或其他原因,本文档可能在未经任何通知的情况下不定期更新或修改。 + +**读者对象** + +本教程适用于以下工程师: + +- 技术支持工程师 +- 软件开发工程师 + +**修订记录** + +| **日期** | **版本** | **作者** | **修改说明** | +| :--------- | -------- | -------- | ------------ | +| 2024/09/03 | 0.0.0 | 郑必城 | 初始版本 | + + +## 1 简介 + +GPIO(General Purpose Input/Output,通用输入/输出)是一种在嵌入式系统和微控制器上常用的接口,用于实现基本的输入输出操作。这些引脚可以被配置为输入模式,用于读取外部信号(如按钮按下、传感器数据等),或者配置为输出模式,用于控制外部设备(如LED灯、电机等)。本章节中,我们将教会你如何使用 Lockzhiner Vision Module 上的 GPIO 输出和读取电平。 + +## 2 前期准备 + +在开始这个章节前,请确保你已经按照 [开发环境搭建指南](../../../docs/introductory_tutorial/development_environment.md) 正确配置了开发环境。 + +## 3 API 文档 + +```c++ +/// @enum GPIOMode +/// @brief GPIO引脚的工作模式枚举。 +enum class GPIOMode { + /// @brief 输入模式。 + IN, + /// @brief 输出模式。 + OUT, +}; + +/// @enum GPIOState +/// @brief GPIO引脚的状态枚举。 +enum class GPIOState { + /// @brief 高电平状态。 + HIGH = 1, + /// @brief 低电平状态。 + LOW = 0, +}; + +/// @template GPIO_Base +/// @brief GPIO基类模板,用于表示和操作GPIO引脚。 +/// @param bank GPIO引脚所属的银行(或组)。 +/// @param port_char GPIO引脚所在的端口字符('A' - 'Z')。 +/// @param pin GPIO引脚号。 +template +class GPIO_Base { + public: + GPIO_Base(); + ~GPIO_Base(); + + /// @brief 配置GPIO引脚的工作模式。 + /// @param mode 要设置的工作模式(输入或输出)。 + /// @return 配置是否成功。 + bool Config(GPIOMode mode); + + /// @brief 写入GPIO引脚的状态。 + /// @param state 要写入的状态(高电平或低电平)。 + /// @return 写入是否成功。 + bool Write(GPIOState state); + + /// @brief 读取GPIO引脚的状态。 + /// @param[out] state 读取到的状态(高电平或低电平)。 + /// @return 读取是否成功。 + bool Read(GPIOState& state); + + private: + // clang-format off + inline constexpr static uint32_t gpio_index_ = (32 * bank + 8 * (port_char - 'A') + pin); + inline const static std::string direction_file_path_ = fmt::format("/sys/class/gpio/gpio{}/direction", gpio_index_); + inline const static std::string value_file_path_ = fmt::format("/sys/class/gpio/gpio{}/value", gpio_index_); + // clang-format on +}; + +/******************** GPIO_0XX ********************/ +template +using GPIO_0_Base = GPIO_Base<0, port_char, pin>; +template +using GPIO_0A_Base = GPIO_0_Base<'A', pin>; +using GPIO_0A0 = GPIO_0A_Base<0>; +/******************** GPIO_0XX ********************/ + +/******************** GPIO_1XX ********************/ +template +using GPIO_1_Base = GPIO_Base<1, port_char, pin>; +template +using GPIO_1C_Base = GPIO_0_Base<'C', pin>; +using GPIO_1C7 = GPIO_1C_Base<7>; +/******************** GPIO_1XX ********************/ +``` + +## 3 项目介绍 + +为了方便大家入手,我们将项目拆分为 GPIO 输出电平和 GPIO 输入电平两个部分,他们共用一个 CMake 文件。 + +```cmake +# CMake最低版本要求 +cmake_minimum_required(VERSION 3.10) + +project(test_gpio) + +# 定义项目根目录路径 +set(PROJECT_ROOT_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../..") +# 定义 LockzhinerVisionModule SDK 路径 +set(LockzhinerVisionModule_ROOT_PATH "${PROJECT_ROOT_PATH}/third_party/lockzhiner_vision_module_sdk") +set(LockzhinerVisionModule_DIR "${LockzhinerVisionModule_ROOT_PATH}/lib/cmake/lockzhiner_vision_module") +find_package(LockzhinerVisionModule REQUIRED) + +# 配置 GPIO 输出 Demo +add_executable(Test-GPIO-Write test_gpio_write.cc) +target_include_directories(Test-GPIO-Write PRIVATE ${LOCKZHINER_VISION_MODULE_INCLUDE_DIRS}) +target_link_libraries(Test-GPIO-Write PRIVATE ${LOCKZHINER_VISION_MODULE_LIBRARIES}) + +# 配置 GPIO 读取 Demo +add_executable(Test-GPIO-Read test_gpio_read.cc) +target_include_directories(Test-GPIO-Read PRIVATE ${LOCKZHINER_VISION_MODULE_INCLUDE_DIRS}) +target_link_libraries(Test-GPIO-Read PRIVATE ${LOCKZHINER_VISION_MODULE_LIBRARIES}) +``` + +GPIO 输入电平的核心代码如下: + +```cpp +#include + +#include +#include + +int main() { + lockzhiner_vision_module::periphery::GPIO_0A0 gpio_0A0; + + if (!gpio_0A0.Config(lockzhiner_vision_module::periphery::GPIOMode::IN)) { + std::cout << "Failed to config gpio mode" << std::endl; + return 1; + } + + lockzhiner_vision_module::periphery::GPIOState state; + if (!gpio_0A0.Read(state)) { + std::cout << "Failed to read gpio mode" << std::endl; + return 1; + } + + std::cout << "state is " << static_cast(state) << std::endl; + return 0; +} +``` + +GPIO 输出电平的核心代码如下: + +```cpp +#include + +#include +#include + +int main() { + lockzhiner_vision_module::periphery::GPIO_0A0 gpio_0A0; + + if (!gpio_0A0.Config(lockzhiner_vision_module::periphery::GPIOMode::OUT)) { + std::cout << "Failed to config gpio mode" << std::endl; + return 1; + } + + if (!gpio_0A0.Write(lockzhiner_vision_module::periphery::GPIOState::HIGH)) { + std::cout << "Failed to config gpio mode" << std::endl; + return 1; + } + + for (int i = 0; i < 10; i++) { + std::cout << "Wait: " << i << "/" << 10 << std::endl; + std::this_thread::sleep_for(std::chrono::seconds(1)); + } + + if (!gpio_0A0.Write(lockzhiner_vision_module::periphery::GPIOState::LOW)) { + std::cout << "Failed to config gpio mode" << std::endl; + return 1; + } + + return 0; +} +``` + +## 4 编译项目 + +使用 Docker Destop 打开 LockzhinerVisionModule 容器并执行以下命令来编译项目 + +```bash +# 进入 Demo 目录 +cd /LockzhinerVisionModuleWorkSpace/LockzhinerVisionModule/example/periphery/gpio + +# 创建编译目录 +rm -rf build && mkdir build && cd build + +# 配置交叉编译工具链 +export TOOLCHAIN_ROOT_PATH=${PWD}/../../../../../arm-rockchip830-linux-uclibcgnueabihf + +# 使用 cmake 配置项目 +cmake -DCMAKE_TOOLCHAIN_FILE=../../../../toolchains/arm-rockchip830-linux-uclibcgnueabihf.toolchain.cmake \ + -DCMAKE_BUILD_TYPE=Release \ + .. + +# 执行编译 +make -j8 +``` + +![](images/build_example.png) + +## 5 上传测试例程 + +参考 [连接设备指南](../../../docs/introductory_tutorial/connect_device_using_ssh.md) 正确连接 Lockzhiner Vision Module 设备。 + +![](../../../docs/introductory_tutorial/images/connect_device_using_ssh/ssh_success.png) + +使用 SFTP 功能将软件上传到 Lockzhiner Vision Module + +![](images/sftp.png) + +## 6 执行 GPIO 测试程序 + +### 6.1 测试 GPIO 输出电平 + +为了方便调试,我们这里使用 **示波器** 进行调试,请正确的将 Lockzhiner Vision Module 的引脚按照以下方式连接 + +* LockzhinerVisionModule GPIO_0A0 <-> Input IO +* LockzhinerVisionModule GND <-> Input GND + +板子上的引脚丝印较小,如果看不清引脚信息,可以参考下图 + +![](../../../images/periphery.png) + +在 Lockzhiner Vision Module 上运行以下代码来执行 GPIO 输出电平程序 + +```bash +chmod +x ./Test-GPIO-Write +./Test-GPIO-Write +``` + +查看示波器可以看到,GPIO_0A0 输出了 3.4V 左右的电压 + +![](images/show_0.png) + +电压持续 10S 后恢复了正常 + +![](images/show_1.png) + +### 6.2 测试 GPIO 输入高电平程序 + +为了方便调试,我们这里使用 **3V3 引脚** 进行调试,请正确的将 Lockzhiner Vision Module 的引脚按照以下方式连接 + +* LockzhinerVisionModule GPIO_0A0 <-> LockzhinerVisionModule 3V3 + +在 Lockzhiner Vision Module 上运行以下代码来执行 GPIO 接收程序 + +```bash +chmod +x ./Test-GPIO-Read +./Test-GPIO-Read +``` + +可以看到,在接高电平引脚的情况下,引脚的状态信息为 1 + +![](images/show_2.png) + +### 6.3 测试 GPIO 输入低电平程序 + +为了方便调试,我们这里使用 **GND 引脚** 进行调试,请正确的将 Lockzhiner Vision Module 的引脚按照以下方式连接 + +* LockzhinerVisionModule GPIO_0A0 <-> LockzhinerVisionModule GND + +在 Lockzhiner Vision Module 上运行以下代码来执行 GPIO 接收程序 + +```bash +export LD_LIBRARY_PATH=${PWD}:$LD_LIBRARY_PATH +chmod +x ./Test-GPIO-Read +./Test-GPIO-Read +``` + +可以看到,在低电平引脚的情况下,引脚的状态信息为 0 + +![](images/show_3.png) \ No newline at end of file diff --git a/example/periphery/gpio/images/build_example.png b/example/periphery/gpio/images/build_example.png new file mode 100644 index 0000000000000000000000000000000000000000..3e88199f843bf403382230746738720bd22fb585 Binary files /dev/null and b/example/periphery/gpio/images/build_example.png differ diff --git a/example/periphery/gpio/images/sftp.png b/example/periphery/gpio/images/sftp.png new file mode 100644 index 0000000000000000000000000000000000000000..883319d227feeeba32b228c8efe830633d555fcc Binary files /dev/null and b/example/periphery/gpio/images/sftp.png differ diff --git a/example/periphery/gpio/images/show_0.png b/example/periphery/gpio/images/show_0.png new file mode 100644 index 0000000000000000000000000000000000000000..e2651742fc34f4b5f777abb4b7b783e230046fb6 Binary files /dev/null and b/example/periphery/gpio/images/show_0.png differ diff --git a/example/periphery/gpio/images/show_1.png b/example/periphery/gpio/images/show_1.png new file mode 100644 index 0000000000000000000000000000000000000000..6e57d06a7d930b21e43829ecfd582e85c3617c93 Binary files /dev/null and b/example/periphery/gpio/images/show_1.png differ diff --git a/example/periphery/gpio/images/show_2.png b/example/periphery/gpio/images/show_2.png new file mode 100644 index 0000000000000000000000000000000000000000..1e204f1106f0f78ca9851c74d2c800ffb6004312 Binary files /dev/null and b/example/periphery/gpio/images/show_2.png differ diff --git a/example/periphery/gpio/images/show_3.png b/example/periphery/gpio/images/show_3.png new file mode 100644 index 0000000000000000000000000000000000000000..a290d4f504eee189e004f580ee6175b3c341fe8f Binary files /dev/null and b/example/periphery/gpio/images/show_3.png differ diff --git a/example/periphery/gpio/test_gpio_read.cc b/example/periphery/gpio/test_gpio_read.cc new file mode 100644 index 0000000000000000000000000000000000000000..485ab49907b2c4ded4f8ba70436c24a1ee3c5736 --- /dev/null +++ b/example/periphery/gpio/test_gpio_read.cc @@ -0,0 +1,22 @@ +#include + +#include +#include + +int main() { + lockzhiner_vision_module::periphery::GPIO_0A0 gpio_0A0; + + if (!gpio_0A0.Config(lockzhiner_vision_module::periphery::GPIOMode::IN)) { + std::cout << "Failed to config gpio mode" << std::endl; + return 1; + } + + lockzhiner_vision_module::periphery::GPIOState state; + if (!gpio_0A0.Read(state)) { + std::cout << "Failed to read gpio mode" << std::endl; + return 1; + } + + std::cout << "state is " << static_cast(state) << std::endl; + return 0; +} \ No newline at end of file diff --git a/example/periphery/gpio/test_gpio_write.cc b/example/periphery/gpio/test_gpio_write.cc new file mode 100644 index 0000000000000000000000000000000000000000..afc2d1874072e90a511830868eb470cd4a7438d0 --- /dev/null +++ b/example/periphery/gpio/test_gpio_write.cc @@ -0,0 +1,30 @@ +#include + +#include +#include + +int main() { + lockzhiner_vision_module::periphery::GPIO_0A0 gpio_0A0; + + if (!gpio_0A0.Config(lockzhiner_vision_module::periphery::GPIOMode::OUT)) { + std::cout << "Failed to config gpio mode" << std::endl; + return 1; + } + + if (!gpio_0A0.Write(lockzhiner_vision_module::periphery::GPIOState::HIGH)) { + std::cout << "Failed to config gpio mode" << std::endl; + return 1; + } + + for (int i = 0; i < 10; i++) { + std::cout << "Wait: " << i << "/" << 10 << std::endl; + std::this_thread::sleep_for(std::chrono::seconds(1)); + } + + if (!gpio_0A0.Write(lockzhiner_vision_module::periphery::GPIOState::LOW)) { + std::cout << "Failed to config gpio mode" << std::endl; + return 1; + } + + return 0; +} \ No newline at end of file diff --git a/example/periphery/pwm/CMakeLists.txt b/example/periphery/pwm/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..3e0bae252a0c9defd151f3e3bbfd05e02a7ddaed --- /dev/null +++ b/example/periphery/pwm/CMakeLists.txt @@ -0,0 +1,16 @@ +# CMake最低版本要求 +cmake_minimum_required(VERSION 3.10) + +project(test_pwm) + +# 定义项目根目录路径 +set(PROJECT_ROOT_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../..") +# 定义 LockzhinerVisionModule SDK 路径 +set(LockzhinerVisionModule_ROOT_PATH "${PROJECT_ROOT_PATH}/third_party/lockzhiner_vision_module_sdk") +set(LockzhinerVisionModule_DIR "${LockzhinerVisionModule_ROOT_PATH}/lib/cmake/lockzhiner_vision_module") +find_package(LockzhinerVisionModule REQUIRED) + +# 配置 PWM 读取例程 +add_executable(Test-PWM test_pwm.cc) +target_include_directories(Test-PWM PRIVATE ${LOCKZHINER_VISION_MODULE_INCLUDE_DIRS}) +target_link_libraries(Test-PWM PRIVATE ${LOCKZHINER_VISION_MODULE_LIBRARIES}) \ No newline at end of file diff --git a/example/periphery/pwm/README.md b/example/periphery/pwm/README.md new file mode 100644 index 0000000000000000000000000000000000000000..1fad535db88074ff050a4bba25ed9b4e9312e28c --- /dev/null +++ b/example/periphery/pwm/README.md @@ -0,0 +1,240 @@ +

PWM 使用指南

+ +发布版本:V0.0.0 + +日期:2024-08-30 + +文件密级:□绝密 □秘密 □内部资料 ■公开 + +--- + +**免责声明** + +本文档按**现状**提供,福州凌睿智捷电子有限公司(以下简称**本公司**)不对本文档中的任何陈述、信息和内容的准确性、可靠性、完整性、适销性、适用性及非侵权性提供任何明示或暗示的声明或保证。本文档仅作为使用指导的参考。 + +由于产品版本升级或其他原因,本文档可能在未经任何通知的情况下不定期更新或修改。 + +**读者对象** + +本教程适用于以下工程师: + +- 技术支持工程师 +- 软件开发工程师 + +**修订记录** + +| **日期** | **版本** | **作者** | **修改说明** | +| :--------- | -------- | -------- | ------------ | +| 2024/08/30 | 0.0.0 | 郑必城 | 初始版本 | + + +## 1 简介 + +在电子工程和嵌入式系统开发中,脉冲宽度调制(PWM, Pulse Width Modulation)是一项关键技术,它允许我们通过调整脉冲信号的占空比来控制模拟信号的平均电平。 + +## 2 前期准备 + +在开始这个章节前,请确保你已经按照 [开发环境搭建指南](../../../docs/introductory_tutorial/development_environment.md) 正确配置了开发环境。本章节中,我们将教会你如何控制 Lockzhiner Vision Module 上的 PWM 接口。 + +## 3 API 文档 + +```c++ +/** + * @brief PWM 类提供了对脉冲宽度调制(PWM)信号的控制接口。 + * + * 这个类允许用户打开、关闭 PWM 通道,并配置 PWM 信号的频率和占空比。 + * 需要注意的是, PWM 输出的电压在低电平时为 0V,高电平时为 3.3V。 + */ +class PWM { + public: + /** + * @brief PWM 类的构造函数。 + * + * 构造函数初始化 PWM 类的实例,但不自动打开 PWM 通道。 + */ + PWM(); + + /** + * @brief PWM 类的析构函数。 + * + * 析构函数负责清理 PWM 类实例使用的资源,但不会自动关闭 PWM 通道。 + * 建议在不需要 PWM 时显式调用 Close() 函数。 + */ + ~PWM(); + + /** + * @brief 打开 PWM 通道。 + * + * 此函数尝试打开 PWM 通道,但不配置任何参数(如频率和占空比)。 + * 成功时返回 true,失败时返回 false。 + * + * @return bool 指示操作是否成功。 + */ + bool Open(); + + /** + * @brief 关闭 PWM 通道。 + * + * 此函数关闭 PWM 通道,停止 PWM 信号的输出。 + * 成功时返回 true,失败时返回 false。 + * + * @return bool 指示操作是否成功。 + */ + bool Close(); + + /** + * @brief 配置 PWM 信号的频率和占空比。 + * + * 配置 PWM 信号的频率(以Hz为单位)和占空比(以 0.0 到 1.0 的浮点数表示)。 + * 成功时返回 true,失败时返回 false。 + * + * @param frequency PWM 信号的频率(Hz)。 + * @param duty_cycle PWM 信号的占空比(0.0 到 1.0 之间)。 + * @return bool 指示操作是否成功。 + */ + bool ConfigPWM(uint32_t frequency, float duty_cycle); + + /** + * @brief 打开 PWM 通道并配置频率与占空比。 + * + * 这是一个便捷的函数,它首先尝试打开 PWM 通道,然后配置 PWM + * 信号的频率和占空比。 如果任何一步失败,函数将返回 false。 + * + * @param frequency PWM 信号的频率(Hz)。 + * @param duty_cycle PWM 信号的占空比(0.0 到 1.0 之间)。 + * @return bool 指示操作是否成功。 + */ + bool Open(uint32_t frequency, float duty_cycle); +}; +``` + +## 4 项目介绍 + +为了方便大家入手,我们做了一个简易的 PWM 例程。该例程可以输出持续 10s 的 PWM 信号。 + +```cmake +# CMake最低版本要求 +cmake_minimum_required(VERSION 3.10) + +project(test_pwm) + +# 定义项目根目录路径 +set(PROJECT_ROOT_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../..") +# 定义 LockzhinerVisionModule SDK 路径 +set(LockzhinerVisionModule_ROOT_PATH "${PROJECT_ROOT_PATH}/third_party/lockzhiner_vision_module_sdk") +set(LockzhinerVisionModule_DIR "${LockzhinerVisionModule_ROOT_PATH}/lib/cmake/lockzhiner_vision_module") +find_package(LockzhinerVisionModule REQUIRED) + +# 配置 PWM 读取例程 +add_executable(Test-PWM test_pwm.cc) +target_include_directories(Test-PWM PRIVATE ${LOCKZHINER_VISION_MODULE_INCLUDE_DIRS}) +target_link_libraries(Test-PWM PRIVATE ${LOCKZHINER_VISION_MODULE_LIBRARIES}) +``` + +例程的核心代码如下: + +```cpp +#include + +#include // 为了使用atoi() +#include // 为了使用strtof() +#include +#include + +int main(int argc, char* argv[]) { + uint32_t frequency = 1000000; + float duty_cycle = 0.5; + if (argc == 3) { + frequency = std::atoi(argv[1]); + duty_cycle = std::strtof(argv[2], nullptr); + } + std::cout << "frequency is " << frequency << std::endl; + std::cout << "duty_cycle is " << duty_cycle << std::endl; + + lockzhiner_vision_module::periphery::PWM pwm; + + // 打开 PWM + if (!pwm.Open(frequency, duty_cycle)) { + std::cout << "Failed to open adc." << std::endl; + return 1; + } + + for (int i = 0; i < 10; i++) { + std::cout << "Wait: " << i << "/" << 10 << std::endl; + std::this_thread::sleep_for(std::chrono::seconds(1)); + } + + // 关闭 PWM + if (!pwm.Close()) { + std::cout << "Failed to open adc." << std::endl; + return 1; + } + return 0; +} +``` + +## 5 编译项目 + +使用 Docker Destop 打开 LockzhinerVisionModule 容器并执行以下命令来编译项目 + +```bash +# 进入 Demo 目录 +cd /LockzhinerVisionModuleWorkSpace/LockzhinerVisionModule/example/periphery/pwm + +# 创建编译目录 +rm -rf build && mkdir build && cd build + +# 配置交叉编译工具链 +export TOOLCHAIN_ROOT_PATH=${PWD}/../../../../../arm-rockchip830-linux-uclibcgnueabihf + +# 使用 cmake 配置项目 +cmake -DCMAKE_TOOLCHAIN_FILE=../../../../toolchains/arm-rockchip830-linux-uclibcgnueabihf.toolchain.cmake \ + -DCMAKE_BUILD_TYPE=Release \ + .. + +# 执行编译 +make -j8 +``` + +![](images/build_example.png) + +## 6 正确连接设备 + +> 注意: Lockzhiner Vision Module PWM 引脚输出的理论高电平为 3.3V,理论低电平为 0V + +为了方便调试,我们这里使用 **示波器** 进行调试,请正确的将 Lockzhiner Vision Module 的引脚按照以下方式连接 + +* LockzhinerVisionModule PWM <-> Input IO +* LockzhinerVisionModule GND <-> Input GND + +板子上的引脚丝印较小,如果看不清引脚信息,可以参考下图 + +![](../../../images/periphery.png) + +## 7 执行 ADC 测试程序 + +参考 [连接设备指南](../../../docs/introductory_tutorial/connect_device_using_ssh.md) 正确连接 Lockzhiner Vision Module 设备。 + +![](../../../docs/introductory_tutorial/images/connect_device_using_ssh/ssh_success.png) + +使用 SFTP 功能将软件上传到 Lockzhiner Vision Module + +![](images/sftp.png) + +在 Lockzhiner Vision Module 上运行以下代码来执行 ADC 测试程序 + +```bash +chmod +x ./Test-PWM +# ./Test-PWM 频率(默认为1MHZ) 占空比(默认为0.5) +./Test-PWM 100000 0.5 +``` + +程序运行开始后,屏幕上打印配置的频率和占空比并开始每隔一秒显示当前进度 + +![](images/pwm_start.png) +![](images/show_start.png) + +程序运行 10s 后,程序退出 PWM 停止 + +![](images/pwm_end.png) +![](images/show_end.png) \ No newline at end of file diff --git a/example/periphery/pwm/images/build_example.png b/example/periphery/pwm/images/build_example.png new file mode 100644 index 0000000000000000000000000000000000000000..9784743e0cce2fd097afe647a70a91994bede902 Binary files /dev/null and b/example/periphery/pwm/images/build_example.png differ diff --git a/example/periphery/pwm/images/pwm_end.png b/example/periphery/pwm/images/pwm_end.png new file mode 100644 index 0000000000000000000000000000000000000000..79ec1475682e680bc682e90b47e78523581b80ec Binary files /dev/null and b/example/periphery/pwm/images/pwm_end.png differ diff --git a/example/periphery/pwm/images/pwm_start.png b/example/periphery/pwm/images/pwm_start.png new file mode 100644 index 0000000000000000000000000000000000000000..3586a45a9cc9eef7165dd271a02193eed8a3eee5 Binary files /dev/null and b/example/periphery/pwm/images/pwm_start.png differ diff --git a/example/periphery/pwm/images/sftp.png b/example/periphery/pwm/images/sftp.png new file mode 100644 index 0000000000000000000000000000000000000000..b5546d6e4311959bcbf23723431df3d464d62dc6 Binary files /dev/null and b/example/periphery/pwm/images/sftp.png differ diff --git a/example/periphery/pwm/images/show_end.png b/example/periphery/pwm/images/show_end.png new file mode 100644 index 0000000000000000000000000000000000000000..714db93c00af2ccc76bee8e7a9bfcc391461327e Binary files /dev/null and b/example/periphery/pwm/images/show_end.png differ diff --git a/example/periphery/pwm/images/show_start.png b/example/periphery/pwm/images/show_start.png new file mode 100644 index 0000000000000000000000000000000000000000..2a6dca1f92f2fab00fd6beea9356b08f19f4c130 Binary files /dev/null and b/example/periphery/pwm/images/show_start.png differ diff --git a/example/periphery/pwm/test_pwm.cc b/example/periphery/pwm/test_pwm.cc new file mode 100644 index 0000000000000000000000000000000000000000..7dc14b01c6e5376edaf3ef67e5acc78fb7345a48 --- /dev/null +++ b/example/periphery/pwm/test_pwm.cc @@ -0,0 +1,37 @@ +#include + +#include // 为了使用atoi() +#include // 为了使用strtof() +#include +#include + +int main(int argc, char* argv[]) { + uint32_t frequency = 1000000; + float duty_cycle = 0.5; + if (argc == 3) { + frequency = std::atoi(argv[1]); + duty_cycle = std::strtof(argv[2], nullptr); + } + std::cout << "frequency is " << frequency << std::endl; + std::cout << "duty_cycle is " << duty_cycle << std::endl; + + lockzhiner_vision_module::periphery::PWM pwm; + + // 打开 PWM + if (!pwm.Open(frequency, duty_cycle)) { + std::cout << "Failed to open adc." << std::endl; + return 1; + } + + for (int i = 0; i < 10; i++) { + std::cout << "Wait: " << i << "/" << 10 << std::endl; + std::this_thread::sleep_for(std::chrono::seconds(1)); + } + + // 关闭 PWM + if (!pwm.Close()) { + std::cout << "Failed to open adc." << std::endl; + return 1; + } + return 0; +} \ No newline at end of file diff --git a/example/periphery/usart/CMakeLists.txt b/example/periphery/usart/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..8b74045729ec95fb1f8b5108113a53f33932e609 --- /dev/null +++ b/example/periphery/usart/CMakeLists.txt @@ -0,0 +1,21 @@ +# CMake最低版本要求 +cmake_minimum_required(VERSION 3.10) + +project(test_usart) + +# 定义项目根目录路径 +set(PROJECT_ROOT_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../..") +# 定义 LockzhinerVisionModule SDK 路径 +set(LockzhinerVisionModule_ROOT_PATH "${PROJECT_ROOT_PATH}/third_party/lockzhiner_vision_module_sdk") +set(LockzhinerVisionModule_DIR "${LockzhinerVisionModule_ROOT_PATH}/lib/cmake/lockzhiner_vision_module") +find_package(LockzhinerVisionModule REQUIRED) + +# 配置串口输出 Demo +add_executable(Test-USART-Write test_usart_write.cc) +target_include_directories(Test-USART-Write PRIVATE ${LOCKZHINER_VISION_MODULE_INCLUDE_DIRS}) +target_link_libraries(Test-USART-Write PRIVATE ${LOCKZHINER_VISION_MODULE_LIBRARIES}) + +# 配置串口读取 Demo +add_executable(Test-USART-Read test_usart_read.cc) +target_include_directories(Test-USART-Read PRIVATE ${LOCKZHINER_VISION_MODULE_INCLUDE_DIRS}) +target_link_libraries(Test-USART-Read PRIVATE ${LOCKZHINER_VISION_MODULE_LIBRARIES}) \ No newline at end of file diff --git a/example/periphery/usart/README.md b/example/periphery/usart/README.md new file mode 100644 index 0000000000000000000000000000000000000000..1c4a51e1d2de2895ebd764ce0a5e3da1d36e98db --- /dev/null +++ b/example/periphery/usart/README.md @@ -0,0 +1,257 @@ +

串口使用指南

+ +发布版本:V0.0.2 + +日期:2024-08-30 + +文件密级:□绝密 □秘密 □内部资料 ■公开 + +--- + +**免责声明** + +本文档按**现状**提供,福州凌睿智捷电子有限公司(以下简称**本公司**)不对本文档中的任何陈述、信息和内容的准确性、可靠性、完整性、适销性、适用性及非侵权性提供任何明示或暗示的声明或保证。本文档仅作为使用指导的参考。 + +由于产品版本升级或其他原因,本文档可能在未经任何通知的情况下不定期更新或修改。 + +**读者对象** + +本教程适用于以下工程师: + +- 技术支持工程师 +- 软件开发工程师 + +**修订记录** + +| **日期** | **版本** | **作者** | **修改说明** | +| :--------- | -------- | -------- | ------------ | +| 2024/08/29 | 0.0.0 | 郑必城 | 初始版本 | +| 2024/08/29 | 0.0.1 | 郑必城 | 修补缺失的内容 | +| 2024/08/30 | 0.0.2 | 郑必城 | 更新到最新的 串口 SDK | + + +## 1 简介 + +串口,也称为串行接口或串行通信接口,是一种用于连接计算机与外部设备并进行数据传输的接口技术。它使用较少的导线(通常只需要几根线),并且可以在较长的距离上可靠地传输数据,尽管速度相对较慢。本章节中,我们将教会你如何使用 Lockzhiner Vision Module 上的串口进行传输数据。 + +## 2 前期准备 + +在开始这个章节前,请确保你已经按照 [开发环境搭建指南](../../../docs/introductory_tutorial/development_environment.md) 正确配置了开发环境。 + +## 3 API 文档 + +```c++ +/// \class USART +/// \brief 串口控制类,用于串口通信的数据发送和接收。 +/// +/// 该类封装了串口的基本操作,包括打开串口、关闭串口、发送数据和接收数据。 +class USART { + public: + USART() = default; + ~USART(); + + /// \brief 打开串口。 + /// + /// \param baud_rate 波特率,用于设置串口通信速率,默认为 115200。 + /// \return 成功打开串口返回 true,否则返回 false。 + bool Open(uint32_t baud_rate = 115200); + + /// \brief 关闭串口。 + /// + /// \return 成功关闭串口返回 true,否则返回 false。 + bool Close(); + + /// \brief 发送数据。 + /// + /// \param data 要发送的数据字符串。 + /// \return 成功发送数据返回 true,否则返回 false。 + bool Write(const std::string& data); + + /// \brief 接收数据。 + /// + /// \param buffer 用于存储接收到的数据的缓冲区。 + /// \param size 缓冲区的大小。 + /// \return 成功接收数据返回 true,否则返回 false。 + bool Read(std::string& buffer, size_t size); + + private: + int serial_port_ = -1; + uint32_t GetBaudRate(int baud_rate); +}; +``` + +## 3 项目介绍 + +为了方便大家入手,我们将项目拆分为串口接受数据和串口发送数据两个部分,他们共用一个 CMake 文件。 + +```cmake +# CMake最低版本要求 +cmake_minimum_required(VERSION 3.10) + +project(test_usart) + +# 定义项目根目录路径 +set(PROJECT_ROOT_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../..") +# 定义 LockzhinerVisionModule SDK 路径 +set(LockzhinerVisionModule_ROOT_PATH "${PROJECT_ROOT_PATH}/third_party/lockzhiner_vision_module_sdk") +set(LockzhinerVisionModule_DIR "${LockzhinerVisionModule_ROOT_PATH}/lib/cmake/lockzhiner_vision_module") +find_package(LockzhinerVisionModule REQUIRED) + +# 配置串口输出 Demo +add_executable(Test-USART-Write test_usart_write.cc) +target_include_directories(Test-USART-Write PRIVATE ${LOCKZHINER_VISION_MODULE_INCLUDE_DIRS}) +target_link_libraries(Test-USART-Write PRIVATE ${LOCKZHINER_VISION_MODULE_LIBRARIES}) + +# 配置串口读取 Demo +add_executable(Test-USART-Read test_usart_read.cc) +target_include_directories(Test-USART-Read PRIVATE ${LOCKZHINER_VISION_MODULE_INCLUDE_DIRS}) +target_link_libraries(Test-USART-Read PRIVATE ${LOCKZHINER_VISION_MODULE_LIBRARIES}) +``` + +串口接受数据的核心代码如下: + +```cpp +#include // 串口类头文件 + +#include // 引入标准输入输出流库 + +int main() { + // 创建串口类对象 + lockzhiner_vision_module::periphery::USART usart; + + // 尝试以115200的波特率打开串口 + if (!usart.Open(115200)) { + // 如果打开失败,则输出错误信息并返回1 + std::cout << "Failed to open usart." << std::endl; + return 1; + } + + // 输出开始接收串口数据的提示信息 + std::cout << "Start receiving serial port data." << std::endl; + + // 无限循环,持续接收串口数据 + while (1) { + std::string buffer; // 用于存储接收到的串口数据 + // 从串口读取数据到buffer中,最多读取1024字节 + usart.Read(buffer, 1024); + // 如果buffer不为空,则输出接收到的数据 + if (!buffer.empty()) { + std::cout << buffer << std::endl; + } + } + return 0; +} +``` + +串口发送数据的核心代码如下: + +```cpp +#include // 引入串口类头文件 + +#include // 引入标准输入输出流库 + +int main() { + // 创建串口类对象 + lockzhiner_vision_module::periphery::USART usart; + + // 尝试以115200的波特率打开串口 + if (!usart.Open(115200)) { + // 如果打开失败,则输出错误信息并返回1 + std::cout << "Failed to open usart." << std::endl; + return 1; + } + + // 尝试发送字符串"Hello World\n" + if (!usart.Write("Hello World\n")) { + // 如果发送失败,则输出错误信息 + std::cout << "Failed to send data." << std::endl; + } + return 0; +} +``` + +## 4 编译项目 + +使用 Docker Destop 打开 LockzhinerVisionModule 容器并执行以下命令来编译项目 + +```bash +# 进入 Demo 目录 +cd /LockzhinerVisionModuleWorkSpace/LockzhinerVisionModule/example/periphery/usart + +# 创建编译目录 +rm -rf build && mkdir build && cd build + +# 配置交叉编译工具链 +export TOOLCHAIN_ROOT_PATH=${PWD}/../../../../../arm-rockchip830-linux-uclibcgnueabihf + +# 使用 cmake 配置项目 +cmake -DCMAKE_TOOLCHAIN_FILE=../../../../toolchains/arm-rockchip830-linux-uclibcgnueabihf.toolchain.cmake \ + -DCMAKE_BUILD_TYPE=Release \ + .. + +# 执行编译 +make -j8 +``` + +![](images/build_example.png) + +## 5 正确连接设备 + +为了方便调试,我们这里使用 **CH340 USB 转串口模块(以下简称 CH340)**进行调试,请正确的将模型的引脚按照以下方式连接 + +* LockzhinerVisionModule RX1 <-> CH340 TXD +* LockzhinerVisionModule TX1 <-> CH340 RXD +* LockzhinerVisionModule GND <-> CH340 GND + +> Lockzhiner 也提供官方的 [CH340 USB 转串口模块](http://e.tb.cn/h.gMbjEDBRiaOutkO?tk=kBlS35jFQOE),如果有需要可以前往购买。 + +## 6 执行串口测试程序 + +参考 [连接设备指南](../../../docs/introductory_tutorial/connect_device_using_ssh.md) 正确连接 Lockzhiner Vision Module 设备。 + +![](../../../docs/introductory_tutorial/images/connect_device_using_ssh/ssh_success.png) + +使用 SFTP 功能将软件上传到 Lockzhiner Vision Module + +![](images/sftp.png) + +打开串口工具,我这里选择的是 [vofa+](https://www.vofa.plus/),配置波特率为 115200 并打开串口 + +![](images/vofa.png) + +### 6.1 测试串口发送程序 + +在 Lockzhiner Vision Module 上运行以下代码来执行串口发送程序 + +```bash +export LD_LIBRARY_PATH=${PWD}:$LD_LIBRARY_PATH +chmod +x ./Test-USART-Write +./Test-USART-Write +``` + +![](images/usart_wirte_electerm.png) + +vofa+ 上显示发送的字符串(Hello World) + +![](images/usart_write_voft.png) + +### 6.2 测试串口接收程序 + +在 Lockzhiner Vision Module 上运行以下代码来执行串口接收程序 + +```bash +export LD_LIBRARY_PATH=${PWD}:$LD_LIBRARY_PATH +chmod +x ./Test-USART-Read +./Test-USART-Read +``` + +![](images/usart_send_wait_electerm.png) + + +vofa+ 点击发送字符串(Hello World) + +![](images/usart_send_voft.png) + +Lockzhiner Vision Module 打印接受到的字符串(Hello World) + +![](images/usart_send_show_electerm.png) \ No newline at end of file diff --git a/example/periphery/usart/images/build_example.png b/example/periphery/usart/images/build_example.png new file mode 100644 index 0000000000000000000000000000000000000000..73c00a2ce13769c000b092e3b1fce6b9da247b76 Binary files /dev/null and b/example/periphery/usart/images/build_example.png differ diff --git a/example/periphery/usart/images/sftp.png b/example/periphery/usart/images/sftp.png new file mode 100644 index 0000000000000000000000000000000000000000..41d5fa8e1ef9f1183627bc85edc3844d473fb041 Binary files /dev/null and b/example/periphery/usart/images/sftp.png differ diff --git a/example/periphery/usart/images/usart_send_show_electerm.png b/example/periphery/usart/images/usart_send_show_electerm.png new file mode 100644 index 0000000000000000000000000000000000000000..249ab740604ded7836ead349fcf7820a4412db0b Binary files /dev/null and b/example/periphery/usart/images/usart_send_show_electerm.png differ diff --git a/example/periphery/usart/images/usart_send_voft.png b/example/periphery/usart/images/usart_send_voft.png new file mode 100644 index 0000000000000000000000000000000000000000..86f15de3852425cd5be2a8f3cd3d60e29fa83a78 Binary files /dev/null and b/example/periphery/usart/images/usart_send_voft.png differ diff --git a/example/periphery/usart/images/usart_send_wait_electerm.png b/example/periphery/usart/images/usart_send_wait_electerm.png new file mode 100644 index 0000000000000000000000000000000000000000..f84067b90b2c5e17744ce38295a3e28462c90e88 Binary files /dev/null and b/example/periphery/usart/images/usart_send_wait_electerm.png differ diff --git a/example/periphery/usart/images/usart_wirte_electerm.png b/example/periphery/usart/images/usart_wirte_electerm.png new file mode 100644 index 0000000000000000000000000000000000000000..1a68a6d2943c46ec8e7d8b5b02e5a583b8a05cec Binary files /dev/null and b/example/periphery/usart/images/usart_wirte_electerm.png differ diff --git a/example/periphery/usart/images/usart_write_voft.png b/example/periphery/usart/images/usart_write_voft.png new file mode 100644 index 0000000000000000000000000000000000000000..46cbd9a3649f526b410aed890a92f34445da7096 Binary files /dev/null and b/example/periphery/usart/images/usart_write_voft.png differ diff --git a/example/periphery/usart/images/vofa.png b/example/periphery/usart/images/vofa.png new file mode 100644 index 0000000000000000000000000000000000000000..1f9d5c851f8eb96979230b512a45ec50a4804805 Binary files /dev/null and b/example/periphery/usart/images/vofa.png differ diff --git a/example/periphery/usart/test_usart_read.cc b/example/periphery/usart/test_usart_read.cc new file mode 100644 index 0000000000000000000000000000000000000000..93aa0411e6a4e00f650d34d7c6cc16e0daf7d325 --- /dev/null +++ b/example/periphery/usart/test_usart_read.cc @@ -0,0 +1,30 @@ +#include // 串口类头文件 + +#include // 引入标准输入输出流库 + +int main() { + // 创建串口类对象 + lockzhiner_vision_module::periphery::USART usart; + + // 尝试以115200的波特率打开串口 + if (!usart.Open(115200)) { + // 如果打开失败,则输出错误信息并返回1 + std::cout << "Failed to open usart." << std::endl; + return 1; + } + + // 输出开始接收串口数据的提示信息 + std::cout << "Start receiving serial port data." << std::endl; + + // 无限循环,持续接收串口数据 + while (1) { + std::string buffer; // 用于存储接收到的串口数据 + // 从串口读取数据到buffer中,最多读取1024字节 + usart.Read(buffer, 1024); + // 如果buffer不为空,则输出接收到的数据 + if (!buffer.empty()) { + std::cout << buffer << std::endl; + } + } + return 0; +} \ No newline at end of file diff --git a/example/periphery/usart/test_usart_write.cc b/example/periphery/usart/test_usart_write.cc new file mode 100644 index 0000000000000000000000000000000000000000..7ef8c427684af47364665ce3297d91739adf5158 --- /dev/null +++ b/example/periphery/usart/test_usart_write.cc @@ -0,0 +1,22 @@ +#include // 引入串口类头文件 + +#include // 引入标准输入输出流库 + +int main() { + // 创建串口类对象 + lockzhiner_vision_module::periphery::USART usart; + + // 尝试以115200的波特率打开串口 + if (!usart.Open(115200)) { + // 如果打开失败,则输出错误信息并返回1 + std::cout << "Failed to open usart." << std::endl; + return 1; + } + + // 尝试发送字符串"Hello World\n" + if (!usart.Write("Hello World\n")) { + // 如果发送失败,则输出错误信息 + std::cout << "Failed to send data." << std::endl; + } + return 0; +} \ No newline at end of file diff --git a/example/vision/classification/README.md b/example/vision/classification/README.md new file mode 100644 index 0000000000000000000000000000000000000000..6a26cc6e2855e2eb4f59fec610a4faded93fc6f9 --- /dev/null +++ b/example/vision/classification/README.md @@ -0,0 +1,198 @@ +

凌智视觉模块分类模型部署指南

+ +## 1 简介 + +在深度学习中,分类模型是一类用于将输入数据分配到预定义类别或标签的模型。这类模型的主要目标是通过分析输入特征,将数据正确地归类到一个或多个类别中。在本章节中,我们将教你如何使用 PaddleX 和 PaddleSlim 训练一个分类模型并在 LockzhinerVisionModule 上部署。 + +## 2 图像数据标注 + +### 2.1 Labelme 标注工具安装 + +Labelme 是一个 python 语言编写,带有图形界面的图像标注软件。可用于图像分类,目标检测,图像分割等任务,在图像分类的标注任务中,标签存储为 JSON 文件。在本章节中,我们使用这个软件来标注数据。 + +首先,点击 [Labelme 下载地址](https://sourceforge.net/projects/labelme-ima-polygonal.mirror/files/v5.5.0/Labelme.exe/download),耐心等待几秒后,浏览器将自动开始下载 Labelme,如下图: + +![image-20240906175736785](images/sourceForge.png) + +一般来说,下载完成后,系统的下载文件夹内将多出 **Labelme.exe** + +![image-20240906175913060](images/download.png) + +### 2.2 标注前的准备 + +首先,请参考 [摄像头使用指南](./example/periphery/capture/README.md) 利用 **Lockzhiner Vision Module 图片获取助手** 拍摄你需要进行标注的图片,如下图所示: + +![](images/capture_images.png) + +选择一个你想存放数据集的位置,将 **Labelme.exe** 移动到文件夹下同时创建一个空的文件夹并命名为 **Dataset**,如下图: + +![](images/Labelme_Dataset.png) + +进入 **Dataset** 文件夹,创建 **images** 文件夹、**annocations** 文件夹、**flags.txt** 文件,如下图: + +![](images/images_annocations_flags.png) + +进入 **Dataset** 文件夹,打开 **images**目录,将 **Lockzhiner Vision Module 图片获取助手** 保存的图片数据(在程序运行目录的 **LockzhinerVisionModuleImages** 文件夹内)移动到该文件夹内,如下图: + +![](images/images.png) + +进入 **Dataset** 文件夹,打开 **flags.txt** 按行写入待标注数据集的类别。由于我们的数据集将数据分为两类(**good** 和 **bad**),因此向文件中分别写入 good 和 bad,写入完成后如下图所示: + +![image-20240906180109214](images/flags.png) + +进入 **Dataset** 文件夹所在的目录,按住键盘`Shift`键后,单击鼠标右键,点击 **在此处打开 Powershell 窗口**。 + +![](images/powershell.png) + +弹出 **Powershell 窗口**后,输入以下命令来打开 **Labelme**,如下图: + +```bash +.\Labelme.exe .\Dataset\images --nodata --autosave --output .\Dataset\annotations --flags .\Dataset\flags.txt +``` + +![image-20240906182832416](images/cmd.png) + +命令执行后将打开 **Labelme** 程序,如下图 + +![](images/Labelme.png) + +### 2.3 标注并产出数据集 + +打开 **Labelme** 后,我们开始标记图像,勾选右边"标记"方块内的类别对图像进行标记,点击文件列表切换需要标注的图像,请耐心对拍摄的每一张图片进行标注。 + +![](images/annotate_images.png) + +进入 **Dataset** 文件夹所在的目录,将 Dataset 目录压缩为文件夹。注意,压缩包的最外层需要有 Dataset 目录。这里我们建议你使用 Bandzip 压缩软件进行压缩,具体的操作步骤如下: + +![](images/bandzip_0.png) + +![](images/bandzip_1.png) + +![](images/bandzip_2.png) + +压缩完成后,打开压缩文件检查下最外层是否有 Dataset 目录 + +![](images/bandzip_3.png) + +## 3 使用 AIStudio 训练分类模型 + +### 3.1 简介 + +AI Studio 是基于百度深度学习开源平台飞桨的人工智能学习与实训社区,为开发者提供了功能强大的线上训练环境、免费GPU算力及存储资源。Lockzhiner Vision Module 默认使用 AI Studio 进行快速训练。 + +### 3.2 登录 AIStudio + +进入 [AI Studio](https://aistudio.baidu.com),点击右上角的登录按钮,输入你的百度账号进行登录。 + +![](../images/ai_studio_0.png) + +![](../images/ai_studio_1.png) + +### 3.3 上传数据集文件 + +点击**数据**,点击**创建数据集**来打开数据集创建界面,如下图: + +![](../images/ai_studio_2.png) + +正确填入合适的内容,如下图: + +![](../images/ai_studio_3.png) + +耐心等待数据集上传完成,完成后点击 **确定**,如下图: + +![](../images/ai_studio_4.png) + +### 3.4 Fork 项目 + +进入 [【PaddleX】在凌智 AI 视觉模块上部署 PaddleClas 模型](https://aistudio.baidu.com/projectdetail/8285578?sUid=790375&shared=1&ts=1725690007105) 项目,点击右上角的 **Fork** 图标来创建自己的项目,如下图: + +![](images/fork_0.png) + +正确填入合适的内容,如下图: + +![](images/fork_1.png) + +点击取消按钮,如下图: + +![](images/fork_2.png) + +### 3.5 配置项目数据集 + +点击最左侧**项目**按钮,然后点击中间**项目**按钮,找到刚才 Fork 的项目,如下图: + +![](images/config_dataset_0.png) + +点击右上角 **修改**,点击**添加数据集**,点击**个人数据集**,找到刚才创建的数据集并点击**添加**,点击**保存**按钮,如下图: + +![](images/config_dataset_1.png) + +![](images/config_dataset_2.png) + +![](images/config_dataset_3.png) + +![](images/config_dataset_4.png) + +### 3.6 启动项目 + +点击**启动环境**,选择 **V100 16GB**,点击**确定**,如下图 + +![](images/start_project_0.png) + +![](images/start_project_1.png) + +耐心等待一段时间来启动项目,点击**进入**到项目中,如下图: + +![](images/start_project_2.png) + +![](images/start_project_3.png) + +### 3.7 配置项目训练参数 + +点击 **data**,查看并复制数据集保存目录(右键数据集保存目录,点击重命名来复制),如下图: + +![](images/config_project_0.png) + +![](images/config_project_1.png) + +找到**项目全局配置项**,配置数据集路径,我这里是 **data293515**,如下图: + +![](images/config_project_2.png) + +配置分类目标参数,之前数据集是两类,因此这边配置为2,如下图: + +![](images/config_project_3.png) + +### 3.8 开始训练 + +点击**运行全部 Cell** 开启训练,耐心等待训练完成,如下图: + +![](images/run_project_0.png) + +训练完成后,主目录下会出现 **output** 文件夹,文件夹内包含了一个 ONNX 模型和一个 RKNN 模型,如下图: + +![](images/run_project_1.png) + +![](images/run_project_2.png) + +选中 **output** 文件夹,右键鼠标,点击 **打包选中文件夹**。打包完成后,出现 **output.zip** 文件,右键该文件,点击**下载**。 + +![](images/run_project_3.png) + +![](images/run_project_4.png) + +## 4 在凌智视觉模块上部署模型 + +训练完模型后,请参考以下教程使用 C++ 或 Python 在凌智视觉模块上部署模型: + +* [凌智视觉模块分类模型 C++ 部署指南](./cpp/README.md) +* [凌智视觉模块分类模型 Python 部署指南](./python/README.md) + +## 5 各模型性能指标 + +以下测试数据为模型执行 Predict 函数运行 1000 次耗时的平均时间 + +| 分类模型 | FPS(帧/s) | 精度(%) | +|:-------:|:----:|:----:| +|LZ-MobileNetV2_x0_25|70.57|53.21| +|LZ-MobileNetV2_x0_5|63.48|65.03| +|LZ-MobileNetV2_x1_0|49.44|72.15| \ No newline at end of file diff --git a/example/vision/classification/cpp/CMakeLists.txt b/example/vision/classification/cpp/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..bc0b3db8aa030734d93ec811b7a96098ee43d8fc --- /dev/null +++ b/example/vision/classification/cpp/CMakeLists.txt @@ -0,0 +1,19 @@ +cmake_minimum_required(VERSION 3.10) + +project(test_classification) + +# 定义项目根目录路径 +set(PROJECT_ROOT_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../../..") +# 定义 OpenCV SDK 路径 +set(OpenCV_ROOT_PATH "${PROJECT_ROOT_PATH}/third_party/opencv-mobile-4.10.0-lockzhiner-vision-module") +set(OpenCV_DIR "${OpenCV_ROOT_PATH}/lib/cmake/opencv4") +find_package(OpenCV REQUIRED) +set(OPENCV_LIBRARIES "${OpenCV_LIBS}") +# 定义 LockzhinerVisionModule SDK 路径 +set(LockzhinerVisionModule_ROOT_PATH "${PROJECT_ROOT_PATH}/third_party/lockzhiner_vision_module_sdk") +set(LockzhinerVisionModule_DIR "${LockzhinerVisionModule_ROOT_PATH}/lib/cmake/lockzhiner_vision_module") +find_package(LockzhinerVisionModule REQUIRED) + +add_executable(Test-PaddleClas test_paddleclas.cpp) +target_include_directories(Test-PaddleClas PRIVATE ${LOCKZHINER_VISION_MODULE_INCLUDE_DIRS}) +target_link_libraries(Test-PaddleClas PRIVATE ${OPENCV_LIBRARIES} ${LOCKZHINER_VISION_MODULE_LIBRARIES}) \ No newline at end of file diff --git a/example/vision/classification/cpp/README.md b/example/vision/classification/cpp/README.md new file mode 100644 index 0000000000000000000000000000000000000000..d4edf571e6279cfb1c5100b12147e6eb3e4e6de7 --- /dev/null +++ b/example/vision/classification/cpp/README.md @@ -0,0 +1,278 @@ +

凌智视觉模块分类模型 C++ 部署指南

+ +## 1 简介 + +接下来让我们基于 C++ 来部署 PaddleClas 分类模型。在开始本章节前,请确保你已经参考 [凌智视觉模块分类模型部署指南](../README.md) 对模型进行了充分训练。如果你需要使用 Python 来部署 PaddleClas 请参考 [凌智视觉模块分类模型 Python 部署指南](../python/README.md)。 + +## 2 C++ API 文档 + +```cpp +/// \struct ClassificationResult +/// \brief ClassificationResult 结构体 - 用于存储图像分类的结果。 +/// +/// 该结构体包含了图像分类结果的基本信息,包括分类的标签ID和置信度。 +struct ClassificationResult { + /// \brief 默认构造函数。 + /// + /// 创建一个默认的 ClassificationResult 实例,其中 label_id 初始化为 + /// -1,表示空结果,confidence 初始化为 0.0。 + ClassificationResult() = default; + + /// \brief 拷贝构造函数。 + /// + /// 创建一个新的 ClassificationResult 实例,并将其初始化为与另一个 + /// ClassificationResult 实例相同的状态。 + ClassificationResult(const ClassificationResult& other) = default; + + /// \brief 移动赋值运算符。 + /// + /// 将一个右值 ClassificationResult 实例的资源移动到当前实例中。 + /// + /// \param other 要移动的 ClassificationResult 实例。 + /// \return 对当前 ClassificationResult 实例的引用。 + ClassificationResult& operator=(ClassificationResult&& other); + + /// \brief 判断结果是否为空。 + /// + /// 检查 label_id 是否为 -1,如果是,则表示结果为空(即没有有效的分类结果)。 + /// + /// \return 如果结果为空,则返回 true;否则返回 false。 + bool Empty() { return label_id != -1; } + + /// \brief 分类的标签ID。 + /// + /// 存储分类结果的标签ID,用于标识分类的类别。-1 表示结果为空。 + int32_t label_id = -1; + + /// \brief 分类的置信度。 + /// + /// 存储分类结果的置信度,表示模型对分类结果的信任程度。值为 0.0 到 1.0 + /// 之间的浮点数。 + float confidence = 0.0; +}; + +/// \class PaddleClas +/// \brief PaddleClas 类 - 基于 PaddlePaddle 的图像分类模型基类。 +/// +/// 该类继承自 +/// BaseModel,是图像分类模型的基础类,提供了预测、预处理和后处理的方法接口。 +/// 通过派生类可以实现具体的图像分类模型,如 PPLCNet 和 MobileNetV2。 +class PaddleClas : public BaseModel { + public: + /// \brief 默认构造函数。 + /// + /// 创建一个 PaddleClas 实例。 + PaddleClas() = default; + + /// \brief 虚析构函数。 + /// + /// 释放 PaddleClas 实例所占用的资源。 + ~PaddleClas() override = default; + + /// \brief 初始化模型推理后端 + /// + /// 初始化模型推理后端并返回是否初始化成功 + /// + /// \param model 传入 RKNN 模型路径 + /// \return 初始化是否成功 + bool Initialize(void* model); + + /// \brief 进行图像分类预测。 + /// + /// 使用 PaddleClas 模型对输入的图像进行分类预测,并将结果存储在提供的 + /// ClassificationResult 对象中。 + /// + /// \param mat 输入的图像数据,类型为 cv::Mat。 + /// \param result 存储预测结果的 ClassificationResult 对象。 + /// \return 预测是否成功。 + bool Predict(const cv::Mat& mat, ClassificationResult& result); +}; +``` + +## 3 项目介绍 + +为了方便大家入手,我们做了一个简易的图像分类例程。根据输入参数的不同,该程序可以测试模型的推理速度或使用摄像头进行端到端推理。 + +```cmake +cmake_minimum_required(VERSION 3.10) + +project(test_classification) + +# 定义项目根目录路径 +set(PROJECT_ROOT_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../..") +# 定义 OpenCV SDK 路径 +set(OpenCV_ROOT_PATH "${PROJECT_ROOT_PATH}/third_party/opencv-mobile-4.10.0-lockzhiner-vision-module") +set(OpenCV_DIR "${OpenCV_ROOT_PATH}/lib/cmake/opencv4") +find_package(OpenCV REQUIRED) +set(OPENCV_LIBRARIES "${OpenCV_LIBS}") +# 定义 LockzhinerVisionModule SDK 路径 +set(LockzhinerVisionModule_ROOT_PATH "${PROJECT_ROOT_PATH}/third_party/lockzhiner_vision_module_sdk") +set(LockzhinerVisionModule_DIR "${LockzhinerVisionModule_ROOT_PATH}/lib/cmake/lockzhiner_vision_module") +find_package(LockzhinerVisionModule REQUIRED) + +add_executable(Test-PaddleClas Test-PaddleClas.cpp) +target_include_directories(Test-PaddleClas PRIVATE ${LOCKZHINER_VISION_MODULE_INCLUDE_DIRS}) +target_link_libraries(Test-PaddleClas PRIVATE ${OPENCV_LIBRARIES} ${LOCKZHINER_VISION_MODULE_LIBRARIES}) +``` + +例程的核心代码如下: + +```cpp +#include + +#include +#include // for std::rand and std::srand +#include // for std::time +#include +#include + +using namespace std::chrono; + +lockzhiner_vision_module::vision::PaddleClas model; + +int TestFPS() { + // 创建一个空的3通道Mat,宽640,高480,类型为CV_8UC3 + std::srand(static_cast(std::time(nullptr))); + cv::Mat input_mat(480, 640, CV_8UC3); + for (int i = 0; i < input_mat.rows; ++i) { + for (int j = 0; j < input_mat.cols; ++j) { + input_mat.at(i, j)[0] = std::rand() % 256; // B通道 + input_mat.at(i, j)[1] = std::rand() % 256; // G通道 + input_mat.at(i, j)[2] = std::rand() % 256; // R通道 + } + } + + constexpr int run_index = 1000; + int time_ms = 0; + lockzhiner_vision_module::vision::ClassificationResult result; + for (int i = 0; i < run_index; i++) { + high_resolution_clock::time_point start_time = high_resolution_clock::now(); + if (!model.Predict(input_mat, result)) { + std::cout << "Failed to do predict." << std::endl; + return 1; + } + high_resolution_clock::time_point end_time = high_resolution_clock::now(); + auto time_span = duration_cast(end_time - start_time); + time_ms += time_span.count(); + } + std::cout << "Frames per second: " << 1000.0 / time_ms * run_index << std::endl; + return 0; +} + +int TestCapture() { + cv::VideoCapture cap; // 设置摄像头长宽 + cap.set(cv::CAP_PROP_FRAME_WIDTH, 640); + cap.set(cv::CAP_PROP_FRAME_HEIGHT, 480); + // 打开摄像头 + cap.open(0); + + cv::Mat input_mat; + lockzhiner_vision_module::vision::ClassificationResult result; + while (true) { + int read_index = 0; + int time_ms = 0; + for (int i = 0; i < 30; i++) { + high_resolution_clock::time_point start_time = + high_resolution_clock::now(); + cap >> input_mat; + // 判断获取的图片是否为空 + if (input_mat.empty()) { + continue; + } + if (!model.Predict(input_mat, result)) { + std::cout << "Failed to do predict." << std::endl; + return 1; + } + high_resolution_clock::time_point end_time = high_resolution_clock::now(); + auto time_span = duration_cast(end_time - start_time); + time_ms += time_span.count(); + read_index += 1; + std::cout << "confidence is " << result.confidence << ";label_id is " + << result.label_id << std::endl; + } + std::cout << "Frames per second: " << 1000.0 / time_ms * read_index + << std::endl; + return 0; + } +} + +int main(int argc, char *argv[]) { + if (argc != 3) { + std::cerr << "Usage: Test-PaddleClas model_path " << std::endl; + return 1; + } + + if (!model.Initialize(argv[1])) { + std::cout << "Failed to initialize model." << std::endl; + return 1; + } + std::cout << "Initialize runtime succeed." << std::endl; + + std::string argument(argv[2]); + + if (argument == "Capture") { + return TestCapture(); + } else if (argument == "FPS") { + return TestFPS(); + } else { + std::cerr << "Invalid argument: " << argument + << ". Use either 'Capture' or 'FPS'." << std::endl; + return 1; + } + + return 0; +} +``` + +## 4 部署模型 + +### 4.1 配置开发环境 + +在开始这个章节前,请确保你已经按照 [开发环境搭建指南](../../../../docs/introductory_tutorial/cpp_development_environment.md) 正确配置了开发环境。 + +### 4.2 编译项目 + +使用 Docker Destop 打开 LockzhinerVisionModule 容器并执行以下命令来编译项目 + +```bash +# 进入 Demo 目录 +cd /LockzhinerVisionModuleWorkSpace/LockzhinerVisionModule/example/vision/classification/cpp + +# 创建编译目录 +rm -rf build && mkdir build && cd build + +# 配置交叉编译工具链 +export TOOLCHAIN_ROOT_PATH=${PWD}/../../../../../../arm-rockchip830-linux-uclibcgnueabihf + +# 使用 cmake 配置项目 +cmake -DCMAKE_TOOLCHAIN_FILE=../../../../../toolchains/arm-rockchip830-linux-uclibcgnueabihf.toolchain.cmake \ + -DCMAKE_BUILD_TYPE=Release \ + .. + +# 执行编译 +make -j8 +``` + +### 4.3 执行分类模型测试程序 + +参考 [连接设备指南](../../../../docs/introductory_tutorial/connect_device_using_ssh.md) 正确连接 Lockzhiner Vision Module 设备。 + +![](../../../../docs/introductory_tutorial/images/connect_device_using_ssh/ssh_success.png) + +参考之前的例程,将 **Test-PaddleClas** 传输到 Lockzhiner Vision Module 上。将 output 文件夹解压,将 LZ-MobileNetV2_x0_25.rknn 传输到 Lockzhiner Vision Module 上。 + +![](images/sftp.png) + +传输完成后执行以下代码 + +```bash +chmod +x ./Test-PaddleClas +# ./Test-PaddleClas 模型路径 FPS -> 测试模型运行 FPS +./Test-PaddleClas ./LZ-MobileNetV2_x0_25.rknn FPS +# ./Test-PaddleClas 模型路径 Capture -> 测试摄像头获取数据时的模型运行 FPS +./Test-PaddleClas ./LZ-MobileNetV2_x0_25.rknn Capture +``` + +程序将读取摄像头数据,使用神经网络检测后输出置信度和类别: + +![](images/result_0.png) diff --git a/example/vision/classification/cpp/images/result_0.png b/example/vision/classification/cpp/images/result_0.png new file mode 100644 index 0000000000000000000000000000000000000000..8cc504366b9aab8580b2f01764f088d12cdc7600 Binary files /dev/null and b/example/vision/classification/cpp/images/result_0.png differ diff --git a/example/vision/classification/cpp/images/sftp.png b/example/vision/classification/cpp/images/sftp.png new file mode 100644 index 0000000000000000000000000000000000000000..91ecd55a72c749eafdc1424aa912467da9fda5fa Binary files /dev/null and b/example/vision/classification/cpp/images/sftp.png differ diff --git a/example/vision/classification/cpp/test_paddleclas.cpp b/example/vision/classification/cpp/test_paddleclas.cpp new file mode 100644 index 0000000000000000000000000000000000000000..263f4af7089926b25e98827a41fa4e21e0f7cca6 --- /dev/null +++ b/example/vision/classification/cpp/test_paddleclas.cpp @@ -0,0 +1,104 @@ +#include + +#include +#include // for std::rand and std::srand +#include // for std::time +#include +#include + +using namespace std::chrono; + +lockzhiner_vision_module::vision::PaddleClas model; + +int TestFPS() { + // 创建一个空的3通道Mat,宽640,高480,类型为CV_8UC3 + std::srand(static_cast(std::time(nullptr))); + cv::Mat input_mat(480, 640, CV_8UC3); + for (int i = 0; i < input_mat.rows; ++i) { + for (int j = 0; j < input_mat.cols; ++j) { + input_mat.at(i, j)[0] = std::rand() % 256; // B通道 + input_mat.at(i, j)[1] = std::rand() % 256; // G通道 + input_mat.at(i, j)[2] = std::rand() % 256; // R通道 + } + } + + constexpr int run_index = 1000; + int time_ms = 0; + lockzhiner_vision_module::vision::ClassificationResult result; + for (int i = 0; i < run_index; i++) { + high_resolution_clock::time_point start_time = high_resolution_clock::now(); + if (!model.Predict(input_mat, result)) { + std::cout << "Failed to do predict." << std::endl; + return 1; + } + high_resolution_clock::time_point end_time = high_resolution_clock::now(); + auto time_span = duration_cast(end_time - start_time); + time_ms += time_span.count(); + } + std::cout << "Frames per second: " << 1000.0 / time_ms * run_index << std::endl; + return 0; +} + +int TestCapture() { + cv::VideoCapture cap; // 设置摄像头长宽 + cap.set(cv::CAP_PROP_FRAME_WIDTH, 640); + cap.set(cv::CAP_PROP_FRAME_HEIGHT, 480); + // 打开摄像头 + cap.open(0); + + cv::Mat input_mat; + lockzhiner_vision_module::vision::ClassificationResult result; + while (true) { + int read_index = 0; + int time_ms = 0; + for (int i = 0; i < 30; i++) { + high_resolution_clock::time_point start_time = + high_resolution_clock::now(); + cap >> input_mat; + // 判断获取的图片是否为空 + if (input_mat.empty()) { + continue; + } + if (!model.Predict(input_mat, result)) { + std::cout << "Failed to do predict." << std::endl; + return 1; + } + high_resolution_clock::time_point end_time = high_resolution_clock::now(); + auto time_span = duration_cast(end_time - start_time); + time_ms += time_span.count(); + read_index += 1; + std::cout << "confidence is " << result.confidence << ";label_id is " + << result.label_id << std::endl; + } + std::cout << "Frames per second: " << 1000.0 / time_ms * read_index + << std::endl; + return 0; + } +} + +int main(int argc, char *argv[]) { + if (argc != 3) { + std::cerr << "Usage: Test-PaddleClas model_path " << std::endl; + return 1; + } + + if (!model.Initialize(argv[1])) { + std::cout << "Failed to initialize model." << std::endl; + return 1; + } + std::cout << "Initialize runtime succeed." << std::endl; + + std::string argument(argv[2]); + + if (argument == "Capture") { + return TestCapture(); + } else if (argument == "FPS") { + return TestFPS(); + } else { + std::cerr << "Invalid argument: " << argument + << ". Use either 'Capture' or 'FPS'." << std::endl; + return 1; + } + + return 0; +} \ No newline at end of file diff --git a/example/vision/classification/images/Labelme.png b/example/vision/classification/images/Labelme.png new file mode 100644 index 0000000000000000000000000000000000000000..c2a962c202424919a3215e91fc1cb04e66d4e7ec Binary files /dev/null and b/example/vision/classification/images/Labelme.png differ diff --git a/example/vision/classification/images/Labelme_Dataset.png b/example/vision/classification/images/Labelme_Dataset.png new file mode 100644 index 0000000000000000000000000000000000000000..42de032b5a0958bbd8bcef7eb66ddb78ed0de4fe Binary files /dev/null and b/example/vision/classification/images/Labelme_Dataset.png differ diff --git a/example/vision/classification/images/annotate_images.png b/example/vision/classification/images/annotate_images.png new file mode 100644 index 0000000000000000000000000000000000000000..acc4dd605c751e922ff9e4fe20702cd72d364b8d Binary files /dev/null and b/example/vision/classification/images/annotate_images.png differ diff --git a/example/vision/classification/images/bandzip_0.png b/example/vision/classification/images/bandzip_0.png new file mode 100644 index 0000000000000000000000000000000000000000..3ec0bbd4b6607b4fd3ac54086953c1a606a6c886 Binary files /dev/null and b/example/vision/classification/images/bandzip_0.png differ diff --git a/example/vision/classification/images/bandzip_1.png b/example/vision/classification/images/bandzip_1.png new file mode 100644 index 0000000000000000000000000000000000000000..f2d9c38f5d06281df922825048c86efac936a7c2 Binary files /dev/null and b/example/vision/classification/images/bandzip_1.png differ diff --git a/example/vision/classification/images/bandzip_2.png b/example/vision/classification/images/bandzip_2.png new file mode 100644 index 0000000000000000000000000000000000000000..797934adfd9632056a2d0907b34f06c22a59df59 Binary files /dev/null and b/example/vision/classification/images/bandzip_2.png differ diff --git a/example/vision/classification/images/bandzip_3.png b/example/vision/classification/images/bandzip_3.png new file mode 100644 index 0000000000000000000000000000000000000000..0e73a9b59cb9845c0606de5ab11c6c7736c2862c Binary files /dev/null and b/example/vision/classification/images/bandzip_3.png differ diff --git a/example/vision/classification/images/capture_images.png b/example/vision/classification/images/capture_images.png new file mode 100644 index 0000000000000000000000000000000000000000..b5b670940b65411da276828b9d6fcac7184a79e9 Binary files /dev/null and b/example/vision/classification/images/capture_images.png differ diff --git a/example/vision/classification/images/cmd.png b/example/vision/classification/images/cmd.png new file mode 100644 index 0000000000000000000000000000000000000000..21b8b1bfa6cb9fd94aeee2cda5b1db107fd40d42 Binary files /dev/null and b/example/vision/classification/images/cmd.png differ diff --git a/example/vision/classification/images/config_dataset_0.png b/example/vision/classification/images/config_dataset_0.png new file mode 100644 index 0000000000000000000000000000000000000000..7d737fa3757da256fd0b5be1a45aea295b28763d Binary files /dev/null and b/example/vision/classification/images/config_dataset_0.png differ diff --git a/example/vision/classification/images/config_dataset_1.png b/example/vision/classification/images/config_dataset_1.png new file mode 100644 index 0000000000000000000000000000000000000000..0c381c55298151412ccefb86dd38343b2f2743aa Binary files /dev/null and b/example/vision/classification/images/config_dataset_1.png differ diff --git a/example/vision/classification/images/config_dataset_2.png b/example/vision/classification/images/config_dataset_2.png new file mode 100644 index 0000000000000000000000000000000000000000..b6b079f49722f963ab862da9fe853dfe87358c2c Binary files /dev/null and b/example/vision/classification/images/config_dataset_2.png differ diff --git a/example/vision/classification/images/config_dataset_3.png b/example/vision/classification/images/config_dataset_3.png new file mode 100644 index 0000000000000000000000000000000000000000..073d7567adf1cc082ccec4f4da16bad077f77c6d Binary files /dev/null and b/example/vision/classification/images/config_dataset_3.png differ diff --git a/example/vision/classification/images/config_dataset_4.png b/example/vision/classification/images/config_dataset_4.png new file mode 100644 index 0000000000000000000000000000000000000000..41da3473662da20e005c708ea85185ac43267e83 Binary files /dev/null and b/example/vision/classification/images/config_dataset_4.png differ diff --git a/example/vision/classification/images/config_project_0.png b/example/vision/classification/images/config_project_0.png new file mode 100644 index 0000000000000000000000000000000000000000..9477c8e705d3d6a74fb3cd2cd2fa5f501bed61de Binary files /dev/null and b/example/vision/classification/images/config_project_0.png differ diff --git a/example/vision/classification/images/config_project_1.png b/example/vision/classification/images/config_project_1.png new file mode 100644 index 0000000000000000000000000000000000000000..676f7d5be5cc84697ed4b26e783d7c85b1e614de Binary files /dev/null and b/example/vision/classification/images/config_project_1.png differ diff --git a/example/vision/classification/images/config_project_2.png b/example/vision/classification/images/config_project_2.png new file mode 100644 index 0000000000000000000000000000000000000000..e400d1d98472dfc4fe91b6b827b02a8ce0ad97d4 Binary files /dev/null and b/example/vision/classification/images/config_project_2.png differ diff --git a/example/vision/classification/images/config_project_3.png b/example/vision/classification/images/config_project_3.png new file mode 100644 index 0000000000000000000000000000000000000000..06d13232e1cc3052471241b387e39d98bc09698f Binary files /dev/null and b/example/vision/classification/images/config_project_3.png differ diff --git a/example/vision/classification/images/download.png b/example/vision/classification/images/download.png new file mode 100644 index 0000000000000000000000000000000000000000..dd93e8e65057246f4badcb4c0c72b22d961341e6 Binary files /dev/null and b/example/vision/classification/images/download.png differ diff --git a/example/vision/classification/images/flags.png b/example/vision/classification/images/flags.png new file mode 100644 index 0000000000000000000000000000000000000000..f74145f3a5dcac6e62a07e90ecb1b392d1811674 Binary files /dev/null and b/example/vision/classification/images/flags.png differ diff --git a/example/vision/classification/images/fork_0.png b/example/vision/classification/images/fork_0.png new file mode 100644 index 0000000000000000000000000000000000000000..493d017a330c1bf3ada2d522a5865341d1e273fd Binary files /dev/null and b/example/vision/classification/images/fork_0.png differ diff --git a/example/vision/classification/images/fork_1.png b/example/vision/classification/images/fork_1.png new file mode 100644 index 0000000000000000000000000000000000000000..390b5e9a9a82cbccdcff049bbd28427324c948d2 Binary files /dev/null and b/example/vision/classification/images/fork_1.png differ diff --git a/example/vision/classification/images/fork_2.png b/example/vision/classification/images/fork_2.png new file mode 100644 index 0000000000000000000000000000000000000000..b9a152c3b62ae18a65a4975b3cece0d09ac347cf Binary files /dev/null and b/example/vision/classification/images/fork_2.png differ diff --git a/example/vision/classification/images/images.png b/example/vision/classification/images/images.png new file mode 100644 index 0000000000000000000000000000000000000000..53006311fec7258e155401dbab03c38c419483ec Binary files /dev/null and b/example/vision/classification/images/images.png differ diff --git a/example/vision/classification/images/images_annocations_flags.png b/example/vision/classification/images/images_annocations_flags.png new file mode 100644 index 0000000000000000000000000000000000000000..314fef93084d077729de78f5971a0dedb77dcee2 Binary files /dev/null and b/example/vision/classification/images/images_annocations_flags.png differ diff --git a/example/vision/classification/images/powershell.png b/example/vision/classification/images/powershell.png new file mode 100644 index 0000000000000000000000000000000000000000..130ca76798d794fde0f9c7e3cc2c23f87ce19d7a Binary files /dev/null and b/example/vision/classification/images/powershell.png differ diff --git a/example/vision/classification/images/run_project_0.png b/example/vision/classification/images/run_project_0.png new file mode 100644 index 0000000000000000000000000000000000000000..92131381728ba39ed4f1d5517f92fbab9adf163f Binary files /dev/null and b/example/vision/classification/images/run_project_0.png differ diff --git a/example/vision/classification/images/run_project_1.png b/example/vision/classification/images/run_project_1.png new file mode 100644 index 0000000000000000000000000000000000000000..383d6e6d78f61dbbbaefe6be0debd8463ab4293d Binary files /dev/null and b/example/vision/classification/images/run_project_1.png differ diff --git a/example/vision/classification/images/run_project_2.png b/example/vision/classification/images/run_project_2.png new file mode 100644 index 0000000000000000000000000000000000000000..5d4162fd219071a7eb9d8f619fabaae9a84abd23 Binary files /dev/null and b/example/vision/classification/images/run_project_2.png differ diff --git a/example/vision/classification/images/run_project_3.png b/example/vision/classification/images/run_project_3.png new file mode 100644 index 0000000000000000000000000000000000000000..fa989d7def91daeea795612634ccde06c29cd250 Binary files /dev/null and b/example/vision/classification/images/run_project_3.png differ diff --git a/example/vision/classification/images/run_project_4.png b/example/vision/classification/images/run_project_4.png new file mode 100644 index 0000000000000000000000000000000000000000..49dd4cf449f877d3f74d496ce0f5d1364439549e Binary files /dev/null and b/example/vision/classification/images/run_project_4.png differ diff --git a/example/vision/classification/images/sourceForge.png b/example/vision/classification/images/sourceForge.png new file mode 100644 index 0000000000000000000000000000000000000000..4b9d3d3ede87112602db99bf324186e700ac8e79 Binary files /dev/null and b/example/vision/classification/images/sourceForge.png differ diff --git a/example/vision/classification/images/start_project_0.png b/example/vision/classification/images/start_project_0.png new file mode 100644 index 0000000000000000000000000000000000000000..a4bf2ab530048ee23401ac91f14579850fe9468a Binary files /dev/null and b/example/vision/classification/images/start_project_0.png differ diff --git a/example/vision/classification/images/start_project_1.png b/example/vision/classification/images/start_project_1.png new file mode 100644 index 0000000000000000000000000000000000000000..cd1e037fe95aacda5fb0670f80dd6c8d98b36498 Binary files /dev/null and b/example/vision/classification/images/start_project_1.png differ diff --git a/example/vision/classification/images/start_project_2.png b/example/vision/classification/images/start_project_2.png new file mode 100644 index 0000000000000000000000000000000000000000..18b4127ae93b8616843b129a6e60fe43ff012fc9 Binary files /dev/null and b/example/vision/classification/images/start_project_2.png differ diff --git a/example/vision/classification/images/start_project_3.png b/example/vision/classification/images/start_project_3.png new file mode 100644 index 0000000000000000000000000000000000000000..11cd7a28927d27c96bc8e46f4dfabba19bfb482c Binary files /dev/null and b/example/vision/classification/images/start_project_3.png differ diff --git a/example/vision/classification/python/README.md b/example/vision/classification/python/README.md new file mode 100644 index 0000000000000000000000000000000000000000..75869211418b8888c64a733aa0c8b232eb91b5c6 --- /dev/null +++ b/example/vision/classification/python/README.md @@ -0,0 +1,184 @@ +

凌智视觉模块分类模型 Python 部署指南

+ + +发布版本:V0.0.0 + +日期:2024-09-11 + +文件密级:□绝密 □秘密 □内部资料 ■公开 + +--- + +**免责声明** + +本文档按**现状**提供,福州凌睿智捷电子有限公司(以下简称**本公司**)不对本文档中的任何陈述、信息和内容的准确性、可靠性、完整性、适销性、适用性及非侵权性提供任何明示或暗示的声明或保证。本文档仅作为使用指导的参考。 + +由于产品版本升级或其他原因,本文档可能在未经任何通知的情况下不定期更新或修改。 + +**读者对象** + +本教程适用于以下工程师: + +- 技术支持工程师 +- 软件开发工程师 + +**修订记录** + +| **日期** | **版本** | **作者** | **修改说明** | +| :--------- | -------- | -------- | ------------ | +| 2024/09/11 | 0.0.0 | 郑必城 | 初始版本 | + + +## 1 简介 + +接下来让我们基于 Python 来部署 PaddleClas 分类模型。在开始本章节前,请确保你已经参考 [凌智视觉模块分类模型部署指南](../README.md) 对模型进行了充分训练。如果你需要使用 C++ 来部署 PaddleClas 请参考 [凌智视觉模块分类模型 C++ 部署指南](../cpp/README.md)。 + + +## 2 Python API 文档 + + +```python +class ClassificationResult: + """ + 分类结果类,用于封装和处理分类结果数据。 + + 该类主要提供了一个包装层,用于访问和管理由视觉模块产生的分类结果。 + 它包含了两个属性: label_id 和 confidence ,分别表示分类的标签 ID 和置信度。 + """ + + def __init__(self): + """ + 构造函数,初始化分类结果对象。 + + 这里会创建一个新的 vision.ClassificationResult 对象,并将其赋值给 self.classification_result。 + """ + self.classification_result = vision.ClassificationResult() + + @property + def label_id(self): + """ + 获取分类结果的标签 ID。 + + Returns: + int: 分类结果的标签 ID ,表示识别出的物体的类别。 + """ + return self.classification_result.label_id + + @property + def confidence(self): + """ + 获取分类结果的标签 ID。 + + Returns: + float: 分类结果的置信度,表示识别结果的可靠程度,范围为 0 到 1。 + """ + return self.classification_result.confidence + + +class PaddleClas: + """ + PaddleClas 类 - 用于图像分类的 PaddlePaddle 模型封装。 + + 该类封装了 PaddlePaddle 框架下的图像分类模型,提供了初始化和预测的方法。 + """ + + def __init__(self): + """ + 构造函数 - 初始化 PaddleClas 对象。 + + 创建一个新的 PaddleClas 实例, 并初始化内部的 PaddlePaddle 模型。 + """ + self.model = vision.PaddleClas() + + def initialize(self, model_path): + """ + 初始化模型 - 加载预训练的PaddlePaddle模型。 + + Args: + model_path (str): 模型文件的路径。 + + Returns: + bool: 初始化是否成功。 + """ + return self.model.initialize(model_path) + + def predict(self, input_mat): + """ + 进行预测 - 使用加载的模型对输入数据进行分类预测。 + + Args: + input_mat (cv2.Mat): 输入的图像数据,通常是一个 cv2.Mat 变量。 + + Returns: + ClassificationResult: 预测结果对象,包含了分类的标签、置信度等信息。 + """ + return self.model.predict(input_mat) +``` + +## 3 项目介绍 + +为了方便大家入手,我们做了一个简易的图像分类例程。该程序可以使用摄像头进行端到端推理。 + +```python +from lockzhiner_vision_module.cv2 import VideoCapture +from lockzhiner_vision_module.vision import PaddleClas +import time + +if __name__ == "__main__": + model = PaddleClas() + if model.initialize("LZ-MobileNetV2_x0_25.rknn") is False: + print("Failed to initialize PaddleClas") + exit(1) + + video_capture = VideoCapture() + if video_capture.open(0) is False: + print("Failed to open capture") + exit(1) + + while True: + read_index = 0 + total_time_ms = 0 + for i in range(30): + ret, mat = video_capture.read() + if ret is False: + continue + + start_time = time.time() + result = model.predict(mat) + end_time = time.time() + total_time_ms += (end_time - start_time) + read_index += 1 + print(result.label_id, result.confidence) + print(f"FPS is {1.0 / (total_time_ms/read_index)}") +``` + +## 4 上传并测试 Python 程序 + +### 4.1 准备工作 + +在开始这个章节前,请确保你已经按照 [开发环境搭建指南](../../../../docs/introductory_tutorial/python_development_environment.md) 正确配置了开发环境。 + +### 4.2 连接设备并测试模型 + +参考 [连接设备指南](../../../../docs/introductory_tutorial/connect_device_using_ssh.md) 正确连接 Lockzhiner Vision Module 设备。 + +![](../../../../docs/introductory_tutorial/images/connect_device_using_ssh/ssh_success.png) + +请使用 Electerm Sftp 依次上传以下两个文件: + +* 进入存放 **test_paddleclas.py** 脚本文件的目录,将 **test_paddleclas.py** 上传到 Lockzhiner Vision Module +* 进入存放 **LZ-MobileNetV2_x0_25.rknn(也可能是其他模型)** 模型存放的目录(模型存放在训练模型后下载的 output 文件夹内),将 **LZ-MobileNetV2_x0_25.rknn** 上传到 Lockzhiner Vision Module + +![](images/stfp_0.png) + +![](images/stfp_1.png) + +请使用 Electerm Ssh 并在命令行中执行以下命令: + +```bash +python test_paddleclas.py +``` + +运行程序后,屏幕上开始打印标签索引,分类置信度,并在一段时间后输出 FPS 值 + +![alt text](result_0.png) \ No newline at end of file diff --git a/example/vision/classification/python/images/result_0.png b/example/vision/classification/python/images/result_0.png new file mode 100644 index 0000000000000000000000000000000000000000..59eb9bfd76afffbf51e6d15fb3c1ec8a9e3e4e16 Binary files /dev/null and b/example/vision/classification/python/images/result_0.png differ diff --git a/example/vision/classification/python/images/stfp_0.png b/example/vision/classification/python/images/stfp_0.png new file mode 100644 index 0000000000000000000000000000000000000000..66edc059c9fced317a80dc3b6c0c075e4f729c2b Binary files /dev/null and b/example/vision/classification/python/images/stfp_0.png differ diff --git a/example/vision/classification/python/images/stfp_1.png b/example/vision/classification/python/images/stfp_1.png new file mode 100644 index 0000000000000000000000000000000000000000..fdd084e1b2cc5c0e0d196d53e786ea50fd25dfc9 Binary files /dev/null and b/example/vision/classification/python/images/stfp_1.png differ diff --git a/example/vision/classification/python/test_paddleclas.py b/example/vision/classification/python/test_paddleclas.py new file mode 100644 index 0000000000000000000000000000000000000000..25dc77f2fe7c369a4f8a56a4d07cd2988d2f76a8 --- /dev/null +++ b/example/vision/classification/python/test_paddleclas.py @@ -0,0 +1,30 @@ +from lockzhiner_vision_module.cv2 import VideoCapture +from lockzhiner_vision_module.vision import PaddleClas +import time + +if __name__ == "__main__": + model = PaddleClas() + if model.initialize("LZ-MobileNetV2_x0_25.rknn") is False: + print("Failed to initialize PaddleClas") + exit(1) + + video_capture = VideoCapture() + if video_capture.open(0) is False: + print("Failed to open capture") + exit(1) + + while True: + read_index = 0 + total_time_ms = 0 + for i in range(30): + start_time = time.time() + ret, mat = video_capture.read() + if ret is False: + continue + + result = model.predict(mat) + end_time = time.time() + total_time_ms += (end_time - start_time) + read_index += 1 + print(result.label_id, result.confidence) + print(f"FPS is {1.0 / (total_time_ms/read_index)}") \ No newline at end of file diff --git a/example/vision/images/ai_studio_0.png b/example/vision/images/ai_studio_0.png new file mode 100644 index 0000000000000000000000000000000000000000..9cb0699aa80250a86213f431f7a8fe09f2d1f5f7 Binary files /dev/null and b/example/vision/images/ai_studio_0.png differ diff --git a/example/vision/images/ai_studio_1.png b/example/vision/images/ai_studio_1.png new file mode 100644 index 0000000000000000000000000000000000000000..90e4622d4212992f5b6d0ec2d8f439b57382c09b Binary files /dev/null and b/example/vision/images/ai_studio_1.png differ diff --git a/example/vision/images/ai_studio_2.png b/example/vision/images/ai_studio_2.png new file mode 100644 index 0000000000000000000000000000000000000000..687bdfcae1a7c765d272afbfa5e8d12e20b93833 Binary files /dev/null and b/example/vision/images/ai_studio_2.png differ diff --git a/example/vision/images/ai_studio_3.png b/example/vision/images/ai_studio_3.png new file mode 100644 index 0000000000000000000000000000000000000000..89843b22f854537a593474b7752335b220e9a212 Binary files /dev/null and b/example/vision/images/ai_studio_3.png differ diff --git a/example/vision/images/ai_studio_4.png b/example/vision/images/ai_studio_4.png new file mode 100644 index 0000000000000000000000000000000000000000..cf50db2355a93d4bcba40e7eda729877b410b4c3 Binary files /dev/null and b/example/vision/images/ai_studio_4.png differ diff --git a/images/issues_completed.png b/images/issues_completed.png new file mode 100644 index 0000000000000000000000000000000000000000..7df35bc53a608d669149c30a833ba67239c2682f Binary files /dev/null and b/images/issues_completed.png differ diff --git a/images/issues_feedback.png b/images/issues_feedback.png new file mode 100644 index 0000000000000000000000000000000000000000..434b9759c8cf562453a6e5d6e642b9b4c5e84ad4 Binary files /dev/null and b/images/issues_feedback.png differ diff --git a/images/periphery.png b/images/periphery.png new file mode 100644 index 0000000000000000000000000000000000000000..8d78b9ffafd5f4f7df66e3733c4f2527fbd704d7 Binary files /dev/null and b/images/periphery.png differ diff --git a/toolchains/arm-rockchip830-linux-uclibcgnueabihf.toolchain.cmake b/toolchains/arm-rockchip830-linux-uclibcgnueabihf.toolchain.cmake new file mode 100644 index 0000000000000000000000000000000000000000..4442bf2181af6784b93cbe9bcf14756f0245d608 --- /dev/null +++ b/toolchains/arm-rockchip830-linux-uclibcgnueabihf.toolchain.cmake @@ -0,0 +1,24 @@ +set(CMAKE_SYSTEM_NAME Linux) +set(CMAKE_SYSTEM_PROCESSOR arm) + +if(DEFINED ENV{TOOLCHAIN_ROOT_PATH}) + file(TO_CMAKE_PATH $ENV{TOOLCHAIN_ROOT_PATH} TOOLCHAIN_ROOT_PATH) +else() + message(FATAL_ERROR "TOOLCHAIN_ROOT_PATH env must be defined") +endif() + +set(TOOLCHAIN_ROOT_PATH ${TOOLCHAIN_ROOT_PATH} CACHE STRING "root path to toolchain") + +set(CMAKE_C_COMPILER "${TOOLCHAIN_ROOT_PATH}/bin/arm-rockchip830-linux-uclibcgnueabihf-gcc") +set(CMAKE_CXX_COMPILER "${TOOLCHAIN_ROOT_PATH}/bin/arm-rockchip830-linux-uclibcgnueabihf-g++") + +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) + +set(CMAKE_C_FLAGS "-march=armv7-a -mfloat-abi=hard -mfpu=neon") +set(CMAKE_CXX_FLAGS "-march=armv7-a -mfloat-abi=hard -mfpu=neon") + +# cache flags +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS}" CACHE STRING "c flags") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}" CACHE STRING "c++ flags") diff --git a/utils/export.py b/utils/export.py new file mode 100644 index 0000000000000000000000000000000000000000..9f498d48f84a93a6007b9092d60c6b829469f261 --- /dev/null +++ b/utils/export.py @@ -0,0 +1,69 @@ +import os +import yaml +import argparse +from rknn.api import RKNN +from onnxslim import slim +import onnx + +def get_config(): + parser = argparse.ArgumentParser() + parser.add_argument("--verbose", default="Debug", help="rknntoolkit verbose") + parser.add_argument("--config_path", required=True, help="The path of model config file") + parser.add_argument("--model_load_path", required=True, help="The path of onnx model file") + parser.add_argument("--target_platform", required=True, help="The target platform") + parser.add_argument("--model_save_path", required=True, help="The path of rknn model save") + args = parser.parse_args() + return args + + +if __name__ == "__main__": + config = get_config() + with open(config.config_path) as file: + file_data = file.read() + yaml_config = yaml.safe_load(file_data) + print(yaml_config) + model = RKNN(config.verbose) + + # Prune ONNX Model + print('--> Prune ONNX Model') + slim_prune_onnx_model = slim(config.model_load_path, inputs=yaml_config["load_onnx"]["inputs"], outputs=yaml_config["load_onnx"]["outputs"]) + onnx.save(slim_prune_onnx_model, "/tmp/slim_prune_onnx_model.onnx") + print('done') + + # Config + print('--> Config') + mean_values = [255 * mean for mean in yaml_config["config"]["mean"]] + std_values = [255 * std for std in yaml_config["config"]["std"]] + target_platform = config.target_platform + model.config(mean_values=mean_values, std_values=std_values, target_platform=target_platform) + print('done') + + # Load ONNX model + print('--> Load ONNX model') + model_path = "/tmp/slim_prune_onnx_model.onnx" + inputs = yaml_config["load_onnx"]["inputs"] + input_size_list = yaml_config["load_onnx"]["input_size_list"] + outputs = yaml_config["load_onnx"]["outputs"] + ret = model.load_onnx(model=model_path, inputs=inputs, input_size_list=input_size_list, outputs=outputs) + assert ret == 0, "Load model failed!" + print('done') + + # Build model + print('--> Build model') + do_quantization = yaml_config["build"]["do_quantization"] + dataset = yaml_config["build"]["dataset"] + ret = model.build(do_quantization=do_quantization, dataset=dataset) + assert ret == 0, "Build model failed!" + print('done') + + # Init Runtime + print('--> Init Runtime') + ret = model.init_runtime() + assert ret == 0, "Init runtime environment failed!" + print('done') + + # Export + model_save_path = config.model_save_path + ret = model.export_rknn(model_save_path) + assert ret == 0, "Export rknn model failed!" + print("Export OK!") \ No newline at end of file diff --git a/utils/paddle/infer_paddle_model_shape.py b/utils/paddle/infer_paddle_model_shape.py new file mode 100644 index 0000000000000000000000000000000000000000..b212adee9fc279c0f422edd303ffd54f2a958ca8 --- /dev/null +++ b/utils/paddle/infer_paddle_model_shape.py @@ -0,0 +1,78 @@ +import argparse +import paddle +import paddle.base as base +import paddle.static as static + + +def process_old_ops_desc(program): + for i in range(len(program.blocks[0].ops)): + if program.blocks[0].ops[i].type == "matmul": + if not program.blocks[0].ops[i].has_attr("head_number"): + program.blocks[0].ops[i]._set_attr("head_number", 1) + + +def infer_shape(program, input_shape_dict): + paddle.enable_static() + + OP_WITHOUT_KERNEL_SET = { + 'feed', 'fetch', 'recurrent', 'go', 'rnn_memory_helper_grad', + 'conditional_block', 'while', 'send', 'recv', 'listen_and_serv', + 'fl_listen_and_serv', 'ncclInit', 'select', 'checkpoint_notify', + 'gen_bkcl_id', 'c_gen_bkcl_id', 'gen_nccl_id', 'c_gen_nccl_id', + 'c_comm_init', 'c_sync_calc_stream', 'c_sync_comm_stream', + 'queue_generator', 'dequeue', 'enqueue', 'heter_listen_and_serv', + 'c_wait_comm', 'c_wait_compute', 'c_gen_hccl_id', 'c_comm_init_hccl', + 'copy_cross_scope' + } + model_version = program.desc._version() + paddle_version = paddle.__version__ + major_ver = model_version // 1000000 + minor_ver = (model_version - major_ver * 1000000) // 1000 + patch_ver = model_version - major_ver * 1000000 - minor_ver * 1000 + model_version = "{}.{}.{}".format(major_ver, minor_ver, patch_ver) + if model_version != paddle_version: + print( + "[WARNING] The model is saved by paddlepaddle v{}, but now your paddlepaddle is version of {}, this difference may cause error, it is recommend you reinstall a same version of paddlepaddle for this model". + format(model_version, paddle_version)) + for k, v in input_shape_dict.items(): + program.blocks[0].var(k).desc.set_shape(v) + for i in range(len(program.blocks)): + for j in range(len(program.blocks[0].ops)): + if program.blocks[i].ops[j].type in OP_WITHOUT_KERNEL_SET: + continue + program.blocks[i].ops[j].desc.infer_shape(program.blocks[i].desc) + + +def parse_arguments(): + parser = argparse.ArgumentParser() + parser.add_argument( + '--model_path', + required=True, + help='Directory path to input model + model name without suffix.') + parser.add_argument( + '--input_shape_dict', required=True, help="The new shape information.") + parser.add_argument( + '--save_path', + required=True, + help='Directory path to save model + model name without suffix.') + return parser.parse_args() + + +if __name__ == '__main__': + args = parse_arguments() + paddle.enable_static() + input_shape_dict_str = args.input_shape_dict + input_shape_dict = eval(input_shape_dict_str) + print("Start to load paddle model...") + exe = base.Executor(paddle.CPUPlace()) + [program, feed_target_names, fetch_targets] = static.io.load_inference_model(args.model_path, exe) + process_old_ops_desc(program) + infer_shape(program, input_shape_dict) + + feed_vars = [program.global_block().var(name) for name in feed_target_names] + static.io.save_inference_model( + args.save_path, + feed_vars=feed_vars, + fetch_vars=fetch_targets, + executor=exe, + program=program) \ No newline at end of file diff --git a/utils/paddle/prune_paddle_model.py b/utils/paddle/prune_paddle_model.py new file mode 100644 index 0000000000000000000000000000000000000000..5bc88d2b1baacc0a5e69c8b9ec761b2e4d15e4dc --- /dev/null +++ b/utils/paddle/prune_paddle_model.py @@ -0,0 +1,117 @@ +import argparse +import sys +import paddle +import paddle.base.core as core +import paddle.static as static +import os + + +def prepend_feed_ops(program, feed_target_names): + if len(feed_target_names) == 0: + return + + global_block = program.global_block() + feed_var = global_block.create_var( + name='feed', + type=core.VarDesc.VarType.FEED_MINIBATCH, + persistable=True) + + for i, name in enumerate(feed_target_names): + if not global_block.has_var(name): + print( + "The input[{i}]: '{name}' doesn't exist in pruned inference program, which will be ignored in new saved model.". + format( + i=i, name=name)) + continue + out = global_block.var(name) + global_block._prepend_op( + type='feed', + inputs={'X': [feed_var]}, + outputs={'Out': [out]}, + attrs={'col': i}) + + +def append_fetch_ops(program, fetch_target_names): + """ + In this palce, we will add the fetch op + """ + global_block = program.global_block() + fetch_var = global_block.create_var( + name='fetch', + type=core.VarDesc.VarType.FETCH_LIST, + persistable=True) + print("the len of fetch_target_names:%d" % (len(fetch_target_names))) + for i, name in enumerate(fetch_target_names): + global_block.append_op( + type='fetch', + inputs={'X': [name]}, + outputs={'Out': [fetch_var]}, + attrs={'col': i}) + + +def insert_by_op_type(program, op_names, op_type): + global_block = program.global_block() + need_to_remove_op_index = list() + for i, op in enumerate(global_block.ops): + if op.type == op_type: + need_to_remove_op_index.append(i) + print(need_to_remove_op_index) + for index in need_to_remove_op_index[::-1]: + global_block._remove_op(index) + program.desc.flush() + + if op_type == "feed": + prepend_feed_ops(program, op_names) + else: + append_fetch_ops(program, op_names) + program.desc.flush() + + +def parse_arguments(): + parser = argparse.ArgumentParser() + parser.add_argument('--model_dir', required=True, help='Path of directory saved the input model.') + parser.add_argument('--model_filename', required=True, help='The input model file name.') + parser.add_argument('--params_filename', required=True, help='The parameters file name.') + parser.add_argument('--input_names', nargs='+', help='The inputs of pruned model.') + parser.add_argument('--output_names', required=True, nargs='+', help='The outputs of pruned model.') + parser.add_argument('--save_dir', required=True, help='Path of directory to save the new exported model.') + return parser.parse_args() + + +if __name__ == '__main__': + args = parse_arguments() + if len(set(args.output_names)) < len(args.output_names): + print( + "[ERROR] There's dumplicate name in --output_names, which is not allowed." + ) + sys.exit(-1) + + paddle.enable_static() + print("Start to load paddle model...") + exe = static.Executor(paddle.CPUPlace()) + [program, feed_target_names, fetch_targets] = static.io.load_inference_model( + args.model_dir, + exe, + model_filename=args.model_filename, + params_filename=args.params_filename) + + if args.input_names is not None: + insert_by_op_type(program, args.input_names, 'feed') + feed_vars = [program.global_block().var(name) for name in args.input_names] + else: + feed_vars = [program.global_block().var(name) for name in feed_target_names] + + if args.output_names is not None: + insert_by_op_type(program, args.output_names, 'fetch') + fetch_vars = [program.global_block().var(out_name) for out_name in args.output_names] + else: + fetch_vars = [out_var for out_var in fetch_targets] + + model_name = args.model_filename.split(".")[0] + path_prefix = os.path.join(args.save_dir, model_name) + static.io.save_inference_model( + path_prefix=path_prefix, + feed_vars=feed_vars, + fetch_vars=fetch_vars, + executor=exe, + program=program)