MATLAB - 机器人机械臂设计轨迹规划器

news2024/10/9 9:25:12

系列文章目录

 


前言

        本示例介绍了一种设计抓取和轨迹规划器的方法,该规划器可用于垃圾箱拣选系统。

        在机器人技术中,垃圾箱拣选包括使用机械手从垃圾箱中取出物品。智能垃圾箱拣选是这一过程的高级版本,具有更强的自主性。使用摄像系统感知部件,规划器生成与场景相适应的无碰撞轨迹。

        本示例展示了如何创建一个轨迹规划器组件,该组件将与料箱拣选系统配合使用。该组件作为独立模型存储,可作为线束中的引用模型调用。该示例还使用了一个简单的测试线束来验证规划器的行为。


 

一、查看模型

        打开包含规划器模型的测试

open_system('TrajectoryPlanning_Harness')
open_system('TrajectoryPlanning_Harness/Planner Subsystem')

        线束,并导航到规划器子系统以检查其内容。

a21723d1ff1a4811accd415d4a09350a.png

        规划器模块由几个部分组成:

  • 计算逆运动学
  • 规划无碰撞轨迹并优化运动学给定约束条件
  • 缩放生成的轨迹,使其在速度和加速度约束条件下达到时间最优
  • 在线性间隔内插值结果

        本节将详细介绍这些步骤:

1.1 计算逆运动学

        为了计算无碰撞轨迹,规划器必须知道四件事:起始和目标关节构型、机器人模型和环境模型。虽然起始构型是已知的(即机器人的当前构型),但目标构型往往是未知的。相反,运动规划器指令可能只传递一个目标姿势:末端执行器的笛卡尔空间目标。在这种情况下,规划器首先需要将姿态转换为达到该姿态的关节构型,这需要使用逆运动学块来完成。

1.2 规划无碰撞轨迹并优化给定的运动学约束条件

        轨迹规划的大部分工作都在该区域的两个区块中进行。这两个块都是系统对象,是一种类似于 MATLAB 功能块的文件类型,可用于在 Simulink 中运行 MATLAB 代码。但与 MATLAB 功能块不同的是,系统对象可以在代码生成和解释模式下执行,执行起来更加灵活。

8197eae83e4c4c4abbd2c7095354ef82.png

        该例程使用两个系统对象:

  • MotionPlannerCHOMP - 这是操纵器CHOMP 对象的封装程序。系统对象接受起点和目标构型以及障碍物的详细信息。它还接受机器人和静态环境细节作为参数。在内部,大部分计算由辅助文件 exampleHelperCHOMPMotionPlanner 处理,该文件创建并执行规划器。为提高性能,该代码经过了混编,最终在系统对象中调用混编后的代码来代替原始的 MATLAB 代码。您可以使用以下命令查看系统对象或运动规划器代码:
edit('MotionPlannerCHOMP.m'); % System object
edit('exampleHelperCHOMPMotionPlanner.m'); % Planner creation & execution within the system object
  • Contopptraj - 这是 TOPP-RA 求解器 contopptraj 函数的系统对象包装器。该函数采用已知轨迹,并对其重新参数化,以便在遵守所提供的速度和加速度限制的前提下尽可能地穿越该轨迹。结果就是时间最优轨迹。您可以使用 this 命令检查这段代码。
edit('Contopptraj.m')

        这两个模块会依次返回一个采样的无碰撞轨迹,在运动学约束条件下,该轨迹是时间最优的。不过,虽然 contopptraj 返回的是完整轨迹,但并不是均匀采样的。

        如前所述,规划器代码的性能依赖于 mexed 版本,该版本附后。您可以使用以下命令自行生成该代码:

generateMEXforPlanner

1.3 使用均匀步长重新采样轨迹

        一个包含插值器的系统对象用于获取非均匀采样的轨迹,并使用细粒度的均匀采样对其进行重新采样。然后,这个完整的轨迹就可以输出给目标控制器执行。

        最后,将输出重新组合为输出总线格式。下面的接口部分将对此进行详细介绍。

