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

news2024/11/25 16:26:09

✨✨ 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.coloradmin.cn/o/2235369.html

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

相关文章

【TS】九天学会TS语法——3.TypeScript 函数

今天学习 TypeScript 的函数&#xff0c;包括函数类型、可选参数、默认参数、剩余参数。 函数声明和表达式函数类型可选参数和默认参数剩余参数 在 TypeScript 中&#xff0c;函数是编程的核心概念之一。它们允许我们将代码组织成可重用的块&#xff0c;并提供了强大的抽象能力…

stm32不小心把SWD和JTAG都给关了,程序下载不进去,怎么办?

因为想用STM32F103的PA15引脚&#xff0c;调试程序的时候不小心把SWD和JTAD接口都给关了&#xff0c;先看下罪魁祸首 GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);//关掉JTAG&#xff0c;不关SWGPIO_PinRemapConfig(GPIO_Remap_SWJ_Disable, ENABLE);//关掉SW&am…

Rust重写万物之——从头开始编写浏览器引擎

一款用 Rust 编写的全新“轮子”最近备受关注—— 因不满大公司垄断,Gosub 项目团队用 Rust 从头开始编写了一个新的浏览器引擎,目前 star 数已超过 3k。 Gosub 项目的诞生是因为不少用户对当前的 Web 浏览器现状感到不满。 尽管市面上有许多浏览器可供选择,但其中大多数…

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

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

泷羽sec学习打卡-shodan扫描4

声明 学习视频来自B站UP主 泷羽sec,如涉及侵权马上删除文章 笔记的只是方便各位师傅学习知识,以下网站只涉及学习内容,其他的都与本人无关,切莫逾越法律红线,否则后果自负 关于shodan的那些事儿-4 一、shodan4如何查看公网ip&#xff1f;如何查看自己的ip&#xff1f;如何查看出…

杨传辉:云+AI 时代的一体化数据库|OceanBase发布会实录

在 2024 OceanBase 年度发布会 上&#xff0c; OceanBase CTO 杨传辉进行了主题为《云和 AI 时代的一体化数据库战略思考》的演讲&#xff0c;本文为演讲实录&#xff0c;欢迎阅读。 视频观看可点击&#xff1a;https://www.oceanbase.com/video/9001825 各位 OceanBase 的客…

04 深入 Oracle 并发世界:MVCC、锁、闩锁、事务隔离与并发性能优化的探索

文章目录 深入 Oracle 并发世界&#xff1a;MVCC、锁、闩锁、事务隔离与并发性能优化的探索一、多版本并发控制&#xff08;MVCC&#xff09;1.1 理论解析1.2 实践应用 二、锁与闩锁机制2.1 理论解析2.2 实践应用 三、事务隔离级别3.1 理论解析3.2 实践应用 四、死锁预防与解决…

Python-利用tkinter库编写一个exe伪恶意程序文件(下)

前言 接着上篇所讲的&#xff0c;我们已经完成了源代码的准备&#xff0c;并将其储存在了function_1.py文件中。接下来我们将把function_1.py文件编写为相对应的exe文件。那么好&#xff0c;废话不多说&#xff0c;我们直接开始。&#xff08;温馨提示&#xff1a;由于整蛊的需…

vue使用canves把数字转成图片验证码

