揭秘全向轮运动学:机动艺术与上下位机通信的智慧桥梁

✨✨ Rqtz 个人主页 : 点击✨✨

🌈Qt系列专栏:点击

🎈Qt智能车上位机专栏: 点击🎈

        本篇文章介绍的是有关于全向轮运动学分析,单片机与上位机通信C++代码以及ROS里程计解算的内容。

目录

大纲

 ROS(机器人操作系统)

全向轮运动学分析

a,b,c三轮

a轮       

c轮

全向轮正运动解算公式(顺时针为正方向)

全向轮逆运动解算公式

矩阵形式

单片机与上位机通信

通信协议的设定(共9位)

上位机发送,下位机解析(将线速度序列化转换为编码器脉冲)

举例说明:

下位机发送,上位机解析(将编码器脉冲反序列化转换为线速度)

为什么说高8位大于等于128就为负数,

线速度到轮子编码器数值(转速)的转化系数

里程计速度解算

公式总结


大纲

全向轮运动学结算主要涉及到:

  • 各个轮子的速度解算
  • 顺逆时针各个轮子和速度公式
  • 速度正交分解示意图

单片机与上位机通信主要涉及到:

  • 如何将解算后的轮子转速转换为编码器数值并按照设定通信协议发送下位机
  • 如何接收下位机反馈编码器数值并转化为轮子转速
  • 涉及上位机发送与接收通信协议以及数值解编码

里程计解算主要是涉及到:

  • 根据轮子转速和imu偏航角度得到机器人在x,y轴行使距离
  • 结合ROS机器人操作系统发布里程计数据

文章最后附公式总结

 ROS(机器人操作系统)

        ROS(机器人操作系统,Robot Operating System),是专为机器人软件开发所设计出来的一套电脑操作系统架构。本文的运动学分解将结合ROS机器人操作系统进行进一步的应用。

全向轮运动学分析

        全向轮(Omni-wheels)以其独特的运动能力和灵活性,成为了众多研究者和技术爱好者关注的焦点。不同于传统的轮式移动系统,全向轮能够在水平面上实现任意方向的平滑移动,无需改变轮子的方向或进行复杂的转向操作。这种革命性的移动方式不仅极大地拓宽了机器人的应用范围,也为自动化、物流、服务机器人等领域带来了前所未有的可能性。

        图一为90度转轴驱动,图二为电机直接驱动。

a,b,c三轮

        全向轮a,b,c三个轮子的线速度分别为Va,Vb,Vc,机器人底盘整体的x轴线速度为Vx,整体的y轴线速度为Vy(以ros中的坐标系为准),机器人底盘逆时针旋转的角速度为w,轮子距离底盘中心的距离为L。其中,轮子与水平线的夹角为120度

        以顺时针方向为正方向。

a轮       

      1.  对于a轮来讲,按照图中顺时针的正方向,将机器人整体x轴线速度与y轴线速度正交分解,以Vx为例,将其分解到沿轮子方向Vx2垂直于轮子方向Vx1;以Vy为例,将其分解到沿轮子方向Vy2和垂直于轮子方向Vy1

         按照图中顺时针的正方向,a轮的和速度为Vx2+Vy2。在根据夹角60度,可得到a轮的线速度公式(机器人底盘逆时针旋转时):

        其中,由图可知,\Theta 1为30度,\Theta 2为60度。\omega L由V =\omega L得到, 由于机器人底盘逆时针旋转圆周运动在a轮的切向速度与轮子正方向相反,所以为负的\omega L

Fxy1 = Vx\cos \Theta 1+Vy\sin \Theta 1-\omega L

Fxy1 = Vx\sqrt{3}/2+Vy1/2-\omega L

       2. a轮的线速度公式(机器人底盘顺时针旋转时):

Fxy1 = Vx\cos \Theta 1+Vy\sin \Theta 1+\omega L

Fxy1 = Vx\sqrt{3}/2+Vy1/2+\omega L

b轮

同理可得

b轮的线速度公式(机器人底盘逆时针旋转时)

