基于UE5和ROS2的激光雷达+深度RGBD相机小车的仿真指南(三)---创建自定义激光雷达Componet组件
前言
- 本系列教程旨在使用
UE5
配置一个具备激光雷达
+深度摄像机
的仿真小车,并使用通过跨平台的方式进行ROS2
和UE5
仿真的通讯,达到小车自主导航的目的。 - 本教程默认有ROS2导航及其gazebo仿真相关方面基础,Nav2相关的学习教程可以参考本人的其他博客Nav2代价地图实现和原理–Nav2源码解读之CostMap2D(上)-CSDN博客
- 往期教程:
- 第一期:基于UE5和ROS2的激光雷达+深度RGBD相机小车的仿真指南(一)—UnrealCV获取深度+分割图像-CSDN博客
- 第二期:基于UE5和ROS2的激光雷达+深度RGBD相机小车的仿真指南(二)—ROS2与UE5进行图像数据传输-CSDN博客
- UE5系列教程:
- 第一期:UE5-C++入门教程(一):使用代码创建一个指定目标的移动小球-CSDN博客
- 第二期:UE5-C++入门教程(二)—编写Editor类别的自定义模型实现小球规划路线的可视化-CSDN博客
- 本教程环境支持:
- UE5.43
- ubuntu 22.04 ros2 humble
- 前两期我们讲了如何使用
UnrealCV
在UE5
中捕获深度,分割,原始图像,并借助rosbridge
将图像数据实时传输到ubuntu22.04 ros2 humble
中。本期我们来讲讲如何在UE5
中模拟激光雷达
的仿真数据。
激光雷达
介绍
-
激光雷达(Lidar)
是一种利用激光来探测和测量物体距离、速度、方位和形状的技术。它通过发射激光脉冲,并接收从目标反射回来的激光,从而计算出目标的位置和特性。激光雷达广泛应用于各种领域,如地理信息系统(GIS)、环境监测、遥感、自动驾驶汽车、考古学等。 -
激光雷达的基本工作原理如下:
- 发射激光:激光雷达系统发射激光脉冲,这些脉冲可以是连续波或者脉冲波。
- 反射激光:激光脉冲照射到目标物体后,部分光波会被反射回来。
- 接收反射光:激光雷达系统中的接收器会捕捉到反射回来的激光。
- 数据处理:系统通过计算激光发射和接收之间的时间差,以及激光的波长,来确定目标的距离。通过分析反射光的强度、频率变化等,还可以获取目标的速度、方位和形状等信息。
性能指标
-
这里我们借助
镭神智能公司
旗下的16线机械式激光雷达
来讲解激光雷达具备的基本参数(这里不是广告(迫真)) -
- 激光波长905nm:
- 激光波长是激光雷达发射的激光的波长,通常以纳米(nm)为单位。常用的波长包括905nm和1550nm。不同波长的激光具有不同的特性和应用,例如,905nm波长的激光雷达通常成本较低,但容易受到阳光和其他环境因素的干扰;而1550nm波长的激光雷达具有更好的抗干扰能力和较长的探测距离。
- 探测距离70/120/150/200m:
- 探测距离是指激光雷达能够有效测量目标的最远距离。探测距离受激光功率、目标反射率、大气条件等因素的影响。通常,激光雷达的探测距离从几米到几百米不等。
- 视场角(FOV)- 水平视场角:360°,垂直视场角:-15°~15° / -10°~10°:
- 视场角是指激光雷达能够覆盖的水平或垂直角度范围。水平视场角通常为360度,而垂直视场角则取决于激光雷达的具体设计。视场角越大,激光雷达能够感知的环境范围就越广。
- 测距精度±3cm:
- 测距精度是指激光雷达测量距离的准确程度,通常以厘米或毫米为单位。高精度的激光雷达可以提供非常准确的距离测量,这对于需要高精度定位和测量的应用至关重要。
- 角分辨率垂直:2°,水平:0.09°@5Hz, 0.18°@10Hz, 0.36°@20Hz:
- 角分辨率是指激光雷达能够分辨的最小角度变化。高角分辨率意味着激光雷达可以更细致地描绘目标的形状和轮廓。角分辨率通常分为水平角分辨率和垂直角分辨率。
- 出点数- 320,000点/秒(单回波):
- 出点数是指激光雷达每秒钟能够发射的激光点数。出点数越多,激光雷达获取的环境信息越丰富,扫描速度越快。
- 线束16线:
- 线束是指激光雷达在垂直方向上的激光束数量。多线激光雷达通过多个激光发射器在垂直方向上的分布,形成多条线束的扫描。线束越多,对环境的描述越充分。
- 安全等级 1级(人眼安全):
- 激光雷达的安全等级需要满足特定的安全标准,例如Class 1,以确保在正常使用条件下不会对用户造成伤害。
- 输出参数:
- 输出参数包括障碍物的位置、速度、方向、时间戳、反射率等,这些参数对于后续的数据处理和分析至关重要。
- IP防护等级IP67:
- IP防护等级表示激光雷达对固体颗粒和水的防护能力,对于在恶劣环境下工作的激光雷达尤为重要。
- 功率和供电电压:
- 功率和供电电压决定了激光雷达的能耗和适用场景。激光雷达的功率通常以瓦特(W)为单位,供电电压则取决于激光雷达的具体设计。
- 激光发射方式- 机械旋转:
- 激光发射方式分为机械旋转和固态两种。机械旋转激光雷达通过旋转发射器来扫描环境,而固态激光雷达则通过电子方式控制激光束的方向。
- 使用寿命:
- 使用寿命是指激光雷达在正常工作条件下的预期寿命。机械旋转激光雷达的使用寿命一般在几千小时,而固态激光雷达的使用寿命可高达10万小时。
题外话-旧版本UE5插件支持(不使用)
- 值得一提的是,在UE5的虚幻商城中,是存在一款免费的2D雷达仿真插件的,但是由于其支持的引擎版本,本期我们不使用该插件。
1.创建自定义雷达插件
- 本小结我们将借助激光雷达的原理,不借助任何现成插件,尝试在
UE5
中借助内置函数,通过cpp代码实现完成上述激光雷达的仿真。
1-1 概念解析–插件
- Unreal Engine 5 (UE5) 提供了一个强大的插件系统,允许开发者扩展和定制引擎的功能。插件可以是社区创建的,也可以是 Epic Games 官方提供的,它们可以添加新的工具、功能、内容或集成到 Unreal Engine 中。
- UE5 插件的特点和优势包括:
- 模块化:插件通常以模块的形式集成到 Unreal Engine 中,这意味着它们可以独立于引擎的其他部分进行开发、编译和更新。
- 可定制性:开发者可以根据自己的需求定制插件,添加新的功能或改进现有功能。
- 可重用性:插件可以在不同的项目中重用,节省开发时间和资源。
- 易于安装:Unreal Engine 提供了一个插件市场,开发者可以轻松地浏览、安装和管理插件。
- 要使用 UE5 插件,我们只需要将其导入到 Unreal Engine 项目中。一旦插件被导入,开发者可以在项目的插件管理器中启用或禁用插件,并根据需要配置插件的设置。
1-2 创建自定义插件
-
新建一个新的项目(这里取名为
Plugins_project
),选择C++
而不是蓝图
,否则我们将会只有一种类型的插件 -
打开你的新建的项目(记得确保是
C++
),在左上角菜单栏点击编辑
,在下拉菜单栏中找到插件
,在新打开的插件窗口中选择+ 添加
,会出现如下画面 -
这里我们把插件名字定义为
LaserScannerSim
- 作者:我www
- 描述为:a plugin which mantian at 2D laser scanning simualtion including laser displaying and laser messages publishing
-
VS2022
打开项目(记得重新加载),在项目根目录下会多出一个Plugins
文件夹 -
.uplugin
文件是 Unreal Engine 中的插件描述文件,它定义了插件的各种元数据和设置,包括插件的名称、版本、描述、作者、加载阶段、模块列表等。这个文件是插件的重要组成部分,它告诉 Unreal Engine 如何加载、集成和管理插件。我们来关注LaserScannerSim.uplugin
这个文件的结尾部分
"Modules": [{"Name": "LaserScannerSim","Type": "Runtime","LoadingPhase": "Default"}
]
Name
:LaserScannerSim
这是模块的名称,它应该是独一无二的,并且会用作模块的标识符。在代码中,通常会与模块相关的文件和目录同名。
Type
:"Runtime"
这表示模块类型为运行时模块。运行时模块包含在游戏或应用程序的运行时阶段加载的代码和资源。LoadingPhase
:"Default"
- 这指定了模块的加载阶段。Default
加载阶段意味着模块将在默认的加载时间点被加载,这对于大多数插件来说是合适的。如果需要更细粒度的控制,可以指定其他加载阶段,例如PostEngineInit
、PreLoadMap
或PostLoadMap
。- 这里我们把这个插件的
LoadingPhase
改为PostEngineInit,我希望模块在引擎初始化完成后加载。
"Modules": [{"Name": "LaserScannerSim","Type": "Runtime","LoadingPhase": "PostEngineInit"}
]
- 紧接着我们来看看该插件文件夹下的两个文件夹
- Public:LaserScannerSim.hpp
// Copyright Epic Games, Inc. All Rights Reserved.#pragma once#include "CoreMinimal.h"
#include "Modules/ModuleManager.h"class FLaserScannerSimModule : public IModuleInterface
{
public:/** IModuleInterface implementation */virtual void StartupModule() override;virtual void ShutdownModule() override;
};
- Private:LaserScannerSim.cpp
// Copyright Epic Games, Inc. All Rights Reserved.#include "LaserScannerSim.h"#define LOCTEXT_NAMESPACE "FLaserScannerSimModule"void FLaserScannerSimModule::StartupModule()
{// This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module
}void FLaserScannerSimModule::ShutdownModule()
{// This function may be called during shutdown to clean up your module. For modules that support dynamic reloading,// we call this function before unloading the module.
}#undef LOCTEXT_NAMESPACEIMPLEMENT_MODULE(FLaserScannerSimModule, LaserScannerSim)
StartupModule
和ShutdownModule
。这两个函数分别在模块加载到内存后和卸载前调用。稍后我们将讲述如何运用IModuleInterface
类它定义了模块(Module)在Unreal Engine中加载和卸载时的行为。
1-3 报错提示-UE5.4版本BUG
-
值得注意的是,在UE5.4中,在上述创建自定义插件后在VS2022进行编译会出现下述报错
-
这是因为你不能在UE的
Live Coding enabled
的时候进行编译,这时我们选择关闭UE的Live Coding enabled
-
重新编译,成功。
2 创建自定义Componet雷达组件
- 我们来快速思考以下,我们要创建的雷达插件应该是可以广泛运用到用户的各类模型(Actor)上,用户可以根据调用我们的雷达组件,根据其喜好参数,把此组件运用到任意模组中,可以是车辆,或者是雷达模型上。因此我们要创建一个
Componet
组件,它可以被套用到用户希望的Actor上
2-1 创建自定义雷达组件Components
-
创建组件的详细教程见->UE5-C++入门教程(一):使用代码创建一个指定目标的移动小球-CSDN博客
-
这里我们快速创建一个组件,选择
ActorComponent
作为父类 -
为新的组件取名为
LaserScanner2D
,注意添加到我们的插件模块下(并设置为私有)
2-2 激光雷达实现函数
-
这里介绍一个
UE5
提供的内置函数LineTraceSingleByChannel
,我们打开官方API手册,搜索得到相关关于这个函数的API实现 -
函数
LineTraceSingleByChannel
用于执行光线投射(Line Tracing)。这个函数可以用来检测从起点到终点之间是否有碰撞,并返回碰撞信息。FHitResult & OutHit
用于存储光线投射的结果。如果检测到碰撞,这个参数会被填充碰撞信息,例如碰撞的位置、碰撞的物体等。const FVector & Start
这是光线投射的起点,类型为FVector
,表示三维空间中的一个点。const FVector & End
: 这是光线投射的终点,类型同样为FVector
。ECollisionChannel TraceChannel
这是一个枚举类型,用于指定需要检测的碰撞通道。const FCollisionQueryParams & Params
:这是一个引用参数,用于配置光线投射的查询参数,允许你设置诸如忽略特定的Actor
、检测隐藏的Actor
等选项。const FCollisionResponseParams & ResponseParam
:允许你设置碰撞后的响应行为
bool LineTraceSingleByChannel
&40; struct FHitResult & OutHit, const FVector & Start, const FVector & End, ECollisionChannel TraceChannel, const FCollisionQueryParams & Params, const FCollisionResponseParams & ResponseParam
&41; const
2-3 激光雷达可视化
-
这里我们使用
DrawDebugLine
对雷达的射线进行可视化 -
WorldContextObject
: 表示当前世界上下文的对象。通常,你会传递GetWorld()
的返回值给这个参数,它会返回一个指向当前游戏世界的指针。
LineStart
: 直线的起始位置,它是一个FVector
类型,表示三维空间中的一个点。LineEnd
: 直线的结束位置,它也是一个FVector
类型,表示三维空间中的另一个点。LineColor
: 直线的颜色,它是一个FLinearColor
类型,允许你设置红、绿、蓝和透明度。Duration
: 直线在游戏世界中显示的时间(以秒为单位)。如果设置为-1.0f,直线会一直显示直到下一帧或显式地被清除。Thickness
: 直线的厚度(以世界单位为单位)。这允许你设置直线的宽度。
static void DrawDebugLine
&40; const UObject &42; WorldContextObject, const FVector LineStart, const FVector LineEnd, FLinearColor LineColor, float Duration, float Thickness
&41;
2-4 编写雷达组件基本逻辑
- 那么我们来编写一下雷达组件的实现逻辑
- LaserScanner2D.hpp,我们为雷达组件添加以下逻辑的代码
FVector StartRelativeLocation;
//起始位置bool bScanEnabled = true;
//是否使能int32 Resolution = 1;
// 分辨率,每1度检测一次float ScanHz = 30.0f;
// 扫描频率,每秒30次float LaserMinDistance = 0.1f;
// 最近检测距离float LaserMaxDistance = 100.0f;
// 最远检测距离float debugLineStayDuration = 1.0f;
// 射线持续时间
// Fill out your copyright notice in the Description page of Project Settings.#pragma once#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "LaserScanner2D.generated.h"UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class ULaserScanner2D : public UActorComponent
{GENERATED_BODY()public: // Sets default values for this component's propertiesULaserScanner2D();protected:// Called when the game startsvirtual void BeginPlay() override;
public:void ScanForObjects();
public: // Called every framevirtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;private:UPROPERTY(EditAnywhere)FVector StartRelativeLocation; //起始位置UPROPERTY(EditAnywhere)bool bScanEnabled = true; //是否使能UPROPERTY(EditAnywhere)int32 Resolution = 1; // 分辨率,每10度检测一次UPROPERTY(EditAnywhere)float ScanHz = 30.0f; // 扫描频率,每秒30次UPROPERTY(EditAnywhere)float LaserMinDistance = 0.1f; // 最近检测距离UPROPERTY(EditAnywhere)float LaserMaxDistance = 100.0f; // 最远检测距离UPROPERTY(EditAnywhere)float debugLineStayDuration = 1.0f; // 射线持续时间
};
- LaserScanner2D.cpp
- 我们在
BeginPlay()
初始化一个起始位置
#include "LaserScanner2D.h"
ULaserScanner2D::ULaserScanner2D()
{PrimaryComponentTick.bCanEverTick = true;
}
void ULaserScanner2D::BeginPlay()
{Super::BeginPlay();StartRelativeLocation = FVector(0.0f, 0.0f, 0.0f);
}
TickComponent
将会一直运行,我们让其根据我们指定的频率去调用我们写的雷达扫描函数
void ULaserScanner2D::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{Super::TickComponent(DeltaTime, TickType, ThisTickFunction);static float AccumulatedTime = 0.0f; // 累积时间AccumulatedTime += DeltaTime; // 累加Delta Time// 当累积时间达到扫描周期时,执行扫描if (AccumulatedTime >= 1.0f / ScanHz){ScanForObjects();AccumulatedTime -= 1.0f / ScanHz; }
}
- 雷达扫描函数
for (int32 i = 0; i < 360; i += Resolution)
我们按照指定分辨率去选择扫描Rotation
: 这个FRotator
对象表示当前射线发射的方向。它是一个绕Y轴旋转的旋转器,其Z轴和X轴的值为0,Y轴的值为当前的角度i
。
EndLocation
: 这是当前射线的结束位置。它通过将StartLocation
与Rotation
的向量相加以LaserMaxDistance
的长度来计算得出。FMath::Clamp
函数确保这个距离不会超过LaserMaxDistance
的最远距离,也不会小于LaserMinDistance
的最近距离。OutHit
: 这是一个FHitResult
对象,它用于存储射线与场景中其他对象碰撞的信息。Params
: 这是一个FCollisionQueryParams
对象,它定义了射线检测的参数。AddIgnoredActor(GetOwner())
调用确保激光雷达不会与自己所在的Actor
发生碰撞。- 如果检测到膨胀,则绘制一条从
StartLocation
到OutHit.Location
的绿色直线。OutHit.Location
是射线碰撞点的位置。如果没有检测到碰撞,则绘制一条从StartLocation
到EndLocation
的红色直线。
GetWorld()
:- 在Unreal Engine中,
GetWorld()
是一个成员函数,用于获取当前Actor
或Component
所在的World
对象。World
对象是Unreal Engine中的一个核心概念,它代表了游戏世界的环境,包括场景中的所有Actor
、地形、光照、音效等。
- 在Unreal Engine中,
UWorld* GetWorld() const;
GetWorld()
成员函数是许多类的接口的一部分,尤其是那些与游戏世界直接交互的类。以下是一些常见的具有GetWorld()
函数的类:AActor
: 代表游戏世界中的可移动对象。UActorComponent
: 代表附加到Actor
上的组件,它们通常需要访问游戏世界来进行各种操作。UGameInstance
: 代表游戏会话的单例,它可以访问当前的游戏世界。ULevel
: 代表游戏世界中的一个关卡。APlayerController
: 代表玩家控制器,它可以访问游戏世界来控制玩家视角和输入。AGameModeBase
: 代表游戏模式,它定义了游戏的基本规则和流程。UUserWidget
: 代表游戏中的用户界面元素,它可能需要访问游戏世界来获取数据或执行操作。UFieldSystem
: 代表场系统,用于在游戏世界中模拟物理场。
- 然而,并不是所有的类都有GetWorld()函数。
void ULaserScanner2D::ScanForObjects()
{const FVector StartLocation = StartRelativeLocation;for (int32 i = 0; i < 360; i += Resolution){FRotator Rotation = FRotator(0.0f, i, 0.0f);FVector EndLocation = StartLocation + Rotation.Vector() * FMath::Clamp(LaserMaxDistance, LaserMinDistance, LaserMaxDistance);FHitResult OutHit;FCollisionQueryParams Params;Params.AddIgnoredActor(GetOwner());if (GetWorld()->LineTraceSingleByChannel(OutHit, StartLocation, EndLocation, ECC_Visibility, Params)){DrawDebugLine(GetWorld(), StartLocation, OutHit.Location, FColor::Green, false, debugLineStayDuration);}else{DrawDebugLine(GetWorld(), StartLocation, EndLocation, FColor::Red, false, debugLineStayDuration);}}
}
2-5 编译与验证
-
点击VS2022的绿色透明小箭头,编译代码
-
在内容处创建一个蓝图类
Lidar
(UE教程我们详细见过了,这里快速通过) -
为蓝图类添加LaserScanner2D组件
-
我们把新的
Lidar
蓝图类添加到常见中,并为主场景添加一些基本的物体 -
我们可以在雷达类下修改一些基本的参数
-
运行,可以看到我们的雷达成功完成目标
小结
- 本期我们通过自定义插件的方式实现了激光雷达的仿真
- 下一期我们将讲述如何对雷达数据进行打包并转发给
ubuntu
的ROS2
- 感谢大家对本教程的支持!如有错误,欢迎指出!
相关文章:

