EdgeX Foundry - MQTT 设备服务

文章目录

    • 一、MQTT 设备服务
      • 1.概述
      • 2.服务配置
      • 3.协议属性
      • 4.多级 Topics
        • 4.1.异步数据
        • 4.2.命令
    • 二、连接 MQTT 设备
      • 1.docker-comepse
      • 2.设备配置文件
      • 3.安装自定义配置
      • 4.启动 EdgeX Foundry
      • 5.创建 MQTT 设备模拟器
      • 6.访问 UI
        • 6.1. consul
        • 6.2. EdgeX Console
      • 7.测试
        • 7.1.命令
        • 7.2.事件
        • 7.3.读值

  • EdgeX Foundry
# EdgeX Foundry

https://iothub.org.cn/docs/edgex/
https://iothub.org.cn/docs/edgex/device/service-mqtt/

一、MQTT 设备服务

1.概述

MQTT 设备服务使用 MQTT 协议将设备/传感器连接到 EdgeX。目标设备和此设备服务连接到同一 MQTT 代理并交换异步数据和设备命令的消息。
在这里插入图片描述

EdgeX 与 MQTT 设备通信
在这里插入图片描述

2.服务配置

MQTT 设备服务具有以下配置来实现 MQTT 协议。

ConfigurationDefault ValueDescription
MQTTBrokerInfo.SchematcpThe URL schema
MQTTBrokerInfo.HostlocalhostThe URL host
MQTTBrokerInfo.Port1883The URL port
MQTTBrokerInfo.Qos0Quality of Service 0 (At most once), 1 (At least once) or 2 (Exactly once)
MQTTBrokerInfo.KeepAlive3600Seconds between client ping when no active data flowing to avoid client being disconnected. Must be greater then 2
MQTTBrokerInfo.ClientIddevice-mqttClientId to connect to the broker with
MQTTBrokerInfo.CredentialsRetryTime120The retry times to get the credential
MQTTBrokerInfo.CredentialsRetryWait1The wait time(seconds) when retry to get the credential
MQTTBrokerInfo.ConnEstablishingRetry10The retry times to establish the MQTT connection
MQTTBrokerInfo.ConnRetryWaitTime5The wait time(seconds) when retry to establish the MQTT connection
MQTTBrokerInfo.AuthModenoneIndicates what to use when connecting to the broker. Must be one of “none” , “usernamepassword”
MQTTBrokerInfo.CredentialsPathcredentialsName of the path in secret provider to retrieve your secrets. Must be non-blank.
MQTTBrokerInfo.IncomingTopicincoming/data/#IncomingTopic is used to receive the async value
MQTTBrokerInfo.ResponseTopiccommand/response/#ResponseTopic is used to receive the command response from the device
MQTTBrokerInfo.Writable.ResponseFetchInterval500ResponseFetchInterval specifies the retry interval(milliseconds) to fetch the command response from the MQTT broker

使用环境变量覆盖

用户可以使用 compose 文件中的变量覆盖上述任何配置 environment: 以满足他们的要求,例如:

The user can override any of the above configurations using environment: variables in the compose file to meet their requirement, for example:

# docker-compose.override.yml

  version: '3.7'

  services:
    device-mqtt:
      environment:
        MQTTBROKERINFO_CLIENTID: "my-device-mqtt"
        MQTTBROKERINFO_CONNRETRYWAITTIME: "10"

3.协议属性

此服务为支持 2 路通信的每个已定义设备定义以下协议属性。这些属性位于每个设备定义部分的mqtt键下protocols

PropertyDescription
CommandTopic用于向设备发送命令的基本 MQTT 主题

在这里插入图片描述

4.多级 Topics

在多级 Topics 中,发布的有效载荷中的数据是读值数据。设备和源的名称嵌入到主题中。支持多级主题有两种方式——异步数据和命令。

4.1.异步数据