Fxy2 = -Vx\sin \Theta 1+Vy\cos \theta 1-\omega L

Fxy2 = -Vx\sqrt{3}/2+Vy1/2-\omega L

b轮的线速度公式(机器人底盘顺时针旋转时)

Fxy2 = -Vx\sin \Theta 1+Vy\cos \theta 1+\omega L

Fxy2 = -Vx\sqrt{3}/2+Vy1/2+\omega L

b轮中图的\theta 1为60度。

c轮

c轮的线速度公式(机器人底盘逆时针旋转时):

Fxy3=-Vy-\omega L

c轮的线速度公式(机器人底盘顺时针旋转时):

Fxy3=-Vy+\omega L

全向轮正运动解算公式(顺时针为正方向)

根据ros的标准坐标系(右手定则),在ros中速度大小都是向前,向左为正,逆时针旋转为正,所以结合ros的标准坐标系,为-wL,得出以下公式:

\begin{bmatrix} Va=Vx\sqrt{3}/2+Vy1/2-\omega L\\ Vb=-Vx\sqrt{3}/2+Vy1/2-\omega L\\ Vc=-Vy-\omega L \end{bmatrix}

全向轮逆运动解算公式

本质为解三元一次方程组,求解Vx,Vy,\omega

\begin{bmatrix} Vx = (Va-Vb)/\sqrt{3}\\ Vy=(Va+Vb-2Vc)/3)\\ \omega = -(Va+Vb+Vc)/(3L) \end{bmatrix}

矩阵形式

\begin{bmatrix} \sqrt{3}/2 & 1/2& -L\\ -\sqrt{3}/2 & 1/2& -L\\ 0& -1&-L \end{bmatrix}   \begin{bmatrix} Vx\\ Vy\\ \omega \end{bmatrix}   =   \begin{bmatrix} Va\\ Vb\\ Vc \end{bmatrix}

根据ros速度回调函数的线角速度分解轮子编码器数值函数:

/*目标速度回调函数*/
void cmd_velCB(const geometry_msgs::Twist & msg)
{  target_Vx = msg.linear.x;target_Vy = msg.linear.y; target_Vz = msg.angular.z;// ROS_INFO("x %lf",target_Vx);// ROS_INFO("y %lf",target_Vy);// ROS_INFO("z %lf",target_Vz);//逆时针旋转target_Va =  target_Vx*K1 + target_Vy*0.5 - L*target_Vz;target_Vb =  -target_Vx*K1 + target_Vy*0.5 - L*target_Vz;target_Vc =               - target_Vy     - L*target_Vz; //线速度转换为各轮子转速target_a = k_master*target_Va;target_b = k_master*target_Vb;target_c = k_master*target_Vc;// printf("Va=%dfm/s, Vb=%dfm/s, Vc=%dfm/s \n",target_a,target_b,target_c);/*发送小车数据到下位机*/send_Data();
}

单片机与上位机通信

通信协议的设定(共9位)

  • 包头:0xFF 0xFE
  • a,b,c三个电机各两位(高八位/低八位)[][] [][], [][] [][], [][] [][]
  • 异或校验位 [][]Va=0.4*\sqrt{3}/2+0+0 = 0.4*0.866 \approx 0.35

上位机发送,下位机解析(将线速度序列化转换为编码器脉冲)


        上位机(ros)发送线速度Vx,Vy,Vz——>三个轮子线速度Va,Vb,Vc——>转换到编码器脉冲数(16位数据)Na,Nb,Nc——>再取高八位,低八位Na1,Na2;Nb1,Nb2;Nc1,Nc2


其中用有符号的16位数据来存储三个轮子的编码器的脉冲数,数值的正负来表示电机的正转反转,但取过高低八位的数据是无符号的。

发送小车数据到下位机函数实现