<canvas id"captchaCanvas" width"100" height"40"></canvas>function drawCaptcha(text) {const canvas document.getElementById(captchaCanvas);const ctx canvas.getContext(2d);// 设置背景颜色ctx.fillStyle #f0f0f0;ctx.f…

商标注册流程

个人名义&#xff08;自然人&#xff09;申请准备&#xff1a;身份证复印件(签字&#xff0c;PDF格式&#xff0c;小于2M)&#xff1b;个体户执照副本复印件(签字&#xff0c;PDF格式&#xff0c;小于2M)&#xff1b;商标图样(建议黑白JPG&#xff0c;建议尺寸800*800尺寸)。公…

《ElementPlus 与 ElementUI 差异集合》Icon 图标 More 差异说明

参考 《element plus 使用 icon 图标(两种方式)》使用 icon 升级 Vue2 升级 Vue3 项目时&#xff0c;遇到命名时的实心与空心点差异&#xff01; ElementUI&#xff1a; 实心是 el-icon-more空心是 el-icon-more-outline ElementPlus&#xff1a; 实心是 el-icon-more-fill…

如何利用 Python 的爬虫技术获取淘宝天猫商品的价格信息?

以下是使用 Python 的爬虫技术获取淘宝天猫商品价格信息的两种常见方法&#xff1a; 方法一&#xff1a;使用 Selenium 一、环境准备&#xff1a; 安装 selenium 库&#xff1a;在命令行中运行 pip install selenium。下载浏览器驱动&#xff1a;如 ChromeDriver&#xff08;确…

Navicat for MySQL 错误:1251

mySql&#xff1a;8.4 Navicat for MySQL&#xff1a;11.0.10 企业版 绿色版 官网中关于mysql_native_password插件的说法&#xff1a;链接 1. 问题 连接数据库报错&#xff1a;1251 要求升级Navicat for MySQL 2. 原因 mysql中的mysql_native_password插件默认是关闭的 …

Android 如何写代码更少出现bug?借助IDE的检测代码质量插件来解决。

目录 前言 大家好呀~&#xff0c;我是前期后期&#xff0c;在网上冲浪的一名程序员&#xff0c;分享一些自己学到的知识&#xff0c;希望能够帮助大家节省时间。 如何写代码更少出现bug&#xff1f; 很多一些人可能会推荐我们&#xff0c;多看一些阿里巴巴的规范&#xff0c…

洛谷 P2113 看球泡妹子(DP)

传送门https://www.luogu.com.cn/problem/P2113 解题思路 可以设 表示前 场比赛看了 场&#xff0c;小红的满足度为 的最大精彩度。 然后可以枚举前面的一个比赛 &#xff0c;可以得到转移方程&#xff1a; 但是&#xff0c;我们发现数组空间有一点小大&#xff0c;可以…

HTAP数据库国产化改造技术可行性方案分析

一、现状及需求痛点 当前地市统一支撑平台是为地市租户提供全方位业务支持的核心系统&#xff0c;以满足地市级用户在业务处理、数据分析、用户服务及内部管理等多方面的需求。主要承载业务系统的联机事务处理&#xff08;OLTP&#xff09;与联机分析处理&#xff08;OLAP&…

ELK-ELK基本概念_ElasticSearch的配置

文章目录 一、什么是ELK&#xff1f;有什么用&#xff1f;ELK是什么&#xff1f;ElasticsearchLogstashKibana ELK的作用 二、ElasticSearch的安装与基本配置为何需要依赖JDK&#xff1f;使用yum install java-11-openjdk和使用Oracle官网提供的jdk的rpm包安装JDK的区别 参考资…

OpenAI大事记;GPT到ChatGPT参数量进化

目录 OpenAI大事记 GPT到ChatGPT参数量进化 OpenAI大事记 GPT到ChatGPT参数量进化 ChatGPT是从初代 GPT逐渐演变而来的。在进化的过程中,GPT系列模型的参数数量呈指数级增长,从初代GPT的1.17亿个参数,到GPT-2的15 亿个参数,再到 GPT-3的1750 亿个参数。模型越来越大,训练…

DDD领域分析

DDD领域分析是一种对现实业务进行建模分析的一种方法&#xff0c;它对业务问题做了分类&#xff0c;分层与抽象&#xff0c;为后面代码的编写理清了思路。 如何理解DDD呢&#xff1f;首先DDD中有许多名称&#xff0c;我这里一一列举出来&#xff1a;领域&#xff0c;子域&…

ES集群搭建(仅供自己参考)

单节点问题&#xff1a;单机的elasticsearch做数据存储&#xff0c;面临的两个问题&#xff1a;海量的数据存储问题、单节点故障。 一个节点存储的数据是有限的。 海量数据存储问题&#xff1a;将索引库从逻辑上拆分为N个分片&#xff08;shard&#xff09;&#xff0c;存储到…