异步数据发布到主题,incoming/data/{device-name}/{source-name}其中:

  • device-name 是发送读值的设备的名称
  • source-name 是已发布数据的命令或资源名称
  • 当源名称与命令名称匹配时,发布的数据必须是 JSON 对象,并且命令中指定的资源名称为字段名称。

在这里插入图片描述

  • 当source-name 只匹配资源名称的情况下,发布的数据可以是资源的读取值,也可以是以资源名称作为字段名称的 JSON 对象。
    在这里插入图片描述
4.2.命令

发送到设备的命令将针对以下主题发送 command/{device-name}/{command-name}/{method}/{uuid}

  • device-name 是将接收命令的设备的名称

  • command-name 是发送到设备的命令的名称

  • method 是命令的类型,get或者set

  • uuid 是命令请求的唯一标识符

  • 设置命令

如果命令方法是 a set,则发布的有效负载包含一个 JSON 对象,其中包含资源名称和用于设置这些资源的值。作为响应,设备应在主题上发布空响应 command/response/{uuid},其中 uuid 与命令请求主题中发送的唯一标识符匹配。
在这里插入图片描述

  • 获取命令

如果命令方法是 a get,则发布的有效负载为空,并且设备预计将发布对主题“command/response/{uuid}”的响应,其中 uuid 是在命令请求主题中发送的唯一标识符。发布的有效负载包含一个 JSON 对象,其中包含指定命令的资源名称及其值。
在这里插入图片描述

二、连接 MQTT 设备

在这里插入图片描述

# 官方文档

https://docs.edgexfoundry.org/3.1/microservices/device/services/device-mqtt/Ch-ExamplesAddingMQTTDevice/

1.docker-comepse

# 1.克隆 edgex-compose
$ git clone git@github.com:edgexfoundry/edgex-compose.git 
$ git clone https://github.com/edgexfoundry/edgex-compose.git
$ cd edgex-compose 
$ git checkout v3.1


# 2.生成 docker-compose.yml 文件(注意这包括 mqtt-broker)
$ cd compose-builder
$ make gen ds-mqtt mqtt-broker no-secty


# 3.检查生成的文件
$ ls | grep 'docker-compose.yml'
docker-compose.yml
[root@edgex mqtt-device]# git clone https://github.com/edgexfoundry/edgex-compose.git
Cloning into 'edgex-compose'...
remote: Enumerating objects: 4779, done.
remote: Counting objects: 100% (2916/2916), done.
remote: Compressing objects: 100% (173/173), done.
remote: Total 4779 (delta 2831), reused 2804 (delta 2741), pack-reused 1863
Receiving objects: 100% (4779/4779), 1.22 MiB | 450.00 KiB/s, done.
Resolving deltas: 100% (4042/4042), done.


[root@edgex mqtt-device]# ll
total 4
drwxr-xr-x. 6 root root 4096 Feb  1 04:10 edgex-compose


[root@edgex mqtt-device]# cd edgex-compose/
[root@edgex edgex-compose]# git checkout v3.1
Note: checking out 'v3.1'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:

  git checkout -b new_branch_name

HEAD is now at 488a3fe... Merge pull request #424 from lenny-intel/device-mqtt-secure-mode-napa


[root@edgex edgex-compose]# cd compose-builder/

[root@edgex compose-builder]# make gen ds-mqtt mqtt-broker no-secty
echo MQTT_VERBOSE=
MQTT_VERBOSE=
docker compose  -p edgex -f docker-compose-base.yml -f add-device-mqtt.yml -f add-mqtt-broker-mosquitto.yml convert > docker-compose.yml
rm -rf ./gen_ext_compose


[root@edgex compose-builder]# ls | grep 'docker-compose.yml'
docker-compose.yml

2.设备配置文件

在本部分中,我们创建文件夹,其中包含部署自定义设备配置以与现有设备服务配合使用所需的文件:

- custom-config
  |- devices
     |- my.custom.device.config.yaml
  |- profiles
     |- my.custom.device.profile.yml