/*发送小车数据到下位机*/
void send_Data()
{//发送标志位s_buffer[0] = 0xFF;s_buffer[1] = 0xFE;   //A电机速度s_buffer[2] = target_a>>8;//取高八位s_buffer[3] = target_a&0x00ff;//取低八//B电机速度s_buffer[4] = target_b>>8;s_buffer[5] = target_b&0x00ff;//C电机速度s_buffer[6] = target_c>>8;s_buffer[7] = target_c&0x00ff;//异或校验位(2-7位校验)unsigned char check_num =0;for(int i=2;i<8;i++){check_num ^= s_buffer[i];// printf(" %d ",s_buffer[i]);}s_buffer[8]=check_num;//发送9位数据my_serial.write(s_buffer,9);
}

如何将一个16位数据取到高低八位:

取到高八位方法:右移八位(>>8)

取到低八位方法:与上0x00ff(&0x00ff)

举例说明:

若上位机(ros)发送仅有Vx = 0.4m/s的x轴线速度,Vy = 0,\omega = 0.

(1).带入前面提到的正运动学公式得到a,b,c轮子的线速度:

Va=0.4\ast \sqrt{3}/2+0+0 \approx 0.35   

Vb=-0.4\ast \sqrt{3}/2+0+0 \approx -0.35

Vc = 0

(2).由轮子线速度得到编码器数值

线速度到轮子编码器数值(转速)的转化系数为 k = 320/\pi/0.152(下方有解释)

相乘即可

Na=0.35\ast(320/\pi /0.152) = 233

Nb=-0.35\ast(320/\pi /0.152) = -233

Nc=0

(3).分别取到高八位,低八位

        Na = 233,233为正数,10进制233转为二进制(233 = 128+64+32+8+1)——>1110 1001(8位)——>转为16位 0000 0000 1110 1001

高八位:0000 0000 1110 1001 右移8位 >>8 得到 0000 0000 ——>0 A电机高8位

低八位:0000 0000 1110 1001 与上0x00ff(&0x00ff) 得到 1110 1001 ——>233 A电机低8位


        Nb = -233,-233为负数(需要转为补码的形式),-233的绝对值233转为二进制——>0000 0000 1110 1001 ——>取反加1 得到1111 1111 0001 0111

高八位:1111 1111 0001 0111右移8位 >>8 得到 1111 1111 ——>255 B电机高8位

低八位:1111 1111 0001 0111 与上0x00ff(&0x00ff) 得到 0001 01111 ——>23 B电机低8位

        因此得到一个结论是:如果有一个电机的的高8位为255(或者大于等于128),就为负数,那么该电机一定是在反转


下位机发送,上位机解析(将编码器脉冲反序列化转换为线速度)

由上述可知,上位机向下位机发送了一帧数据

0xFF 0xFE 00 233 255 23 00 00 校验位,如果下位机反馈回来的数据同样也是

0xFF 0xFE 00 233 255 23 00 00 ,那么我们如何将这一帧数据算回机器人底盘的线速度Vx,Vy与角速度Vz呢?

解答:

        首先判断数据是正数还是负数,判断方法为看最高位(符号位)是0还是1,是0在则为正数,是1则为负数。

        对于A电机的两位 00 233,高8位的最高位为0,则为正数,所以还原后的A电机的编码器脉冲数为0*256+233*1 = 233。(高8位乘以256,低8位乘以1的原因是:16位的数据拆分为高8位,低8位,高8位基数为2^8=256,低8位基数2^0=1。)

        对于B电机的两位 255 23,高8位1111 1111 最高位为1,所以为负数,负数以补码的形式存在,高8位取反0000 0000 ,低8位取反加1,23二进制0001 0111 取反 1110 1000 加1后 1110 1001 转为二进制后为233,因为是负数,所以加个负号为-233。

        对于c电机为0.

所以反序列化后的编码器数值

Na = 233 Nc = -233 Nc = 0

        再得到轮子的线速度,当时发给下位机的时候乘以的是那个转化系数,这时候接收下位机转换后得除以那个转化系数(320/\pi/0.152)。

Va = 233 / (320/\pi/0.152) = 0.35

Vb = -233 / (320/\pi/0.152) = -0.35

Vc = 0

带入前面提到的逆运动学公式得到底盘整体的Vx,Vy,Vz线速度:

Vx = (Va-Vb)/\sqrt{3} = 0.4  

Vy=0

Vz =0

和上位机发送的一摸一样。

上位机解码下位机数据的代码实现:

/*右移七位,判断第一位符号位0是否为1,是的话就是负数*/
if(r_buffer[0]>>7==1){
/*补码转原码后减一*/
r_buffer[0]=~r_buffer[0];
r_buffer[1]=~(r_buffer[1]-0x01);
real_Va = -(r_buffer[0]*256+r_buffer[1])/ k;// printf("a电机反转");}
else real_Va = (r_buffer[0]*256+r_buffer[1])/ k;                        if(r_buffer[2]>>7==1){
r_buffer[2]=~r_buffer[2];
r_buffer[3]=~(r_buffer[3]-0x01);
real_Vb = -(r_buffer[2]*256+r_buffer[3])/ k;
//  printf("b电机反转");
}  
else real_Vb = (r_buffer[2]*256+r_buffer[3])/ k;
if(r_buffer[4]>>7==1){
r_buffer[4]=~r_buffer[4];
r_buffer[5]=~(r_buffer[5]-0x01);
real_Vc = -(r_buffer[4]*256+r_buffer[5])/ k;
}
else real_Vc = (r_buffer[4]*256+r_buffer[5])/ k;

为什么说高8位大于等于128就为负数,

为什么说高8位大于等于128就为负数,因为对于一个int16位数据,他的数据总数位2^16 = 65535,又因为是有符号的,所以正数和负数各占一半,最大正整数为32767,最小负整数为-32767.

        32767——>二进制0111 1111 1111 1111(最高位为0,高八位数值为127(64+32+16+8+4+2+1))

        -32767——>绝对值的二进制0111 1111 1111 1111——>取反1000 0000 0000 0000——>加1——>1000 0000 0000 0001(最高位符号位为1,高八位数值为128)

        所以说高八位128是正数与负数的连接处,也是电机正转与反转的连接处。

总结公式

若高八位最高位符号位为0,即正数时

Va = (Na1*256+Na2*1)/K

若高八位最高位符号位为1,即负数时

Va =( -[\sim Na1*256+\sim (Na2-0x01)])/K

Na1为高8位,Na2为低8位,~为取反,k值为编码器数值到车轮线速度的转化系数。

线速度到轮子编码器数值(转速)的转化系数

车轮线速度到编码器数值公式推算

设车轮直径L,编码器CPR 为N,采样周期为T,单周期下编码器反馈计数值为n,车轮线速度为v

显然单周期T时间下车轮行进距离s = v*T

又:s =π*L * n/N

v = [π*L /( T*N ) ]*n

本车中L = 0.152m,编码器CPR = 32000,采样周期为10ms = 0.01s

∴ v = [π*0.152/( 0.01*32000 ) ]*n= (π*0.152/320)*n

里程计速度解算

如图

底盘向左偏移了yaw个弧度,将Vx和Vy分解到X_dis和y_dis坐标轴上得到

x = Vx\ast \cos(yaw)-Vy\ast \sin (yaw)

y = Vx\ast \sin(yaw)+Vy\ast \cos (yaw)

在接收下位机的循环中,获取时间

current_time = ros::Time::now();//获得当前时间
double dt = (current_time - last_time).toSec();//转换成秒
last_time = current_time;

计算里程计数据公式(累加)

x += (Vx\ast \cos(yaw)-Vy\ast \sin (yaw))\ast dt

y += (Vx\ast \sin(yaw)+Vy\ast \cos (yaw))\ast dt

在ros中发布里程计数据

        //里程计累计x行驶距离X_dist += (real_Vx*cos(Yaw)-real_Vy*sin(Yaw))*dt;//里程计累计y行驶距离Y_dist += (real_Vx*sin(Yaw)+real_Vy*cos(Yaw))*dt; //四元数变量geometry_msgs::Quaternion odom_quat = tf::createQuaternionMsgFromYaw(Yaw);        //定义里程计对象nav_msgs::Odometry odom;//载入里程计时间戳odom.header.stamp = current_time; //里程计的父子坐标系odom.header.frame_id = "odom";odom.child_frame_id = "base_link";       //里程计位置数据:x,y,z,方向odom.pose.pose.position.x = X_dist;     odom.pose.pose.position.y = Y_dist;odom.pose.pose.position.z = 0.0;odom.pose.pose.orientation = odom_quat;       //载入线速度和角速度odom.twist.twist.linear.x = real_Vx;odom.twist.twist.linear.y = real_Vy;odom.twist.twist.angular.z = real_Vz;if(!real_Vx || !real_Vy || !real_Vz){odom.pose.covariance = {1e-9, 0, 0, 0, 0, 0,       0, 1e-3, 1e-9, 0, 0, 0,0, 0, 1e6, 0, 0, 0,0, 0, 0, 1e6, 0, 0,0, 0, 0, 0, 1e6, 0,0, 0, 0, 0, 0, 1e-9};odom.twist.covariance = {1e-9, 0, 0, 0, 0, 0,      0, 1e-3, 1e-9, 0, 0, 0,0, 0, 1e6, 0, 0, 0,0, 0, 0, 1e6, 0, 0,0, 0, 0, 0, 1e6, 0,0, 0, 0, 0, 0, 1e-9};}else{odom.pose.covariance = {1e-3, 0, 0, 0, 0, 0,       0, 1e-3, 0, 0, 0, 0,0, 0, 1e6, 0, 0, 0,0, 0, 0, 1e6, 0, 0,0, 0, 0, 0, 1e6, 0,0, 0, 0, 0, 0, 1e3};odom.twist.covariance = {1e-3, 0, 0, 0, 0, 0,      0, 1e-3, 0, 0, 0, 0,0, 0, 1e6, 0, 0, 0,0, 0, 0, 1e6, 0, 0,0, 0, 0, 0, 1e6, 0,0, 0, 0, 0, 0, 1e3};}

其中odom_quat指的是根据偏航角yaw来获取四元数数据,并放入odom里程计的话题类型中。

公式总结

ROS标准坐标系下全向轮正运动解

\begin{bmatrix} Va=Vx\sqrt{3}/2+Vy1/2-\omega L\\ Vb=-Vx\sqrt{3}/2+Vy1/2-\omega L\\ Vc=-Vy-\omega L \end{bmatrix}

ROS标准坐标系下全向轮逆运动解

\begin{bmatrix} Vx = (Va-Vb)/\sqrt{3}\\ Vy=(Va+Vb-2Vc)/3)\\ \omega = -(Va+Vb+Vc)/(3L) \end{bmatrix}