二、总线概述

        该模型接受机器人指令总线和运动规划响应总线,前者表明轨迹规划任务的性质,后者包含生成的轨迹和一些相关的解决方案数据。总线结构如下。

        你可以选择建立一个完全不同的界面,但必须使用相同的总线进行通信。请注意,总线有许多字段,但只有少数字段是绝对必要的。

2.1 机器人指令总线

        输入类型是机器人命令总线。通过初始化结构可以看到其结构:

busCmdToTest = motionPlannerCmdInitValue;

        有几个关键参数:

  • 请求 ID 是发送任务时的正数。在本模块中,只要计划器执行,请求 ID 就会一直传递。在父任务调度器中,请求 ID 与命令任务的 ID 进行比较,以验证任务是否已完成。
  • 任务数组是详细说明每个具体任务的结构。规划指令的主要内容就在这里。两个补充属性描述了这些任务: MaxNumTasks 表示每个命令的任务数上限,NumTasks 表示该命令提供的任务数。不过,在本模块中,这些属性未被使用,只查询第一个任务。下面将进一步详细介绍该数组。
  • ObstacleObjects 属性允许用户输入静态环境中的障碍物。所提供的障碍物数量由 NumObstacleObjects 给出,最大值由 MaxNumObstacleObjects 指定。该参数为可选参数,当障碍物对机器人的工作空间无明显阻碍时,该参数通常不会被使用。
  • InitialPositions 属性表示给定轨迹计划的起始构型。
  • MaxIterations 属性定义规划器的最大迭代次数。
  • SampleTime 属性表示规划轨迹的采样时间。

2.2 可变大小命令

        请注意,“任务 ”和 “障碍物对象 ”被初始化为 20 乘 1 的结构,但任务和所提供障碍物的数量可以变化。为适应部署要求,这些数组的大小是固定的,与设定的最大数量相对应。对于每个数组,相关参数 NumTasks 或 NumObstacleObjects 定义了规划器实际查询的项目数。

2.3 任务数组

        每个任务都存储在一个任务数组中,格式如下:

busCmdToTest.Tasks(1)

ans = struct with fields:
                    Name: [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ... ] (1x256 uint8)
                    Type: [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ... ] (1x256 uint8)
               FrameName: [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ... ] (1x256 uint8)
                       p: [3x1 double]
                  eulZYX: [3x1 double]
                       q: [6x1 double]
               MaxLinVel: 0
               MaxAngVel: 0
                  MaxVel: 0
                  Weight: 0
             MaxLinError: 0
             MaxAngError: 0
           MaxJointError: 0
    ConvergenceSpeedGain: 0
            SecurityDist: 0
           InfluenceDist: 0

        该数组有几个重要字段:

  • 名称“、”类型 “和 ”帧名 "属性用于跟踪任务细节。它们存储为固定长度的 uint8,但可以使用 char 函数转换为字符。例如,默认情况下,名称字段未指定,返回的都是空格:
char(busCmdToTest.Tasks(1).Name)
  • p 和 eulZYX 属性分别指定末端执行器的目标位置和方向(以欧拉 ZYX 序列表示)。这两个属性共同定义了末端执行器在给定计划中的目标姿态。提供这些值后,规划器随后将依靠逆运动学将末端执行器的姿态转换为目标构型。
  • q 属性可用于指定目标构型。不过,当前规划器未使用该属性。

        其余参数为可选参数,可用于为规划器提供约束条件。

2.4 障碍物对象数组

        障碍物对象数组为用户提供了另一种提供碰撞盒类型原始障碍物的方法。这个数组在本测试程序中未使用。要更深入地了解其用法,请打开以下辅助程序,该程序会根据结构化输入构建环境:

edit('exampleHelperGenerateCollisionEnvironmentInPlanner.m')

2.5 输入总线中未使用的属性

        作为输入提供的总线设计用于多个不同的子系统。这意味着许多属性可能未被使用。例如,本计划模块做了几处简化:

  • 只查询第一个任务。其他 19 项任务将被忽略。
  • 规划器只查看目标姿态。传入的任何目标构型都将被忽略。
  • 许多规划器参数(如最大线速度)与本规划器无关。

        其他规划器模块可以使用这些输入。使用该线束,您可以类似地验证