[root@edgex custom-config]# pwd
/edgex/mqtt-device-svc/custom-config

[root@edgex custom-config]# tree
.
├── devices
│   └── my.custom.device.config.yaml
└── profiles
    └── my.custom.device.profile.yml

2 directories, 2 files

1.设备配置

使用此配置文件来定义设备和调度作业。device-mqtt 在启动时生成一个相对实例。

创建设备配置文件,命名为my.custom.device.config.yaml,如下所示:

[root@edgex custom-config]# vim my.custom.device.config.yaml 

# Pre-define Devices
deviceList:
- name: "my-custom-device"
  profileName: "my-custom-device-profile"
  description: "MQTT device is created for test purpose"
  labels: [ "MQTT", "test" ]
  protocols:
    mqtt:
      CommandTopic: "command/my-custom-device"
  autoEvents:
    - interval: "30s"
      onChange: false
      sourceName: "message"

CommandTopic 用于发布GET或SET命令请求

2.设备配置文件

DeviceProfile定义了设备的值和操作方法,可以是 Read 或 Write。

创建名为 的设备配置文件 my.custom.device.profile.yml,其中包含以下内容:

[root@edgex custom-config]# vim my.custom.device.profile.yml 

name: "my-custom-device-profile"
manufacturer: "iot"
model: "MQTT-DEVICE"
description: "Test device profile"
labels:
  - "mqtt"
  - "test"
deviceResources:
  -
    name: randnum
    isHidden: true
    description: "device random number"
    properties:
      valueType: "Float32"
      readWrite: "R"
  -
    name: ping
    isHidden: true
    description: "device awake"
    properties:
      valueType: "String"
      readWrite: "R"
  -
    name: message
    isHidden: false
    description: "device message"
    properties:
      valueType: "String"
      readWrite: "RW"
  -
    name: json
    isHidden: false
    description: "JSON message"
    properties:
      valueType: "Object"
      readWrite: "RW"
      mediaType: "application/json"

deviceCommands:
  -
    name: values
    readWrite: "R"
    isHidden: false
    resourceOperations:
        - { deviceResource: "randnum" }
        - { deviceResource: "ping" }
        - { deviceResource: "message" }

3.安装自定义配置

创建一个 docker-compose 文件来扩展compose-builder 生成的docker-compose.override.yml compose 文件。在此文件中,我们添加卷路径和环境变量,如下所示:

 # docker-compose.override.yml

 version: '3.7'

 services:
     device-mqtt:
        environment:
          DEVICE_DEVICESDIR: /custom-config/devices
          DEVICE_PROFILESDIR: /custom-config/profiles
        volumes:
        - /path/to/custom-config:/custom-config

将示例中的替换/path/to/custom-config为正确的路径

[root@edgex custom-config]# vim docker-compose.override.yml 

 version: '3.7'

 services:
     device-mqtt:
        environment:
          DEVICE_DEVICESDIR: /custom-config/devices
          DEVICE_PROFILESDIR: /custom-config/profiles
        volumes:
        - /edgex/mqtt-device-svc/custom-config:/custom-config

4.启动 EdgeX Foundry

使用以下命令部署 EdgeX:

$ cd edgex-compose/compose-builder
$ docker compose pull
$ docker compose -f docker-compose.yml -f docker-compose.override.yml up -d


# 修改配置文件
替换IP地址 127.0.0.1 为 0.0.0.0
# docker compose pull

# docker compose -f docker-compose.yml -f docker-compose.override.yml up -d

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

5.创建 MQTT 设备模拟器

要实现模拟的自定义 MQTT 设备,请创建一个名为 的 javascript,mock-device.js其中包含以下内容:

function getRandomFloat(min, max) {
    return Math.random() * (max - min) + min;
}

const deviceName = "my-custom-device";
let message = "test-message";
let json = {"name" : "My JSON"};