ROS标准坐标系下全向轮正运动解(矩阵形式)

\begin{bmatrix} \sqrt{3}/2 & 1/2& -L\\ -\sqrt{3}/2 & 1/2& -L\\ 0& -1&-L \end{bmatrix}   \begin{bmatrix} Vx\\ Vy\\ \omega \end{bmatrix}   =   \begin{bmatrix} Va\\ Vb\\ Vc \end{bmatrix}

轮子二进制编码器数据解码到轮子线速度

若高八位Na1最高位符号位为0,即正数时

Va = (Na1*256+Na2*1)/K

若高八位Na1最高位符号位为1,即负数时,~为取反

Va =( -[\sim Na1*256+\sim (Na2-0x01)])/K

K为线速度到轮子编码器数值(转速)的转化系数

ROS标准坐标系下里程计运动(累加)解算

x += (Vx\ast \cos(yaw)-Vy\ast \sin (yaw))\ast dt

y += (Vx\ast \sin(yaw)+Vy\ast \cos (yaw))\ast dt

上述内容如果有误,请及时指正批评,谢谢大家!

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

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

相关文章

移远通信推出八款天线新品,覆盖5G、4G、Wi-Fi和LoRa领域

近日&#xff0c;全球领先的物联网整体解决方案供应商移远通信宣布&#xff0c;再次推出八款高性能天线新品&#xff0c;进一步丰富其天线产品阵容&#xff0c;更好地满足全球客户对高品质天线的更多需求。具体包括5G超宽带天线YECT005W1A和YECT004W1A、5G天线YECT028W1A、4G天…