2.6 运动规划响应总线

        轨迹规划完成后,必须进行输出。首先要将轨迹组合成一个结构,提供完整的采样轨迹:

motionPlannerResponseInitValue.JointTrajectory

ans = struct with fields:
       NumPoints: 0
    MaxNumPoints: 30000
            Time: [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ... ] (1x30000 double)
        JointPos: [6x30000 double]
        JointVel: [6x30000 double]
        JointAcc: [6x30000 double]
        JointTau: [6x30000 double]

        这里的 MaxNumPoints 再次表示轨迹大小的上限。所有属性都很重要:

  • NumPoints 属性设置了轨迹实际使用的点数。例如,对于以 1000 Hz 频率采样的 5 秒轨迹,只会使用前 5000 个索引。
  • 时间属性表示轨迹的采样时间。该属性初始化为一个 1-by-MaxNumPoints 的零矩阵,计划时间占第一个 NumPoints 元素、
  • JointPos、JointVel、JointAcc 和 JointTau 分别包含关节构型、速度、加速度和挺举。它们被初始化为 N-by-MaxNumPoints 矩阵的零,但计划轨迹占据了前 N-by-NumPoints 索引。这里的 N 是指机器人的非移动关节数。对于 UR5e cobot,N 等于 6。

        最后,关节轨迹总线被插入运动规划器响应总线。该总线主要是一组标志:

motionPlannerResponseInitValue

motionPlannerResponseInitValue = struct with fields:
          RequestID: -1
             Status: -1
    JointTrajectory: [1x1 struct]
         IsPosValid: -1
         IsVelValid: -1
         IsAccValid: -1
         IsTauValid: -1

        总线具有以下属性:

  • RequestID 是任务的请求 ID。通常情况下,调用调度程序用它来验证所请求的任务是否就是被执行的任务。
  • Status(状态)为 1,表示计划已完成并提供了插值轨迹。
  • JointTrajectory 属性包含先前指定的计划轨迹。

        最后四个属性设置为 1 分别表示计划的关节位置、速度、加速度和挺举有效

三、用简单的规划任务验证控制器

        我们可以使用简单的测试线束来验证运动规划模块。该工具包旨在测试该模块必须实现的两个主要功能:

        给定当前关节构型和可到达的目标姿势,计算两个姿势之间的无碰撞轨迹

        给定当前关节构型和指定姿态下的物体,计算一条无碰撞轨迹,将机器人定位在合适的抓取姿态上

3.1 初始化测试线束的输入

        所提供的线束通过交替执行的两个独立子系统来实现这一功能。首先加载系统。

open_system('TrajectoryPlanning_Harness');

deaede2716e1484e99416c93b1fc8672.png

        接下来,初始化参数并为输入总线分配有意义的值:

busCmdToTest = motionPlannerCmdInitValue;
busCmdToTest.RequestID = int32(1);
busCmdToTest.NumTasks = uint32(4);
busCmdToTest.InitialPositions = homePosition(:);
busCmdToTest.MaxIterations = uint32(300);
busCmdToTest.SampleTime = 0.2;
busCmdToTest.NumObstacleObjects = uint32(2); % This value should be nonzero to ensure the planner runs

        具体功能在任务结构中定义。创建了两个任务。首先,定义了提取任务:

pickTask = busCmdToTest.Tasks(1);
pickTask.Name(1:length('TooltipTaskSE3')) = uint8('TooltipTaskSE3');
pickTask.Type(1:length('Pick')) = uint8('Pick');
pickTask.FrameName(1:length('Bellow')) = uint8('Bellow');
pickTask.p = [0.485; -0.0032; -0.0368];
pickTask.eulZYX = [1.2041; pi; 0];
pickTask.MaxLinVel = 0.1;
pickTask.MaxAngVel = 0.4;
pickTask.Weight = 1;
pickTask.MaxLinError = 0.01;
pickTask.MaxAngError = 0.0349;

        接下来,通过复制采摘任务并对目标构型进行一些小的编辑,创建一个放置任务:

placeTask = pickTask;
placeTask.Type(1:length('Place')) = uint8('Place');
placeTask.p = [0.1 0.6 0.07]';
placeTask.eulZYX = [1.2041; pi; 0];

3.2 使用测试线束为每个测试任务规划路径

        为每个任务运行测试线束,存储输出结果:

busCmdToTest.Tasks(1) = pickTask;
pickout = sim('TrajectoryPlanning_Harness.slx');

busCmdToTest.Tasks(1) = placeTask;
busCmdToTest.InitialPositions = [-0.2850 -1.5035 2.0352 -2.1025 -1.5708 0.0817]';
placeout = sim('TrajectoryPlanning_Harness.slx');

3.3 分析和验证结果

        为了验证模拟结果,我们将在 MATLAB 中将结果可视化。这需要使用本脚本底部定义的两个辅助函数。这两个辅助函数只是将存储的模型输出转换为可视化的有意义数据。

% Create the environment in which the robot is to be visualized
task_obst = exampleHelperGenerateCollisionEnvironmentInPlanner(uint8(targetEnv),binLength, binWidth, binHeight, binCenterPosition, binRotation, ...
    1, zeros(1,4));

3.4 可视化采摘任务结果

[pick_status, pick_task_traj, picktargetRegion] = helperReadModelData(pickout);