// DataSender sends async value to MQTT broker every 15 seconds
schedule('*/15 * * * * *', ()=>{
    var data = {};
    data.randnum = getRandomFloat(25,29).toFixed(1);
    data.ping = "pong"
    data.message = "Hello World"

    publish( 'incoming/data/my-custom-device/values', JSON.stringify(data));
});

// CommandHandler receives commands and sends response to MQTT broker
// 1. Receive the reading request, then return the response
// 2. Receive the set request, then change the device value
subscribe( "command/my-custom-device/#" , (topic, val) => {
    const words = topic.split('/');
    var cmd = words[2];
    var method = words[3];
    var uuid = words[4];
    var response = {};
    var data = val;

    if (method == "set") {
        switch(cmd) {
            case "message":
                message = data[cmd];
                break;
            case "json":
                json = data[cmd];
                break;
        }
    }else{
        switch(cmd) {
            case "ping":
                response.ping = "pong";
                break;
            case "message":
                response.message = message;
                break;
            case "randnum":
                response.randnum = 12.123;
                break;
            case "json":
                response.json = json;
                break;
        }
    }
    var sendTopic ="command/response/"+ uuid;
    publish( sendTopic, JSON.stringify(response));
});

要运行设备模拟器,请输入下面所示的命令并进行以下更改:

$ mv mock-device.js /path/to/mqtt-scripts
$ docker run --rm --name=mqtt-scripts \
    -v /path/to/mqtt-scripts:/scripts  --network host \
    dersimn/mqtt-scripts --dir /scripts

/path/to/mqtt-scripts将示例中的 mv 命令替换为正确的路径

然后 mqtt-scripts 显示日志如下:

2022-08-12 09:52:42.086 <info>  mqtt-scripts 1.2.2 starting
2022-08-12 09:52:42.227 <info>  mqtt connected mqtt://127.0.0.1
2022-08-12 09:52:42.733 <info>  /scripts/mock-device.js loading
# mv mock-device.js /edgex/mqtt-device/mqtt-scripts

# docker run --rm --name=mqtt-scripts \
    -v /edgex/mqtt-device-svc/mqtt-scripts:/scripts  --network host \
    dersimn/mqtt-scripts --dir /scripts
    
    
# docker run -d --rm --name=mqtt-scripts \
    -v /edgex/mqtt-device-svc/mqtt-scripts:/scripts  --network host \
    dersimn/mqtt-scripts --dir /scripts
# 运行容器

[root@edgex mqtt-device-svc]# docker run -d --rm --name=mqtt-scripts \
>     -v /edgex/mqtt-device-svc/mqtt-scripts:/scripts  --network host \
>     dersimn/mqtt-scripts --dir /scripts
Unable to find image 'dersimn/mqtt-scripts:latest' locally
latest: Pulling from dersimn/mqtt-scripts
4297e0229558: Pull complete 
f75ab7205508: Pull complete 
04c94b0d1e73: Pull complete 
710dcd208222: Pull complete 
e4edbf62c3fd: Pull complete 
45c71e9674b9: Pull complete 
a756f71ae17a: Pull complete 
Digest: sha256:f554723bc1acff53483a4ad0102d617b9bbfa099bc129023c096318c6ddacf8e
Status: Downloaded newer image for dersimn/mqtt-scripts:latest
e810a3bffed5580efae6807cf1df986d152200ede5174908c48b2d10b17033c8

6.访问 UI

6.1. consul
# 访问地址
http://192.168.202.233:8500

在这里插入图片描述

6.2. EdgeX Console
# 访问地址
http://192.168.202.233:4000/

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

7.测试

7.1.命令

在这里插入图片描述

7.2.事件

在这里插入图片描述