【设计模式系列】桥接模式(十三)

一、什么是桥接模式 桥接模式&#xff08;Bridge Pattern&#xff09;是一种结构型设计模式&#xff0c;其核心目的是将抽象部分与实现部分分离&#xff0c;使它们可以独立地变化。这种模式主要用于处理那些在设计时无法确定实现细节的场合&#xff0c;或者需要在多个实现之间…

Java多态和继承(下篇)

今天接着学习多态和继承 目录 1 继承1.1 再谈初始化1.2 protect关键字1.3 继承方式1.4 final 关键字1.5 组合 2 多态2.1 多态的概念2.2 多态实现条件2.3 重写2.4 向上转型和向下转型2.4.1 向上转型2.4.2 向下转型 2.5 多态的优缺点2.6 避免在构造方法中使用重写的方法 总结 1 继…

动态规划理论基础和习题【力扣】【算法学习day.25】

前言 ###我做这类文档一个重要的目的还是给正在学习的大家提供方向&#xff08;例如想要掌握基础用法&#xff0c;该刷哪些题&#xff1f;&#xff09;我的解析也不会做的非常详细&#xff0c;只会提供思路和一些关键点&#xff0c;力扣上的大佬们的题解质量是非常非常高滴&am…

数据结构之顺序表(C语言)

1 线性表 线性表是n个具有相同特性的数据元素的有限序列&#xff0c;是一种在实际中广泛应用的数据结构&#xff0c;常见的线性表有&#xff1a;顺序表、链表、栈、队列、字符串等。 线性表在逻辑上是线性结构&#xff0c;也就说是连续的一条直线。但是在物理结构上并不一定是…

Qt——窗口

一.窗口概述 Qt 窗口是通过 QMainWindow 类来实现的。 QMainWindow是一个为用户提供主窗口程序的类&#xff0c;继承QWidget类&#xff0c;并且提供一个预定义的布局。包含一个菜单栏&#xff08;menu bar&#xff09;&#xff0c;多个工具栏&#xff08;tool bars&#xff0…

长亭那个检测能力超强的 WAF,出免费版啦

告诉你们一个震撼人心的消息&#xff0c;那个检测能力超强的 WAF——长亭雷池&#xff0c;他推出免费社区版啦&#xff0c;体验地址见文末。 八年前我刚从学校毕业&#xff0c;在腾讯做安全研究&#xff0c;看到宇森在 BlackHat 上演讲的议题 《永别了&#xff0c;SQL 注入》 …

漏洞分析 | Spring Framework路径遍历漏洞(CVE-2024-38816)

漏洞概述 VMware Spring Framework是美国威睿&#xff08;VMware&#xff09;公司的一套开源的Java、JavaEE应用程序框架。该框架可帮助开发人员构建高质量的应用。 近期&#xff0c;网宿安全演武实验室监测到Spring Framework在特定条件下&#xff0c;存在目录遍历漏洞&…

tp接口 入口文件 500 错误原因

一、描述 二、可能的原因 1、runtime目录没权限 2、关闭了Tp记录日志的功能 3、关闭debug调试模式 4、关闭了debug模式还是报错 一、描述 Thinkphp项目本地正常&#xff0c;上传到线上后静态文件访问正常&#xff0c;访问tp接口报500错误。 经调试发现&#xff0c;在php入…

第07章 运算符的使用

一、算数运算符 算术运算符主要用于数学运算&#xff0c;其可以连接运算符前后的两个数值或表达式&#xff0c;对数值或表达式进行加 &#xff08;&#xff09;、减&#xff08;-&#xff09;、乘&#xff08;*&#xff09;、除&#xff08;/&#xff09;和取模&#xff08;%&a…

十七 MyBatis的注解式开发