figure;
title('Animate the Picking Task');
show(ur5e, pick_task_traj(:,1)');
hold on
show(picktargetRegion)
showCollisionArray(task_obst);
axis equal

        完整轨迹动画

rc = rateControl(25);
for i = 1:size(pick_task_traj,2)
    drawnow;
    show(ur5e, pick_task_traj(:,i)', FastUpdate=true, PreservePlot=false);
    waitfor(rc);
end

85c3f4e4fa3e4b2499c1b378491952d4.png

3.5 可视化放置任务成果

[task_status, place_task_traj, placetargetRegion] = helperReadModelData(placeout);

figure;
title('Animate the Placing Task');
show(ur5e, place_task_traj(:,1)',Collisions="on");
hold on
show(placetargetRegion)
showCollisionArray(task_obst);
axis equal
rc = rateControl(25);
for i = 1:size(place_task_traj,2)
    drawnow;
    show(ur5e, place_task_traj(:,i)', FastUpdate=true, PreservePlot=false,Collisions="on");
    waitfor(rc);
end

9e68cfb9582c47289de0d0e7ca66a7c2.png

3.6 辅助功能 

function [task_status, task_traj, targetRegion] = helperReadModelData(out)

% Read input data
tasks = out.yout{4}.Values.Tasks(1);
tgtPoses = [tasks.p.Data; tasks.eulZYX.Data];

% Read output data
reqs = out.yout{1}.Values.Data;
status = out.yout{2}.Values.Data;
trajs = out.yout{3}.Values;

% Determine the intervals where the request changes and sort into indices
reqchanges = find(diff(reqs)~=0); %Better than unique because duplicates are not filtered out
reqidx = [[1; reqchanges+1] [reqchanges; numel(reqs)]];

% Get the data corresponding to the first req
taskIDX = 1;
taskind = reqidx(taskIDX+1,:);

% Get the task status and trajectory corresponding to the task
task_status = status(taskind(1):taskind(2));
task_trajsize = trajs.NumPoints.Data(taskind(1));
task_traj = trajs.JointPos.Data(:,1:task_trajsize,taskind(1));

% Create a target region to indicate where the robot trajectory is supposed
% to end. Since this planner treats the target orientation as Z only, the
% valid region is set as a rotation about Z.
targetPoseVec = tgtPoses(:,:,taskind(1));
targetPoseTF = [axang2rotm([0 0 1 targetPoseVec(6)]) targetPoseVec(1:3); 0 0 0 1];
targetRegion = workspaceGoalRegion('tcp',ReferencePose=targetPoseTF);
targetRegion.Bounds(4,:) = [-pi pi]; % Not strictly required but shows that with suction, this is really a region and not a specific target

end

 

 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于sklearn的机器学习应用平台 v2.0

基于sklearn的机器学习应用平台 v2.0 链接:https://pan.baidu.com/s/1nvHMTrtBmtPLT4oNXdw74A 提取码私信博主获取 关于作者 作者:小白熊 作者简介:精通python、matlab、c#语言,擅长机器学习,深度学习,机…

数据结构-4.6.KMP算法(旧版下)-朴素模式匹配算法的优化

一.绪论: 当主串字符和模式串字符不匹配时会执行jnext[j]来改变模式串的指针,但主串的指针不变。 二.求模式串的next数组: 1.例一: 如模式串abcabd,当第六个字符d匹配失败时,此时主串中前五个字符abcab都…

Golang | Leetcode Golang题解之第462题最小操作次数使数组元素相等II

题目&#xff1a; 题解&#xff1a; func partition(a []int, l, r int) int {x : a[r]i : l - 1for j : l; j < r; j {if a[j] < x {ia[i], a[j] a[j], a[i]}}a[i1], a[r] a[r], a[i1]return i 1 }func randomPartition(a []int, l, r int) int {i : rand.Intn(r-l1…

【学习笔记】零基础入门汇编语言(ARM架构+汇编的实际应用)

目录 一.汇编的前世今生 二.寄存器 三.ARM指令集 1.指令格式 2.寻址方式 3.伪指令 4.基本指令 4.1数据传输指令 4.2存储器访问指令 4.3压栈和出栈指令 4.4跳转指令 4.5算术运算指令 4.6逻辑运算指令 四.C语言与汇编混合编程 1.混合编程前置条件 2.混合编程优势 3.…

五款专业三维数据处理工具:GISBox、Cesiumlab、OSGBLab、灵易智模、倾斜伴侣深度解析

随着三维数据处理技术的广泛应用&#xff0c;尤其是在城市规划、地理信息系统&#xff08;GIS&#xff09;、工程监测等领域&#xff0c;处理倾斜摄影、三维建模以及大规模数据管理的需求日益增加。以下是五款我精心挑选的倾斜摄影和三维数据处理工具——GISBox、Cesiumlab、OS…

和鲸科技创始人范向伟:拐点即将来临,AI产业当前的三个瓶颈

在科技迅猛发展的时代&#xff0c;人工智能&#xff08;AI&#xff09;无疑已经成为引领新一轮产业革命的核心动力之一。全球企业纷纷拥抱AI技术&#xff0c;试图借助其变革力量在竞争中突围&#xff0c;然而业界对AI产业化的拐点何时来临却众说纷纭。毕竟AI技术从实验室到商业…

三 星 SCX-4521F 硒 鼓 清 零 及 一 般 故 障 维 修 浅 谈

基本参数 耗材容量:SCX-4521D3/XIL(3000页) 功 率:平均功率350W、休眠模式10W 一般故障讲解 一、三星SCX-4521F打印机更换硒鼓(或加粉)后仍显示墨粉用尽 (加粉清零、关闭碳粉通知) 按菜单------#1934(快速按完)------屏幕会有TECH字母显示------菜单------向…

PCB缺陷检测数据集 xml 可转yolo格式 ,共10688张图片

PCB缺陷检测数据集&#xff08;yolov5,v7,v8&#xff09; 数据集总共有两个文件夹&#xff0c;一个是pcb整体标注&#xff0c;一个是pcb部分截图。 整体标注有6个分类&#xff0c;开路&#xff0c;短路等都已经标注&#xff0c;标注格式为xml&#xff0c;每个文件夹下有100多张…

html内嵌其他网页iframe

在很多情况下&#xff0c;需要将其他网页内嵌到自己的网页&#xff0c;如&#xff1a; 只需要使用iframe标签即可&#xff0c;通过src属性指定网站地址即可&#xff0c;代码如下&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta ch…

苹果手机怎样一键删除照片:快速清理指南

在数字化时代&#xff0c;手机照片的积累如同记忆的沉淀&#xff0c;但过多无用的照片也会占据宝贵的存储空间。对于苹果手机用户来说&#xff0c;如何高效地一键删除照片是一个常见的需求。本文将介绍几种方法&#xff0c;帮助你快速清理苹果手机中的照片。 1. 使用系统相册的…

论文解析三: D2-Net 用于联合描述和检测局部特征的可训练CNN

目录 1.D2-Net摘要2.D2-Net关键点介绍3. Joint Detection and Description (联合检测和描述)3.1 Feature Extraction3.2 Feature Detection3.2.1 Hard feature detection &#xff08;硬特征检测&#xff09;3.2.1 Soft Feature Detection&#xff08;软特征检测&#xff09; 3…

如何在VScode中加入系统安装好的python环境

在vscode的ipynb文件中&#xff0c;加入的环境总是找不到自己电脑当中已有的环境。这可能是由于自己电脑中的python没有安装ipynb对应的包&#xff0c;因而监测不出来。

【自动驾驶】控制算法(十二)横纵向综合控制 | 从理论到实战全面解析

写在前面&#xff1a; &#x1f31f; 欢迎光临 清流君 的博客小天地&#xff0c;这里是我分享技术与心得的温馨角落。&#x1f4dd; 个人主页&#xff1a;清流君_CSDN博客&#xff0c;期待与您一同探索 移动机器人 领域的无限可能。 &#x1f50d; 本文系 清流君 原创之作&…

MP2155升降压芯片全解析——概况、性能、应用电路、输出电压调节计算

MP2155概述 功能&#xff1a; MP2155是一款高效率、低静态电流的升降压转换器&#xff0c;可在高于、低于或等于输出电压的输入电压下工作。该器件为采用单节锂离子或多节碱性电池供电的产品提供电源解决方案。 数据&#xff1a; MP2155 可在 2V 至 5.5V 的输入电压下工作&am…

<<迷雾>> 第10章 用机器做一连串的加法(2)--寄存器 示例电路

使用多个触发器可以构成一个寄存器 info::操作说明 单击按钮开关产生上升沿信号, 将 D 的输入存在 Q 端 primary::在线交互操作链接 https://cc.xiaogd.net/?startCircuitLinkhttps://book.xiaogd.net/cyjsjdmw-examples/assets/circuit/cyjsjdmw-ch10-02-register-by-multipl…

《Programming from the Ground Up》阅读笔记:p147-p180

《Programming from the Ground Up》学习第9天&#xff0c;p147-p180总结&#xff0c;总计34页。 一、技术总结 1.Physical memeory p152, Physical memory refers to the actual RAM chips inside your computer and what they contain. 物理地址指的RAM&#xff0c;即我们…

Kubernetes网络通讯模式深度解析

Kubernetes的网络模型建立在所有Pod能够直接相互通讯的假设之上&#xff0c;这构建了一个扁平且互联的网络空间。在如GCE&#xff08;Google Cloud Engine&#xff09;等云环境中&#xff0c;这一网络模型已预先配置&#xff0c;但在自建的Kubernetes集群中&#xff0c;我们需要…

深圳市步步精科技有限公司成功获得插头结构及电连接器发明专利

2024年8月20日&#xff0c;深圳市步步精科技有限公司&#xff08;以下简称“步步精”&#xff09;喜讯传来&#xff0c;公司申请的“插头结构和电连接器”专利&#xff08;授权公告号CN 118399121 B&#xff09;正式获得授权。这项创新的插头结构在数据线连接领域具有重要的应用…

[含文档+PPT+源码等]精品基于Nodejs实现的家教服务小程序的设计与实现

基于Node.js实现的家教服务小程序的设计与实现背景&#xff0c;主要源于以下几个方面&#xff1a; 一、家教市场的现状与需求 随着教育竞争的日益激烈&#xff0c;家庭对子女教育质量的重视程度不断提升&#xff0c;家教服务已成为许多家庭不可或缺的一部分。然而&#xff0c…

第三方软件测评机构简析:软件安全测试报告的内容和作用

随着数字化时代的到来&#xff0c;软件的安全性显得尤为重要。尤其在信息安全事件频发的今天&#xff0c;软件安全测试报告成为企业和开发者关注的焦点。软件安全测试报告是评估软件系统安全性的一种综合性文档&#xff0c;通常在软件开发生命周期中进行安全性测试后生成。 软…