当前位置: 首页 > news >正文

【Coppeliasim C++】焊接机械臂仿真

项目思维导图

该项目一共三个demo

  1. 机械臂末端走直线

2. 变位机转台转动

3.机械臂末端多点样条运动

笔记:

基于等级的蚁群系统在3D网格地图中搜索路径的方法:

基于等级的蚁群系统(Hierarchical Ant Colony System,HACS)是一种改进的蚁群优化算法。它在传统的蚁群算法基础上,通过构建等级结构来优化搜索过程。

在3D网格地图中,我们可以将地图分为多个等级层次。最高层次是整张地图的概览,地图被等分为较大的网格区域。在较低层次,每个网格区域内又被等分为更小的子区域。最后,最底层是每个子区域内的详情网格。

在搜索路径时,蚁群按照层次顺序进行。在高层次,蚁群用更加宽泛的视野搜索整个地图,找到连接开始点和目标点的大致路径区域。然后在较低层次内搜索,逐步优化路径,找到更加详细和精确的路线。

与传统蚁群相比,这种分层搜索方法可以更快地锁定搜索区域,减少无效搜索,从而提高搜索效率。同时,低层次的详细搜索也可以找到更短和更优的路径。

总之,HACS利用地图的层次信息指导搜索,使蚁群系统既有高层次的宏观视野,也有低层次的局部优化能力。这种方法可有效提高在3D网格地图中搜索路径的性能。

使用蚁群系统解决广义旅行商问题:

广义旅行商问题(Generalized Traveling Salesman Problem, GTSP)是旅行商问题的推广,使用蚁群系统可以有效解决。

GTSP问题是将多个城市分组,要求旅行商访问每个组中的一个城市,并最小化总路程。蚁群算法解GTSP步骤如下:

  1. 构建解空间。将城市分组,每个组看作为一个虚拟城市。

  2. 蚁群搜索。蚁群按照传统TSP规则搜索路径,但每经过一个虚拟城市时,会随机选择该组内的一个真实城市访问。

  3. 信息更新。当蚁群完成一轮搜索后,更新信息素,包括每个城市内的信息素和连接两个虚拟城市的信息素。

  4. 重复搜索。反复迭代上述搜索和更新过程,逐步得到更优解。

  5. 结果输出。迭代终止后,输出当前最优解作为GTSP问题的近似最优解。

这种方法融合了蚁群算法的分布式搜索能力和 GTSP 问题的组内选择要求。相比暴力算法,可以大幅减少搜索空间,更快获得近似最优解。同时也比随机算法更有针对性。因此使用蚁群系统可以高效地求解 GTSP 问题。

要在windows系统下测试需修改Timer.h:

#ifndef PROJECT_TIMER_H
#define PROJECT_TIMER_H#include <assert.h>
#include <stdint.h>
#include <time.h>
#include <windows.h>//#include <ctime>class Timer 
{public:LARGE_INTEGER frequency;LARGE_INTEGER _startTime;explicit Timer() { start(); }// void start() { clock_gettime(CLOCK_REALTIME, &_startTime); }// clock_gettime(CLOCK_MONOTONIC, &_startTime);void start() {QueryPerformanceFrequency(&frequency);QueryPerformanceCounter(&_startTime);}double getMs() { return (double)getNs() / 1.e6; }int64_t getNs() {//struct timespec now;  LARGE_INTEGER now;QueryPerformanceCounter(&now);//clock_gettime(CLOCK_MONOTONIC, &now);//return (int64_t)(now.tv_nsec - _startTime.tv_nsec) +//1000000000 * (now.tv_sec - _startTime.tv_sec);return static_cast<double>(now.QuadPart - _startTime.QuadPart) / frequency.QuadPart*1.e9;}double getSeconds() { return (double)getNs() / 1.e9; }//struct timespec _startTime;
};#endif  // PROJECT_TIMER_H

main程序源码:

/* Includes ------------------------------------------------------------------*/
#include "matplotlibcpp.h"
#include <iostream>
#include "CoppeliaSim.h"
#include "sys_log.h"
#include "core/BSplineBasic.h"
#include "core/BezierCurve.h"
#include "core/Timer.h"
#include "core/ACSRank_3D.hpp"
#include "core/read_STL.hpp"
#include "core/ACS_GTSP.hpp"/* Usr defines ---------------------------------------------------------------*/
using namespace std;
namespace plt = matplotlibcpp;
enum Pose_t
{x,y,z,alpha,beta,_gamma};#ifndef M_PI
#define M_PI 3.14159265358979323846
#define M_PI_2 M_PI/2
#endif_simObjectHandle_Type *Tip_target;
_simObjectHandle_Type *Tip_op;
_simObjectHandle_Type *Joint[6];
_simObjectHandle_Type *platform[2];
_simSignalHandle_Type *weld_cmd;
/*Test*/
STLReader model;
ACS_Rank mySearchPath;//使用基于等级的蚁群系统在基于网格的 3D 地图中搜索路径,ACSRnk_3D 被优化为自动选择搜索参数。//
ACS_GTSP GlobalRoute;//使用蚁群系统解决广义旅行商问题//
BezierCurve<float, 3> straight_line(2);//模板类BezierCurve,用于生成贝塞尔曲线//
BezierCurve<float, 2> platform_angle(2);
BS_Basic<float, 3, 0, 0, 0> *smooth_curve1;/*B样条曲线*/
Timer timer;//计时器//
int demo_type;//演示类型//
bool is_running = false;
float start_time = 0;
float total_time = 0;
float current_pt[6];//当前点//
float target_pt[6];//目标点//
std::vector<float> smooth_x, smooth_y, smooth_z;
/* Founctions ----------------------------------------------------------------*/
// float[6], float[3]
bool go_next_point(float *next, float *res)
{static float last[6] = {0};bool state = false;for (int i(0); i < 6; i++){state |= (next[i] != last[i]) ? 1 : 0;}if(state){ float start_pt[3] = {current_pt[0], current_pt[1], current_pt[2]};float next_pt[3] = {next[0], next[1], next[2]};float **ctrl_pt = new float *[3];ctrl_pt[0] = start_pt;ctrl_pt[1] = next_pt;straight_line.SetParam(ctrl_pt, total_time);start_time = timer.getMs();for (int i(0); i < 6; i++){last[i] = next[i];}}float now_time = (float)timer.getMs() - start_time;if (now_time >= total_time)return false;else{straight_line.getCurvePoint(now_time, res);printf("This point: %.3f, %.3f, %.3f \n", res[0], res[1], res[2]);return true;}
}void manual_input()
{if (is_running == true)//运行中//{if (demo_type == 1)//演示类型1  机械手//{// exit: current time > move time ?float now_time = (float)timer.getMs() - start_time;if (now_time >= total_time)is_running = false;float res[3] = {};straight_line.getCurvePoint(now_time, res);//获取下一点//target_pt[0] = res[0];target_pt[1] = res[1];target_pt[2] = res[2];std::cout << "Target(x,y,z):" << target_pt[0] << ", " << target_pt[1] << ", " << target_pt[2] << endl;}else if (demo_type == 2)//演示类型2  转台//{// exit: current time > move time ?float now_time = (float)timer.getMs() - start_time;if (now_time >= total_time)is_running = false;float res[2];platform_angle.getCurvePoint(now_time, res);//获取转台的下一点:两个转角//platform[0]->obj_Target.angle_f = res[0];platform[1]->obj_Target.angle_f = res[1];std::cout << "Target(pitch, yaw):" << res[0] << ", " << res[1] << endl;}else//其他类型//{static int i = 0;if(i < smooth_x.size()){static clock_t lastTime = clock();if (clock() - lastTime >= 10){lastTime = clock();if (smooth_x[i] - target_pt[0] < 0.3 && smooth_y[i] - target_pt[1] < 0.3&& smooth_z[i] - target_pt[2] < 0.3){target_pt[0] = smooth_x[i];target_pt[1] = smooth_y[i];target_pt[2] = smooth_z[i];std::cout << "Target(x,y,z):" << target_pt[0] << ", " << target_pt[1] << ", " << target_pt[2] << endl;i++;}}}else{is_running = false;}// // 论文和答辩中简单的演示,简单的状态机////float* res;// static int stage = 0;// switch(stage)// {//     case 0://     {//         //到第一个点//         total_time = 3000;//         float next[3] = {mySearchPath.route_points[0].x, mySearchPath.route_points[0].y, mySearchPath.route_points[0].z};//         if(go_next_point(next,res))//         {//              target_pt[0] = res[0];//              target_pt[1] = res[1];//              target_pt[2] = res[2];//                // target_pt[0] = res[0];//             // target_pt[1] = res[1];//             // target_pt[2] = res[2];//         }//         else//         {//             start_time = timer.getMs();//             stage = 1;//         }//     }//     break;//     case 1://     {////         //开始焊接,到第二个点////         weld_cmd->target = 1;//         float next[3] = {mySearchPath.route_points[1].x, mySearchPath.route_points[1].y, mySearchPath.route_points[1].z};//         if(go_next_point(next,res))//         {//             /* target_pt[0] = res[0];//              target_pt[1] = res[1];//              target_pt[2] = res[2];*///              target_pt[0] = res[0];//              target_pt[1] = res[1];//              target_pt[2] = res[2];//         }//         else{//             const std::vector<ACS_Node<float> *> *path = mySearchPath.best_matrix[1][2].getPath();//             int pt_num = (*path).size();//             float start_pt[3] = {mySearchPath.route_points[1].x, mySearchPath.route_points[1].y, mySearchPath.route_points[1].z};//             float end_pt[3] = {mySearchPath.route_points[2].x, mySearchPath.route_points[2].y, mySearchPath.route_points[2].z};//             float **ctrl_pt = new float *[pt_num];//             for (int i = 0; i < pt_num; ++i)//             {//                 ctrl_pt[i] = new float[3];//                 ctrl_pt[i][0] = (*path)[i]->pt.x;//                 ctrl_pt[i][1] = (*path)[i]->pt.y;//                 ctrl_pt[i][2] = (*path)[i]->pt.z;//             }//             smooth_curve1 = new BS_Basic<float, 3, 0, 0, 0>(pt_num);//             smooth_curve1->SetParam(start_pt, end_pt, ctrl_pt, total_time);//             start_time = timer.getMs();//             weld_cmd->target = 0;//             stage = 2;//         }//     }//     break;//     case 2://     {//         //停止焊接,到下面焊路////         float now_time = (float)timer.getMs() - start_time;//         if(now_time < total_time + 500)//         {//             smooth_curve1->getCurvePoint(now_time, res);//         }//         else//         {//             weld_cmd->target = 1;//             stage = 3;//         }//     }//     break;//     case 3://     {//         // 第二段焊路////         float next[3] = {mySearchPath.route_points[3].x, mySearchPath.route_points[3].y, mySearchPath.route_points[3].z};//         if(go_next_point(next,res))//         {//         }//         else//         {//             while(1){}//         }//     }//     break;//     default://         break;// }// target_pt[0] = res[0];// target_pt[1] = res[1];// target_pt[2] = res[2];//}}}else//未运行//{//Select type 选择类型//cout << "Please choose control type: 1) Manipulator 2) Platform 3) Demo : ";cin >> demo_type;if (demo_type == 1)//机械手//{//Set terminal pointsfloat start_pt[3] = {current_pt[0], current_pt[1], current_pt[2]};float next_pt[3];float **ctrl_pt = new float *[3];ctrl_pt[0] = start_pt;ctrl_pt[1] = next_pt;cout << "Current point:(" << current_pt[0] << ", " << current_pt[1] << ", " << current_pt[2] << ")" << endl;cout << "Next point(x, y, z) and Time(t): ";cin >> next_pt[0] >> next_pt[1] >> next_pt[2] >> total_time;straight_line.SetParam(ctrl_pt, total_time);//Set timestart_time = timer.getMs();is_running = true;}else if (demo_type == 2)//转台//{//Set terminal pointsfloat start_pt[2] = {platform[0]->obj_Data.angle_f, platform[1]->obj_Data.angle_f};float next_pt[2];float **ctrl_pt = new float *[2];ctrl_pt[0] = start_pt;ctrl_pt[1] = next_pt;cout << "Current point:(" << platform[0]->obj_Data.angle_f << ", " << platform[1]->obj_Data.angle_f << ")" << endl;cout << "Target angle(pitch, yaw) and Time(t): ";cin >> next_pt[0] >> next_pt[1] >> total_time;platform_angle.SetParam(ctrl_pt, total_time);//Set timestart_time = timer.getMs();is_running = true;}else if(demo_type == 3)//演示//{/*读取工件模型//*/model.readFile("./files/cubic.stl");const std::vector<Triangles<float>> meshes = model.TriangleList();/*搜索路径//*/mySearchPath.creatGridMap(meshes, 0.005, 10,"./files/cubic_grid_map.in");mySearchPath.searchBestPathOfPoints(0.5, "./files/cubic_weld_points.in", "./files/graph.in");//没有文件,//GlobalRoute.readFromGraphFile("./files/graph.in");GlobalRoute.computeSolution();GlobalRoute.read_all_segments(mySearchPath.best_matrix);/*曲线平滑//*/int pt_num = GlobalRoute.g_path_x.size();float start_pt[3] = {GlobalRoute.g_path_x[0], GlobalRoute.g_path_y[0], GlobalRoute.g_path_z[0]};float end_pt[3] = {GlobalRoute.g_path_x[pt_num - 1], GlobalRoute.g_path_y[pt_num - 1], GlobalRoute.g_path_z[pt_num - 1]};float **ctrl_pt = new float *[pt_num];for (int i = 0; i < pt_num; ++i){ctrl_pt[i] = new float[3];ctrl_pt[i][0] = GlobalRoute.g_path_x[i];ctrl_pt[i][1] = GlobalRoute.g_path_y[i];ctrl_pt[i][2] = GlobalRoute.g_path_z[i];}BS_Basic<float, 3, 0, 0, 0> smooth_curve(pt_num);smooth_curve.SetParam(start_pt, end_pt, ctrl_pt, 150);clock_t base_t = clock();clock_t now_t = clock()-base_t;float res[3];do{if(clock() - base_t - now_t >= 10){now_t = clock() - base_t;smooth_curve.getCurvePoint(now_t, res);smooth_x.push_back(res[0]);smooth_y.push_back(res[1]);smooth_z.push_back(res[2]);//printf("Curve point: %f, %f, %f, time:%d \n", res[0], res[1], res[2], now_t);}} while (now_t <= 150);//二次平滑//const float constrain = 0.05;pt_num = smooth_y.size();float second_start_pt[9] = {GlobalRoute.g_path_x[0], GlobalRoute.g_path_y[0], GlobalRoute.g_path_z[0],0,0,0,0,0,0}; float second_end_pt[9] = {GlobalRoute.g_path_x[pt_num - 1], GlobalRoute.g_path_y[pt_num - 1], GlobalRoute.g_path_z[pt_num - 1],0,0,0,0,0,0};float **second_pt = new float*[pt_num];for (int i = 0; i < pt_num; ++i){second_pt[i] = new float[9];second_pt[i][0] = smooth_x[i];second_pt[i][1] = smooth_y[i];second_pt[i][2] = smooth_z[i];for (int j(3); j < 9; j++)second_pt[i][j] = constrain;}smooth_x.clear();smooth_y.clear();smooth_z.clear();BS_Basic<float, 3, 2, 2, 2> second_curve(pt_num);second_curve.SetParam(second_start_pt,second_end_pt,second_pt, 6000);base_t = clock();now_t = clock()-base_t;do{if(clock() - base_t - now_t >= 50){now_t = clock() - base_t;second_curve.getCurvePoint(now_t, res);smooth_x.push_back(res[0]);smooth_y.push_back(res[1]);smooth_z.push_back(res[2]);//printf("Second point: %f, %f, %f, time:%d \n", res[0], res[1], res[2], now_t);}} while (now_t <= 6000);start_time = timer.getMs();is_running = true;}else{cout << "Unidentified type, please select again." << endl;}}
}
/**
* @brief This is the main function for user.
*/
void Usr_Main()
{//这里是主循环,可以运行我们的各部分算法//manual_input();
}/**
* @brief User can config simulation client in this function.
* @note  It will be called before entering the main loop.   
*/
void Usr_ConfigSimulation() //读取句柄//
{//添加关节对象到Joint_list,每个关节可以读写位置和速度,不用单独控制每个关节可以注释下面这段//Joint[0] = CoppeliaSim->Add_Object("IRB4600_joint1", JOINT, {SIM_VELOCITY | CLIENT_RW, SIM_POSITION | CLIENT_RW});Joint[1] = CoppeliaSim->Add_Object("IRB4600_joint2", JOINT, {SIM_VELOCITY | CLIENT_RW, SIM_POSITION | CLIENT_RW});Joint[2] = CoppeliaSim->Add_Object("IRB4600_joint3", JOINT, {SIM_VELOCITY | CLIENT_RW, SIM_POSITION | CLIENT_RW});Joint[3] = CoppeliaSim->Add_Object("IRB4600_joint4", JOINT, {SIM_VELOCITY | CLIENT_RW, SIM_POSITION | CLIENT_RW});Joint[4] = CoppeliaSim->Add_Object("IRB4600_joint5", JOINT, {SIM_VELOCITY | CLIENT_RW, SIM_POSITION | CLIENT_RW});Joint[5] = CoppeliaSim->Add_Object("IRB4600_joint6", JOINT, {SIM_VELOCITY | CLIENT_RW, SIM_POSITION | CLIENT_RW});//读写执行末端相对于器件坐标系的位姿//Tip_target = CoppeliaSim->Add_Object("IRB4600_IkTarget", OTHER_OBJECT, {SIM_POSITION | CLIENT_WO, SIM_ORIENTATION | CLIENT_WO});Tip_op = CoppeliaSim->Add_Object("IRB4600_IkTip", OTHER_OBJECT, {SIM_POSITION | CLIENT_RO, SIM_ORIENTATION | CLIENT_RO});platform[0] = CoppeliaSim->Add_Object("platform_yaw", JOINT, {SIM_POSITION | CLIENT_RW});platform[1] = CoppeliaSim->Add_Object("platform_pitch", JOINT, {SIM_POSITION | CLIENT_RW});weld_cmd = CoppeliaSim->Add_Object("weld_cmd", SIM_INTEGER_SIGNAL, {SIM_SIGNAL_OP | CLIENT_WO});/*Init value*/target_pt[x] = 1.76; //-0.2;target_pt[y] = 0.09;target_pt[z] = 1.42;target_pt[alpha] = 0;target_pt[beta] = M_PI_2 + M_PI_2/2;target_pt[_gamma] = -M_PI_2;Tip_target->obj_Target.position_3f[0] = target_pt[x] + 0;//1.7;  Tip_target->obj_Target.position_3f[1] = target_pt[y] + 0;Tip_target->obj_Target.position_3f[2] = target_pt[z] + 0;Tip_target->obj_Target.orientation_3f[0] = target_pt[alpha];Tip_target->obj_Target.orientation_3f[1] = target_pt[beta];Tip_target->obj_Target.orientation_3f[2] = target_pt[_gamma];
}/**
* @brief These two function will be called for each loop.
*        User can set their message to send or read from sim enviroment.
*/
void Usr_SendToSimulation()//设置目标位姿//
{//这里可以设置关节指令//Tip_target->obj_Target.position_3f[0] = target_pt[x] + 0; //1.7;Tip_target->obj_Target.position_3f[1] = target_pt[y] + 0;Tip_target->obj_Target.position_3f[2] = target_pt[z] + 0;Tip_target->obj_Target.orientation_3f[0] = target_pt[alpha];Tip_target->obj_Target.orientation_3f[1] = target_pt[beta];Tip_target->obj_Target.orientation_3f[2] = target_pt[_gamma];
}
//读取tip当前位姿参数//
void Usr_ReadFromSimulation()
{//这里可以读取反馈//current_pt[x] = Tip_op->obj_Data.position_3f[0] - 0; //1.7;current_pt[y] = Tip_op->obj_Data.position_3f[1] - 0;current_pt[z] = Tip_op->obj_Data.position_3f[2] - 0;current_pt[alpha] = Tip_op->obj_Data.orientation_3f[0];current_pt[beta] = Tip_op->obj_Data.orientation_3f[1];current_pt[_gamma] = Tip_op->obj_Data.orientation_3f[2];
}/**
* @brief It's NOT recommended that user modefies this function.
*        Plz programm the functions with the prefix "Usr_". 
*/
int main(int argc, char *argv[])
{/*System Logger tool init.*/std::cout << "[System Logger] Configuring... \n";std::cout << "[System Logger] Logger is ready ! \n";/*Simulation connection init.*/CoppeliaSim_Client *hClient = &CoppeliaSim_Client::getInstance();std::cout << "[CoppeliaSim Client] Connecting to server.. \n";while (!hClient->Start("127.0.0.1", 5000, 5, false)){};std::cout << "[CoppeliaSim Client] Successfully connected to server, configuring...\n";Usr_ConfigSimulation();std::cout << "[CoppeliaSim Client] Configure done, simulation is ready ! \n";while (1){// Abandon top 5 datastatic int init_num = 5;if (hClient->Is_Connected()){hClient->ComWithServer();}if (init_num > 0)init_num--;else{Usr_ReadFromSimulation();Usr_Main();Usr_SendToSimulation();}};
}

结语:demo并不完美,尤其演示3机械臂末端走样条曲线。源码具有一定学术价值,实际应用效果并不看好,或许这些算法并不适合于连续焊接场景,蚁群算法类可借鉴。仿真场景Lua脚本(焊接火花模拟)可借鉴。

The End

相关文章:

【Coppeliasim C++】焊接机械臂仿真

项目思维导图 该项目一共三个demo&#xff1a; 机械臂末端走直线 2. 变位机转台转动 3.机械臂末端多点样条运动 笔记&#xff1a; 基于等级的蚁群系统在3D网格地图中搜索路径的方法: 基于等级的蚁群系统(Hierarchical Ant Colony System,HACS)是一种改进的蚁群优化算法。它在传…...

【LeetCode】94.二叉树的中序遍历

题目 给定一个二叉树的根节点 root &#xff0c;返回 它的 中序 遍历 。 示例 1&#xff1a; 输入&#xff1a;root [1,null,2,3] 输出&#xff1a;[1,3,2]示例 2&#xff1a; 输入&#xff1a;root [] 输出&#xff1a;[]示例 3&#xff1a; 输入&#xff1a;root [1] 输…...

AWS IAM介绍

前言 AWS是世界上最大的云服务提供商&#xff0c;它提供了很多组件供消费者使用&#xff0c;其中进行访问控制的组件叫做IAM(Identity and Access Management)&#xff0c; 用来进行身份验证和对AWS资源的访问控制。 功能 IAM的功能总结来看&#xff0c;主要分两种&#xff1…...

MySQL碎片清理

为什么产生&#xff1f; 经过大量增删改的表&#xff0c;都可能存在碎片 MySQL数据结构是B树&#xff0c; 删除某一记录&#xff0c;只会标记为删除&#xff0c;后续插入一条该区间的记录&#xff0c;就会复用这个位置。 删除整个数据页的记录&#xff0c;则整个页标记为“可…...

elasticsearch操作(API方式)

说明&#xff1a;es操作索引库、文档&#xff0c;除了使用它们自带的命令外&#xff08;参考&#xff1a;http://t.csdn.cn/4zpmi&#xff09;&#xff0c;在IDEA中可以添加相关的依赖&#xff0c;使用对应的API来操作。 准备工作 搭建一个SpringBoot项目&#xff0c;DAO使用…...

Vue2.0 使用 echarts

目录 1. 配置 渲染2. 数据渲染 1. 配置 渲染 安装 echarts 依赖 npm install echarts -Smain.js&#xff0c;引入 echarts import * as echarts from echarts// 在import的后面&#xff0c;echarts的前面加一个 * as Vue.prototype.$echarts echarts从 echarts 官网直接复制…...

企业微信,阿里钉钉告警群机器人

链接&#xff1a;如何通过企业微信群接收报警通知_云监控-阿里云帮助中心...

linux下的tomcat

springboot项目端口是8080&#xff0c;部署到linux运行之后&#xff0c;为什么能检测到tomcat 手动安装tomcat&#xff0c;以下是在 Linux 系统上安装 Tomcat 的步骤&#xff1a; 下载 Tomcat 安装包。您可以从 Tomcat 官方网站&#xff08;https://tomcat.apache.org/ ↗&…...

Vue源码学习 - new Vue初始化都做了什么?

目录 前言一、创建一个 Vue 实例二、找到 Vue 构造函数三、源码分析 - Vue.prototype._init四、源码分析 - 调用 $mount 方法&#xff0c;进入挂载阶段五、总结 前言 使用Vue也有一段时间了&#xff0c;最近去阅读了Vue的源码&#xff0c;想总结分享下学到的新东西。 如果觉得…...

新零售数字化商业模式如何建立?新零售数字化营销怎么做?

随着零售行业增速放缓、用户消费结构升级&#xff0c;企业需要需求新的价值增长点进行转型升级&#xff0c;从而为消费者提供更为多元化的消费需求、提升自己的消费体验。在大数据、物联网、5G及区块链等技术兴起的背景下&#xff0c;数字化新零售系统应运而生。 开利网络认为&…...

C++语法(26)--- 特殊类设计

C语法&#xff08;25&#xff09;--- 异常与智能指针_哈里沃克的博客-CSDN博客https://blog.csdn.net/m0_63488627/article/details/131537799?spm1001.2014.3001.5501 目录 1.特殊类设计 1.设计一个类&#xff0c;不能被拷贝 C98 C11 2.设计一个类&#xff0c;只能在堆上…...

YAML+PyYAML笔记 2 | YAML缩进、分离、注释简单使用

2 | YAML缩进、分离、注释简单使用 1 简介2 缩进3 分离4 多行文本4.1 折叠块4.2 字面块4.3 引用块 5 注释5.1 行内注释5.2 块注释5.3 完美注释示例 1 简介 YAML 不是一种标记语言&#xff0c;而是一种数据格式&#xff1b;使用缩进和分离来表示数据结构&#xff0c;不需要使用…...

Array(20) 和 Array.apply(null, {length: 20})

1.Array(20) 其结果是&#xff1a; 创建了一个长度为20&#xff0c;但元素均为 empty 的数组。 2.Array.apply(null, { length: 20 }) 其结果是&#xff1a; 创建了一个长度为20&#xff0c;但元素均为 undefined 的数组。 3.异同 3.1相同 console.log(arr1[0] arr2[0]) /…...

Mind+积木编程控制小水泵给宠物喂水

前期用scratch&#xff0c;带着小朋友做了大鱼吃小鱼、桌面弹球、小学生计算器3个作品&#xff0c;小朋友收获不小。关键是小家伙感兴趣&#xff0c;做出来后给家人炫耀了一圈后&#xff0c;兴趣大增&#xff0c;嚷嚷着要做更好玩的。 最近&#xff0c;娃妈从抖音上买了个小猫喝…...

【Linux从入门到精通】进程的控制(进程替换)

本篇文章会对进程替换进行讲解。希望本篇文章会对你有所帮助 文章目录 一、进程替换概念 二、进程替换函数 2、1 execl 2、2 execlp 2、3 execv 2、3 execle 2、4 execve 三、总结 &#x1f64b;‍♂️ 作者&#xff1a;Ggggggtm &#x1f64b;‍♂️ &#x1f440; 专栏&…...

rancher平台上强制删除pod服务操作

背景&#xff1a; 在日常paas平台运维工作中需要对rancher平台进行巡检的工作&#xff0c;在巡检时发现在rancher管理界面无法删除异常的pod服务&#xff0c; 处理&#xff1a; 像这样的情况就是k8s集群的pod无法通过默认的方式去删除掉pod服务&#xff0c;这时候只能是手工强制…...

【Docker】Docker的通信安全

Docker的通信安全 前言一、Docker 容器与虚拟机的区别1. 隔离与共享2. 性能与损耗 二、Docker 存在的安全问题1. Docker 自身漏洞2. Docker 源码问题 三、Docker 架构缺陷与安全机制1. 容器之间的局域网攻击2. DDoS 攻击耗尽资源3. 有漏洞的系统调用4. 共享 root 用户权限 四、…...

c# 函数中可选参数太多,想设置最后一个参数,又不想修改前面默认参数

C#中&#xff0c;你可以使用命名参数来指定你想要设置的可选参数&#xff0c;而保留其他参数的默认值不变。通过使用命名参数&#xff0c;你可以根据需要选择要为哪些参数提供值&#xff0c;而无需按照它们在函数签名中的顺序提供参数值。 以下是一个示例&#xff0c;演示如何…...

openvino资料(1)

1、c++ - OpenVino model outputs zeroes - Stack Overflow 2、https://chinait-intel.oss-cn-beijing.aliyuncs.com/OpenVINO/Ubuntu20.04%E7%8E%AF%E5%A2%83%E4%B8%8B%E4%BD%BF%E7%94%A8OpenVINO%E9%83%A8%E7%BD%B2BiSeNetV2%E6%A8%A1%E5%9E%8B.pdf 3、c++ - How to cre...

第71篇:某银行外网打点到内网核心区红队评估复盘

Part1 前言 大家好&#xff0c;我是ABC_123。本期分享一篇ABC_123曾经做的针对一家银行的红队评估项目&#xff0c;持续时间两周&#xff0c;难度非常大&#xff0c;但是最终打到了银行核心业务区&#xff0c;今天就复盘一下全过程&#xff0c;希望红蓝双方都能得到一些启示&a…...

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…...

DockerHub与私有镜像仓库在容器化中的应用与管理

哈喽&#xff0c;大家好&#xff0c;我是左手python&#xff01; Docker Hub的应用与管理 Docker Hub的基本概念与使用方法 Docker Hub是Docker官方提供的一个公共镜像仓库&#xff0c;用户可以在其中找到各种操作系统、软件和应用的镜像。开发者可以通过Docker Hub轻松获取所…...

企业如何增强终端安全?

在数字化转型加速的今天&#xff0c;企业的业务运行越来越依赖于终端设备。从员工的笔记本电脑、智能手机&#xff0c;到工厂里的物联网设备、智能传感器&#xff0c;这些终端构成了企业与外部世界连接的 “神经末梢”。然而&#xff0c;随着远程办公的常态化和设备接入的爆炸式…...

C#学习第29天:表达式树(Expression Trees)

目录 什么是表达式树&#xff1f; 核心概念 1.表达式树的构建 2. 表达式树与Lambda表达式 3.解析和访问表达式树 4.动态条件查询 表达式树的优势 1.动态构建查询 2.LINQ 提供程序支持&#xff1a; 3.性能优化 4.元数据处理 5.代码转换和重写 适用场景 代码复杂性…...

NPOI Excel用OLE对象的形式插入文件附件以及插入图片

static void Main(string[] args) {XlsWithObjData();Console.WriteLine("输出完成"); }static void XlsWithObjData() {// 创建工作簿和单元格,只有HSSFWorkbook,XSSFWorkbook不可以HSSFWorkbook workbook new HSSFWorkbook();HSSFSheet sheet (HSSFSheet)workboo…...

R 语言科研绘图第 55 期 --- 网络图-聚类

在发表科研论文的过程中&#xff0c;科研绘图是必不可少的&#xff0c;一张好看的图形会是文章很大的加分项。 为了便于使用&#xff0c;本系列文章介绍的所有绘图都已收录到了 sciRplot 项目中&#xff0c;获取方式&#xff1a; R 语言科研绘图模板 --- sciRplothttps://mp.…...

MacOS下Homebrew国内镜像加速指南(2025最新国内镜像加速)

macos brew国内镜像加速方法 brew install 加速formula.jws.json下载慢加速 &#x1f37a; 最新版brew安装慢到怀疑人生&#xff1f;别怕&#xff0c;教你轻松起飞&#xff01; 最近Homebrew更新至最新版&#xff0c;每次执行 brew 命令时都会自动从官方地址 https://formulae.…...

Python网页自动化Selenium中文文档

1. 安装 1.1. 安装 Selenium Python bindings 提供了一个简单的API&#xff0c;让你使用Selenium WebDriver来编写功能/校验测试。 通过Selenium Python的API&#xff0c;你可以非常直观的使用Selenium WebDriver的所有功能。 Selenium Python bindings 使用非常简洁方便的A…...

微服务通信安全:深入解析mTLS的原理与实践

&#x1f525;「炎码工坊」技术弹药已装填&#xff01; 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、引言&#xff1a;微服务时代的通信安全挑战 随着云原生和微服务架构的普及&#xff0c;服务间的通信安全成为系统设计的核心议题。传统的单体架构中&…...

JS红宝书笔记 - 3.3 变量

要定义变量&#xff0c;可以使用var操作符&#xff0c;后跟变量名 ES实现变量初始化&#xff0c;因此可以同时定义变量并设置它的值 使用var操作符定义的变量会成为包含它的函数的局部变量。 在函数内定义变量时省略var操作符&#xff0c;可以创建一个全局变量 如果需要定义…...