十七、MyBatis的注解式开发 mybatis中也提供了注解式开发方式&#xff0c;采用注解可以减少Sql映射文件的配置。 当然&#xff0c;使用注解式开发的话&#xff0c;sql语句是写在java程序中的&#xff0c;这种方式也会给sql语句的维护带来成本。 官方是这么说的&#xff1a; 使…

用 Python 写了一个天天酷跑(附源码)

Hello&#xff0c;大家好&#xff0c;给大家说一下&#xff0c;我要开始装逼了 这期写个天天酷跑玩一下叭&#xff01; 制作一个完整的“天天酷跑”游戏涉及很多方面&#xff0c;包括图形渲染、物理引擎、用户输入处理、游戏逻辑等。由于Python是一种高级编程语言&#xff0c;…

Kettle——CSV文件转换成excel文件输出

1.点击—文件—新建—转换 拖入两个组件&#xff1a; 按shift&#xff0b;鼠标左击建立连接&#xff0c;并点击主输出步骤&#xff0c; 点击CSV文件输入&#xff0c;选择浏览的csv文件&#xff0c;然后点击确定 同样&#xff0c;Excel也同上&#xff0c;只是要删除这个xls 并…

高效管理iPhone存储:苹果手机怎么删除相似照片

在使用iPhone的过程中&#xff0c;我们经常会遇到存储空间不足的问题&#xff0c;尤其是当相册中充满了大量相似照片时。这些照片不仅占用了宝贵的存储空间&#xff0c;还可能使iPhone出现运行卡顿的情况。因此&#xff0c;我们迫切需要寻找苹果手机怎么删除相似照片的方法&…

用示例来看C2Rust工具的使用和功能介绍

C2Rust可以将C语言的源代码转换成Rust语言的源代码。下面是一个简单的C语言代码示例&#xff0c;以及使用c2Rust工具将其转换为Rust安全代码的过程。 C语言源代码示例 // example.c #include <stdio.h>int add(int a, int b) {return a b; }int main() {int result a…

赛普EAP平台 Download.aspx 任意文件读取漏洞复现

0x01 产品描述&#xff1a; ‌赛普EAP平台‌是一款专门为房地产企业打造的数字化管理系统&#xff0c;旨在帮助企业实现业务流程的优化、管理效率的提升和客户体验的改善。该系统集成了项目管理、销售管理、客户关系管理、财务管理、报表分析等多个模块&#xff0c;能够满足企业…

前端三件套-css

一、元素选择器 元素选择器&#xff1a;利用标签名称。p,h1-h6...... 行内样式&#xff08;内联样式&#xff09;&#xff1a;例如<p style"color:red;font-size:50px"> id选择器&#xff1a;针对某一个特定的标签来使用。以#定义。 class&#xff08;类&a…

服务器被攻击排查记录

起因 我的深度学习的所有进程突然被killed&#xff0c;我以为是检修&#xff0c;后面发现好像简单的python代码可以正常运行。但是我的训练进程一启动就会被killed 第一时间没有用htop查看cpu&#xff0c;用top看着挺正常的&#xff0c;但是后面看htop&#xff0c;全是绿的&a…

项目实战:基于Linux的Flappy bird游戏开发

一、项目介绍 项目总结 1.按下空格键小鸟上升&#xff0c;不按小鸟下落 2.搭建小鸟需要穿过的管道 3.管道自动左移和创建 4.小鸟撞到管道游戏结束 知识储备 1.C语言 2.数据结构-链表 3.Ncurses库 4.信号机制 二、Ncurses库介绍 Ncurses是最早的System V Release 4.0 (SVr4)中…

抖音小程序看广告变现秘籍:构建用户粘性与点击收益长期价值解析

在抖音小程序看广告变现的宏伟蓝图中&#xff0c;构建用户粘性和挖掘用户长期价值是核心环节&#xff0c;这是实现丰厚收益和打造高效盈利新引擎的重要保障。 要构建用户粘性&#xff0c;首先要提供优质且持续更新的内容。以一个知识科普类小程序为例&#xff0c;需要不断推出新…