{
	"apiVersion": "v3",
	"id": "af46944b-e7e0-4d8b-bb6d-18d42721399b",
	"deviceName": "my-custom-device",
	"profileName": "my-custom-device-profile",
	"sourceName": "message",
	"origin": 1708341080603620600,
	"readings": [{
		"id": "edb1630b-7d15-49b8-97e3-1662520f7799",
		"origin": 1708341080603617300,
		"deviceName": "my-custom-device",
		"resourceName": "message",
		"profileName": "my-custom-device-profile",
		"valueType": "String",
		"value": "1111111"
	}]
}


{
	"apiVersion": "v3",
	"id": "99809eb7-83b9-49e3-9a5b-d65adc38a522",
	"deviceName": "my-custom-device",
	"profileName": "my-custom-device-profile",
	"sourceName": "values",
	"origin": 1708341090003785700,
	"readings": [{
		"id": "668df4eb-1404-4267-b0ee-464f1296e50b",
		"origin": 1708341090003772400,
		"deviceName": "my-custom-device",
		"resourceName": "randnum",
		"profileName": "my-custom-device-profile",
		"valueType": "Float32",
		"value": "2.650000e+01"
	}, {
		"id": "65067425-d134-4fc3-922f-2337d228cf0f",
		"origin": 1708341090003773700,
		"deviceName": "my-custom-device",
		"resourceName": "ping",
		"profileName": "my-custom-device-profile",
		"valueType": "String",
		"value": "pong"
	}, {
		"id": "fffe8f12-536c-43d9-9989-9d450d3b0b7b",
		"origin": 1708341090003774200,
		"deviceName": "my-custom-device",
		"resourceName": "message",
		"profileName": "my-custom-device-profile",
		"valueType": "String",
		"value": "Hello World"
	}]
}
7.3.读值

在这里插入图片描述

{
	"id": "aa29ebc7-2d31-4a4d-b58a-a8d85ba7903e",
	"origin": 1708341330008859000,
	"deviceName": "my-custom-device",
	"resourceName": "message",
	"profileName": "my-custom-device-profile",
	"valueType": "String",
	"value": "Hello World"
}

{
	"id": "448591a3-d4d7-4188-9943-88a289f9f54a",
	"origin": 1708341345006348800,
	"deviceName": "my-custom-device",
	"resourceName": "randnum",
	"profileName": "my-custom-device-profile",
	"valueType": "Float32",
	"value": "2.530000e+01"
}

{
	"id": "4af98f08-888a-495d-a07e-4c87dc6d2b82",
	"origin": 1708341345006350000,
	"deviceName": "my-custom-device",
	"resourceName": "ping",
	"profileName": "my-custom-device-profile",
	"valueType": "String",
	"value": "pong"
}

{
	"id": "26600864-c850-4d45-bf42-835dcf966249",
	"origin": 1708341345006350600,
	"deviceName": "my-custom-device",
	"resourceName": "message",
	"profileName": "my-custom-device-profile",
	"valueType": "String",
	"value": "Hello World"
}

{
	"id": "d70a679e-3532-4f7d-a3d1-0e53c8ad5f08",
	"origin": 1708341315007203800,
	"deviceName": "my-custom-device",
	"resourceName": "message",
	"profileName": "my-custom-device-profile",
	"valueType": "String",
	"value": "Hello World"
}
  • EdgeX Foundry
# EdgeX Foundry

https://iothub.org.cn/docs/edgex/
https://iothub.org.cn/docs/edgex/device/service-mqtt/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/426960.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【踏雪无痕的痕五】——一年级数学题映射动态规划

目录 一、背景介绍三、过程1.那是什么样的一个数学题&#xff1f;2.动态规划是个啥&#xff1f;3.为啥联系到动态规划了&#xff1f;4.拿01背包算法做个小例子练练手吧5.感受 四、总结 一、背景介绍 小编发烧并发症一周了&#xff0c;这一周从最开始的轻飘飘找不到灵魂在哪里—…

【心理】程序人生之情绪与压力篇,附心理学相关证书备考指南(心理学312统考,心理治疗师,中科院心理咨询师,家庭教育指导师,企业培训证书)