基于UE5和ROS2的激光雷达+深度RGBD相机小车的仿真指南(三)---创建自定义激光雷达Componet组件
前言 本系列教程旨在使用UE5配置一个具备激光雷达深度摄像机的仿真小车,并使用通过跨平台的方式进行ROS2和UE5仿真的通讯,达到小车自主导航的目的。本教程默认有ROS2导航及其gazebo仿真相关方面基础,Nav2相关的学习教程可以参考本人的其他博…...

C++ 设计模式——策略模式
策略模式 策略模式主要组成部分例一:逐步重构并引入策略模式第一步:初始实现第二步:提取共性并实现策略接口第三步:实现具体策略类第四步:实现上下文类策略模式 UML 图策略模式的 UML 图解析 例二:逐步重构…...

【书生大模型实战营(暑假场)闯关材料】基础岛:第3关 浦语提示词工程实践
1.配置环境时遇到的问题 注意要使用terminal,而不是jupyter。 否则退出TMUX会话时,会出问题。 退出TMUX会话命令如下: ctrlB D # 先按CTRLB 随后按D另外一个是,端口转发命令 ssh -p XXXX rootssh.intern-ai.org.cn -CNg -L …...

C++ | Leetcode C++题解之第350题两个数组的交集II
题目: 题解: class Solution { public:vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {sort(nums1.begin(), nums1.end());sort(nums2.begin(), nums2.end());int length1 nums1.size(), length2 nums2…...

遗传算法原理与实战(python、matlab)
遗传算法 1.什么是遗传算法 遗传算法(Genetic Algorithm,简称GA)是一种基于生物进化论和遗传学原理的全局优化搜索算法。它通过模拟自然界中生物种群的遗传机制和进化过程来解决复杂问题,如函数优化、组合优化、机器学习等。遗传…...

《黑神话:悟空》媒体评分解禁 M站均分82
《黑神话:悟空》媒体评分现已解禁,截止发稿时,M站共有43家媒体评测,均分为82分。 部分媒体评测: God is a Geek 100: 毫无疑问,《黑神话:悟空》是今年最好的动作游戏之一ÿ…...

安卓中携程和线程的区别。携程是指什么?
在安卓和其他编程环境中,协程(Coroutine)和线程(Thread)是两种不同的并发处理机制。它们各自有独特的特点和适用场景: 线程(Thread): 线程是操作系统能够进行运算调度的最…...

部署flannel网络(master服务器执行)遇到错误
出现错误 “The connection to the server 192.168.0.23:6443 was refused - did you specify the right host or port?” 的原因通常是因为 Kubernetes API 服务器未能启动或无法访问。以下是一些可能的原因和解决方案: 解决方案 确认 Kubernetes API 服务器的状…...

超越IP-Adapter!阿里提出UniPortrait,可通过文本定制生成高保真的单人或多人图像。
阿里提出UniPortrait,能根据用户提供的文本描述,快速生成既忠实于原图又能灵活调整的个性化人像,用户甚至可以通过简单的句子来描述多个不同的人物,而不需要一一指定每个人的位置。这种设计大大简化了用户的操作,提升了…...

使用托管竞价实例在Amazon SageMaker上运行机器学习训练
这是本系列文章的第二篇,旨在通过动手实践,帮助大家学习亚马逊云科技的生成式AI相关技能。通过这些文章,大家将掌握如何利用亚马逊云科技的各类服务来应用AI技术。 那么让我们开始今天的内容吧! 介绍 什么是Amazon SageMaker …...

AIoT智能物联网平台定义
随着科技的飞速发展,我们正步入一个由智能设备和互联网络构成的新时代。AIoT,即人工智能物联网(Artificial Intelligence of Things),是这个时代的标志性产物。本文旨在探讨AIoT智能物联网平台的定义、核心组件、应用场…...

微服务设计原则——高性能:存储设计
文章目录 1.读写分离2.分库分表3.动静分离4.冷热分离5.重写轻读6.数据异构参考文献 任何一个系统,从单机到分布式,从前端到后台,功能和逻辑各不相同,但干的只有两件事:读和写。而每个系统的业务特性可能都不一样&#…...

hbase-manager图形化界面的安装与配置
相关资料下载 夸克网盘分享 1、上传项目到linux上 解压: 切换到conf目录下:/opt/installs/hbase-manager-2.0.8-hbase-2.x/conf/ 2、修改数据库配置信息 application-druid.yml 3、创建hbase-manager数据库(注意字符集编码),导入数据库脚本…...

STM32之继电器与震动传感器的使用,实现震动灯
在STM32的外设应用中,继电器扮演着重要的角色。继电器作为一种电控制器件,其主要作用是通过小电流控制大电流的通断,实现电路的自动控制和保护。具体来说,继电器在STM32外设中的作用可以归纳为以下几点: 电路隔离与保…...

RS232(旧协议)与RS485(新协议)
RS232: RS485: RS485和RS232是两种常见的串行通信标准,它们在通信距离、速度、拓扑结构等方面存在显著差异。以下是它们的主要区别: 1. 物理层接口 RS232: 使用单端信号传输,即信号通过一根信号线和一根公共地线(GND)…...

android13顶部状态栏里面调节背光,不隐藏状态栏面板
总纲 android13 rom 开发总纲说明 目录 1.前言 2.代码分析 3.修改方法 4.编译运行 5.彩蛋 1.前言 android13顶部状态栏里面调节背光,这个时候状态栏面板会被隐藏掉,有些需求就需要不隐藏这个面板。 2.代码分析 查找亮度条属性 id/brightness_slider ./frameworks/b…...

Webrtc之SDP协议
SDP简介 SDP 最常用于 RTC 实时通话的协商过程,在 WebRTC 中,通信双方在连接阶段使用 SDP 来协商后续传输过程中使用的音视频编解码器(codec)、主机候选地址、网络传输协议等。 在实际的应用过程中,通信双方可以使用 HTTP、WebSocket、Data…...

mfc140u.dll丢失错误解决方法的基本思路——四种修复mfc140u.dll的方法
当遇到mfc140u.dll丢失的错误时,意味着你的系统中缺失了一个重要的动态链接库文件,该文件是微软 Visual C Redistributable for Visual Studio 2015 的一部分,对于运行那些用 Visual C 开发的程序是必需的。今天就教你mfc140u.dll丢失错误解决…...

Python Django 后端架构开发: 中间件架构设计
🌟 Python Django 后端架构开发: 中间件架构设计 🔹 中间件项目测试:自定义中间件的 process_response 与 process_view 方法 在 Django 中,中间件是一种用于处理请求和响应的钩子,可以在视图处理前后对请…...

HTTP的认证方式
0.HTTP认证相关的一些基本概念 0.1 HTTP保护空间(HTTP Protection Space) 也称为认证领域(Authentication Realm),是指在HTTP认证中用来定义一组受保护资源的范围。保护空间通常由一个realm标识符来表示,它定义了用户需要提供凭据(如用户名和密码)才能访问的资源集合…...

10分钟学会LVM逻辑卷
华子目录 前言认识LVMLVM基本概念LVM整体流程LVM管理命令pvs,vgs,lvs命令pvs基本用法选项示例 vgs基本用法选项示例 lvs基本用法 pvcreate,vgcreate,lvcreate命令pvcreate示例 vgcreate基本用法示例选项 lvcreate基本用法示例 pvr…...

【gitlab】gitlab-ce:17.3.0-ce.0 之2:配置
参考阿里云的教程docker的重启 sudo systemctl daemon-reload sudo systemctl restart docker配置 –publish 8443:443 --publish 8084:80 --publish 22:22 sudo docker ps -a 當容器狀態為healthy時,說明GitLab容器已經正常啟動。 root@k8s-master-pfsrv:~...

第七十四:前端实现点击页面某个菜单跳转到对应的锚点功能
1.用js来实现 scrollIntoView方法 先定义个id或者class随意,因为我是循环好几个小模块所以用动态的来实现 点击的时候传对应的类名进行滑动 document.getElementById(item.variableCode).scrollIntoView({behavior:“smooth”}); 加上behavior:“smooth” 进行平…...

PyTorch分布式训练全攻略:DistributedDataParallel精解与实战
标题:PyTorch分布式训练全攻略:DistributedDataParallel精解与实战 在深度学习飞速发展的今天,模型的规模和数据集的体量不断增长,单机单卡的训练方式已难以满足需求。分布式训练以其卓越的扩展性和效率,成为解决这一…...

Python(TensorFlow)多模光纤光束算法和GPU并行模拟
🎯要点 🎯多模光纤包含光学系统线性和非线性部分 | 🎯单变量线性回归、多变量线性回归、人脸图像年龄预测、音频语音分类和 X 射线图像评估算法 | 🎯在空间光调制器记录海螺参数矩阵,光束算法多变量预测年龄 | &#…...

实战Kubernetes之快速部署 K8s 集群 v1.28.0
文章目录 一、前言二、主机准备三、系统配置3.1. 关闭防火墙及相关配置3.2. 修改主机名3.3. 主机名DNS解析3.4. 时间同步3.5. 配置网络3.6. 重启服务器 四、安装软件4.1. 安装 Docker4.2. 安装 cri-dockerd4.3. 添加国内YUM源4.4. 安装 kubeadm、kubelet 和 kubectl 五、Master…...

YOLO知识点总结:
分类: 即是将图像结构化为某一类别的信息,用事先确定好的类别(category)或实例ID来描述图片。这一任务是最简单、最基础的图像理解任务,也是深度学习模型最先取得突破和实现大规模应用的任务。其中,ImageNet是最权威的评测集&…...

合宙LuatOS AIR700 IPV6 TCP 客户端向NodeRed发送数据
为了验证 AIR700 IPV6 ,特别新建向NodeRed Tcp发送的工程。 Air700发送TCP数据源码如下: --[[ IPv6客户端演示, 仅EC618系列支持, 例如Air780E/Air600E/Air780UG/Air700E ]]-- LuaTools需要PROJECT和VERSION这两个信息 PROJECT "IPV6_SendDate_N…...

git 如何生成sshkey公钥
打开git客户端 输入 ssh-keygen -t rsa -b 4096 -C "xxxxxxexample.com" 然后根据提示按enter 或者y 直到出现下图所示 打开 c盘的路径下的文件,/c/Users/18159/.ssh/id_rsa.pub 将id_rsa.pub中的公钥贴到git 网站上的SSH keys即可...

python从入门到精通:函数
目录 1、函数介绍 2、函数的定义 3、函数的传入参数 4、函数的返回值 5、函数说明文档 6、函数的嵌套调用 7、变量的作用域 1、函数介绍 函数是组织好的,可重复使用的,用来实现特定功能的代码段。 name "zhangsan"; length len(nam…...