程序员生活指南&#xff08;情绪与压力篇&#xff09;之 【心理】程序人生之情绪与压力专项&#xff0c;附心理学相关证书备考指南&#xff08;心理学312统考&#xff0c;心理治疗师&#xff0c;中科院心理咨询师&#xff0c;家庭教育指导师&#xff0c;企业培训证书&#xff0…

Linux之进程信号

目录 一、概念引入 1、生活中的信号 2、Linux中的信号 二、信号处理常见方式 三、信号的产生 1、键盘产生信号 2、系统调用接口产生信号 3、软件条件产生信号 4、硬件异常产生信号 四、信号的保存 相关概念 信号保存——三个数据结构 信号集——sigset_t 信号集操…

程序员如何选择职业赛道?

程序员选择职业赛道就像是在一个充满挑战和机遇的迷宫中探索。不同的职业赛道代表着不同的路径&#xff0c;每条路径都有其独特的风景和挑战。我愿意为大家提供一些关于如何选择职业赛道的建议。本文将分为几个部分&#xff0c;包括了解自己、了解行业、职业规划、技能提升和持…

单片机独立按键控制LED状态

一、前言 这幅图是按键的抖动与时间的联系 按键抖动&#xff1a;对于机械开关&#xff0c;当机械鮑点断开、闭合时&#xff0c;由于机械触点的弹性作用&#xff0c;一个开关在闭合时不会马上稳定地接通&#xff0c;在断开时也不会一下子断开&#xff0c;所以在开关闭合及断开的…

加密与安全_探索数字证书

文章目录 Pre概述使用keytool生成证书使用Openssl生成证书 &#xff08;推荐&#xff09;证书的吊销小结 Pre PKI - 借助Nginx 实现Https 服务端单向认证、服务端客户端双向认证 PKI - 04 证书授权颁发机构&#xff08;CA&#xff09; & 数字证书 PKI - 数字签名与数字证…

matplotlib散点图

matplotlib散点图 假设通过爬虫你获取到了北京2016年3, 10月份每天白天的最高气温(分别位于列表a, b), 那么此时如何寻找出气温和随时间(天)变化的某种规律? from matplotlib import pyplot as pltx_3 range(1, 32) x_10 range(51, 82)y_3 [11,17,16,11,12,11,12,6,6,7,8…

GEE:使用双曲正切(tanh)激活函数对单波段图像进行变换(以NDVI为例)

作者:CSDN @ _养乐多_ 本文将介绍在 Google Earth Engine (GEE)平台上,对任意单波段影像进行 双曲正切(tanh)激活函数 变换的代码。并以对 NDVI 影像中像素值的变换为例。 文章目录 一、tanh激活函数1.1 tanh激活函数1.2 用到遥感图像上有什么用?二、代码链接三、完整代…

STL——queue

queue 1. 队列是一种容器适配器&#xff0c;专门用于在FIFO上下文(先进先出)中操作&#xff0c;其中从容器一端插入元素&#xff0c;另一端提取元素。 2. 队列作为容器适配器实现&#xff0c;容器适配器即将特定容器类封装作为其底层容器类&#xff0c;queue提供一组特…

Linux入门到入土

Linxu Linux 简介 Linux 内核最初只是由芬兰人林纳斯托瓦兹&#xff08;Linus Torvalds&#xff09;在赫尔辛基大学上学时出于个人爱好而编写的。 Linux 是一套免费使用和自由传播的类 Unix 操作系统&#xff0c;是一个基于 POSIX&#xff08;可移植操作系统接口&#xff09…

Vscode 使用SSH远程连接树莓派的教程(解决卡在Downloading with wget)

配置Vscode Remote SSH 安装OpenSSH 打开Windows开始页面&#xff0c;直接进行搜索PowerShell&#xff0c;打开第一个Windows PowerShell&#xff0c;点击以管理员身份运行 输入指令 Get-WindowsCapability -Online | ? Name -like OpenSSH* 我是已经安装好了&#xff0c;…

掘根宝典之c语言字符指针,指针数组,数组指针,函数指针

目录 字符指针 字符指针指向字符串 使用字符指针 例子 指针数组 数组指针 数组名和&数组名 数组名 sizeof(数组名)&#xff0c;&数组名 &数组名 &数组名错误使用方法 数组名和&数组名用于一维数组 例子1 例子2 数组名和&数组名用于二维数…

龙耀南街 喜闹元宵| 猜灯谜送汤圆蒙面K歌精彩多多!

上元南街,璀璨烟花!正月十五,你来南街闹元宵了吗? 为了更好的让游客体验碳水王国丰富多元的元宵活动,南街特此设定了:送汤圆做龙灯、猜灯谜送财气、大屏互动.好运连连、南街大舞台.有才你就来—蒙面歌王挑战赛、璀璨烟花,现场热闹欢腾~ 送汤圆: 做龙灯: 猜灯谜送财气: 大屏互…

Java内存区域

Java内存区域 Java内存区域就是Java运行时数据区 线程私有的&#xff1a;程序计数器、虚拟机栈、本地方法栈线程共享的&#xff1a;堆、方法区 1.程序计数器 程序计数器是什么&#xff1a;可以看作是当前线程所执行的字节码的行号指示器 程序计数器的作用&#xff1a; 实…

Open3D 进阶(21)无序点云平面检测的鲁棒统计方法

目录 一、算法原理1、算法过程2、参考文献二、代码实现三、结果展示本文由CSDN点云侠原创,原文链接。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫与GPT。 一、算法原理 1、算法过程 除了寻找具有最大支持的单个平面外,Open3D还包含一个算法,该算法使…

于月仙主动与赵本山握手表示欢迎,赵:怎么着要跟我第二次牵手啊?

于月仙主动与赵本山握手表示欢迎&#xff0c;赵&#xff1a;怎么着要跟我第二次牵手啊&#xff1f; --小品《乡村爱情》&#xff08;中1&#xff09;的台词 表演者&#xff1a;赵本山 于月仙 王小利 唐鉴军等 &#xff08;接上&#xff09; 咱们呢就给新人揭盖头 好 好长贵…

STM32 (4) GPIO(1)

1.芯片的引脚分布 2.普通IO引脚的命名规则 3.IO复用 IO引脚身兼数职的现象叫做IO复用&#xff0c;可以使芯片拥有更多的功能&#xff0c;例如&#xff1a; PA9和PA10既可以用于GPIO的引脚&#xff0c;也可以用于串口或定时器的引脚 通用&#xff1a;CPU直接控制IO引脚的输入输…

Leetcode热题100道

Leetcode热题100道 &#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是 枫度柚子&#x1f341;&#xff0c;Java摆烂选手&#xff0c;很高兴认识大家 &#x1f440; &#x1f4d5;CSDN/掘金/B站: 枫吹过的柚 &#x1f341; &#x1f525;如果感觉博主的文章还不错的话&a…

FreeRTOS(一)FreeRTOS基础知识

目录 简单介绍 FreeRTOS基础知识 任务调度 抢占式调度&#xff1a; 举例说明&#xff1a; 时间片调度 举例说明 任务状态 FreeRTOS中4种任务状态 四种任务状态转换图 任务状态列表 今天开个新坑----FreeRTOS 简单介绍 FreeRTOS是一个轻量级的实时操作系统&#xf…

修复通达OA 百度ueditor 文件上传漏动

前些日子&#xff0c;服务器阿里云监控报警&#xff0c;有文件木马文件&#xff0c;因为非常忙&#xff0c;就没及时处理&#xff0c;直接删除了木马文件了事。 谁知&#xff0c;这几天对方又上传了木马文件。好家伙&#xff0c;今天不花点时间修复下&#xff0c;你都传上瘾了…