【自适应和反应式机器人控制】编程练习 1.1:计算最优轨迹 + 编程练习 1.3:基于三阶多项式的闭式时变轨迹发生器

2.1 编程练习 1.1:计算最优轨迹

书籍对应:编程练习 Ex1.1.2,第8页

此练习的目的是让读者熟悉应用于机械臂运动的基本优化方法。打开chp1_ex1.2.m代码文件,该代码生成一个四关节机械臂的绘图。编辑代码以完成以下任务:

  1. 编写理论练习中冗余机械臂的优化问题,该机械臂在三维空间中运动,因此有一个三维(3D)吸引点。假设关节是依次连接的。尝试将目标位置移动到空间中的不同位置,并比较三个优化的轨迹解。你能找到一个使(b)和(c)的解相同的配置吗?

    • ( a ) 最小化到达目标的时间 T f T_f Tf
    • ( b ) 跟随笛卡尔空间中的最短路径
    • ( c ) 跟随关节空间中的最短路径

使用MATLAB的模型预测控制类

我们使用MATLAB中的模型预测控制(Model Predictive Control, MPC)类来处理数值优化。你只需要定义与书中每个问题对应的代价函数。为此,可以将不同组合的变量XU填入cost变量中,分别表示最优轨迹和最优输入,按行向量存储。

公式定义如下:

X = [ X 0 ⋮ X N ] = [ q 0 1 q 0 2 q 0 3 q 0 4 ⋮ ⋮ ⋮ ⋮ q N 1 q N 2 q N 3 q N 4 ] \mathbf{X} = \begin{bmatrix} \mathbf{X}_0 \\ \vdots \\ \mathbf{X}_N \end{bmatrix} = \begin{bmatrix} q_0^1 & q_0^2 & q_0^3 & q_0^4 \\ \vdots & \vdots & \vdots & \vdots \\ q_N^1 & q_N^2 & q_N^3 & q_N^4 \end{bmatrix} X= X0XN = q01qN1q02qN2q03qN3q04qN4

U = [ U 0 ⋮ U N ] = [ q ˙ 0 1 q ˙ 0 2 q ˙ 0 3 q ˙ 0 4 T f ⋮ ⋮ ⋮ ⋮ ⋮ q ˙ N 1 q ˙ N 2 q ˙ N 3 q ˙ N 4 T f ] \mathbf{U} = \begin{bmatrix} \mathbf{U}_0 \\ \vdots \\ \mathbf{U}_N \end{bmatrix} = \begin{bmatrix} \dot{q}_0^1 & \dot{q}_0^2 & \dot{q}_0^3 & \dot{q}_0^4 & T_f \\ \vdots & \vdots & \vdots & \vdots & \vdots \\ \dot{q}_N^1 & \dot{q}_N^2 & \dot{q}_N^3 & \dot{q}_N^4 & T_f \end{bmatrix} U= U0UN = q˙01q˙N1q˙02q˙N2q˙03q˙N3q˙04q˙N4TfTf

解释:

X表示机械臂的最优轨迹,其值为机械臂各个关节的位置信息(角度等)。U表示最优输入,包含关节的速度信息和达到目标所需的总时间 ( T_f )。通过定义合适的代价函数,MPC可以计算出最优轨迹和输入,使得机械臂满足上述不同的优化目标。

在这里, [ q 1 , q 2 , q 3 , q 4 ] [q^1, q^2, q^3, q^4] [q1,q2,q3,q4] 表示机器人的四个关节位置,而 [ q ˙ 1 , q ˙ 2 , q ˙ 3 , q ˙ 4 ] [\dot{q}^1, \dot{q}^2, \dot{q}^3, \dot{q}^4] [q˙1,q˙2,q˙3,q˙4] 表示四个关节的速度。 T f T_f Tf 是轨迹的终止时间。该轨迹由 N N N个点组成,可以通过以下代码获取:

% 轨迹中的路径点数量:
N = data.PredictionHorizon

需要修改的三个函数分别是 minimumTime()minimumTaskDistance()minimumJointDistance(),它们位于文件底部。你可以尝试不同的代价函数,并在MATLAB中运行相应的部分,查看它对最终轨迹的影响。
注意:某些目标函数可能需要几秒钟才能解决。

你可以使用雅可比矩阵 J ( q ) J(q) J(q)来根据关节速度计算小位移 δ x \delta x δx δ x = J ( q ) ∗ q ˙ ∗ δ t \delta x = J(q) * \dot{q} * \delta t δx=J(q)q˙δt。可以使用以下MATLAB函数来计算雅可比矩阵:

% 输入 4x1 关节位置向量 q,输出 3x4 雅可比矩阵:
jacobian = robot.fastJacobian(q);

解释:

  • N = data.PredictionHorizon 用于获取轨迹中路径点的数量。
  • 文件中定义了三个不同的代价函数 minimumTime()minimumTaskDistance()minimumJointDistance(),分别用于实现不同的优化目标:最小化时间、最小化任务空间中的距离和最小化关节空间中的距离。可以通过修改这些代价函数来观察对轨迹的影响。
  • 使用雅可比矩阵 J ( q ) J(q) J(q)可以将关节速度转换为笛卡尔空间中的小位移,这在计算机器人的实际路径时非常有用。
  • robot.fastJacobian(q) 是MATLAB中的一个函数,用于快速计算给定关节位置下的雅可比矩阵。

通过这些函数和工具,您可以生成并优化机器人的运动轨迹。

chp1_ex1_2

这段代码实现了一个控制机器人手臂的优化控制任务,目的是计算从当前配置到目标位置的最优轨迹。在代码中,定义了三个优化目标:最小时间最小笛卡尔空间距离最小关节空间距离。每个优化任务都需要定义其对应的成本函数。下面是每个任务成本函数的详细补充和解释。

补全代码-实现每个任务的成本函数,以满足优化目标

%% %%%%%%%%%%%%% User defined cost functions %%%%%%%%%%%%% %%
%% ------ Write your code below for Question 2 ------
%  vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv %%% Task 1: Minimum time 
% This function minimizes the time scaling parameter Tf to minimize
% trajectory time
function cost = minimumTime(X, U, e, data, robot, target)% The cost is simply the final time, which we want to minimize.% U(5) is the final time of the trajectory, representing the overall% time needed to reach the target position.cost = U(5); % Minimize the total trajectory time
end% Task 2: Minimum distance in task space 
% This function integrates dx = J*dq to minimize Cartesian trajectory length
% You can obtain the Jacobian J at configuration q using
% J = robot.fastJacobian(q)
% USE THE SQUARE OF THE NORM FOR NUMERICAL STABILITY
function cost = minimumTaskDistance(X, U, e, data, robot, target)% Initialize costcost = 0;% Loop over the prediction horizonfor i = 1:data.PredictionHorizon% Get the joint angles (state) for the current timestepq = X(i, :)';% Get the joint velocities (input) for the current timestepdq = U(i, 1:4)';% Compute the Jacobian J at the current configurationJ = robot.fastJacobian(q);% Calculate the Cartesian velocity dx = J * dqdx = J * dq;% Increment the cost by the square of the norm of dx for stabilitycost = cost + norm(dx)^2;end
end% Task 3: Minimum distance in joint space 
% This function integrates dq to minimize joint trajectory length
% USE THE SQUARE OF THE NORM FOR NUMERICAL STABILITY
function cost = minimumJointDistance(X, U, e, data, robot, target)% Initialize costcost = 0;% Loop over the prediction horizonfor i = 1:data.PredictionHorizon% Get the joint velocities (input) for the current timestepdq = U(i, 1:4)';% Increment the cost by the square of the norm of dq for stabilitycost = cost + norm(dq)^2;end
end

解释每个任务的成本函数

  1. Task 1: Minimum Time

    • 目标:最小化到达目标位置的时间。
    • 实现:时间由控制输入的最后一个分量 ( U(5) ) 表示,这个分量代表整个轨迹的最终时间。因此,成本函数 minimumTime 仅仅返回 ( U(5) ) 的值,以最小化总时间。
    • 公式:cost = U(5);
  2. Task 2: Minimum Distance in Task Space

    • 目标:最小化机器人在笛卡尔空间(任务空间)中的移动距离。
    • 实现:
      • 使用雅可比矩阵 J J J 将关节速度 d q dq dq 转换为任务空间速度 d x dx dx
      • 计算每个时间步中 d x dx dx的平方范数并累加到成本函数中。
      • 使用平方范数可以提高数值稳定性。
    • 公式:
      cost = ∑ i = 1 PredictionHorizon ∥ J ( q ) ⋅ d q ∥ 2 \text{cost} = \sum_{i=1}^{\text{PredictionHorizon}} \| J(q) \cdot dq \|^2 cost=i=1PredictionHorizonJ(q)dq2
  3. Task 3: Minimum Distance in Joint Space

    • 目标:最小化机器人在关节空间中的移动距离。
    • 实现:
      • 直接计算每个时间步中关节速度 d q dq dq的平方范数并累加到成本函数中。
      • 同样地,使用平方范数可以提高数值稳定性。
    • 公式:
      cost = ∑ i = 1 PredictionHorizon ∥ d q ∥ 2 \text{cost} = \sum_{i=1}^{\text{PredictionHorizon}} \| dq \|^2 cost=i=1PredictionHorizondq2

其他说明

  • data.PredictionHorizon 表示优化过程中预测的时间步数。
  • robot.fastJacobian(q) 是用来计算在配置 q q q 下的雅可比矩阵的函数。
  • norm() 函数用于计算向量的范数,使用平方范数有助于数值优化的稳定性。
使用平方范数有助于数值优化的稳定性

如果不使用平方,第3步求解会出错

Slack variable unused or zero-weighted in your custom cost function.
All constraints will be hard. OPTIMIZATION SUCCESSFUL
--------- Reached target in 0.93489 seconds ---------
Elapsed time is 0.374180 seconds.
Press space to continue…
Slack variable unused or zero-weighted in your custom cost function. All constraints will be
hard. OPTIMIZATION SUCCESSFUL
--------- Reached target in 5 seconds ---------
Elapsed time is 0.731092 seconds. Press space to continue…
Slack variable unused or zero-weighted in your custom cost function. All constraints will be
hard.
Warning: Solver failed. Try relaxing some of your constraints In
MPC4DOF/solveOptimalTrajectory (line 146) In chp1_ex1_2 (line 54)

--------- Reached target in 1.5 seconds --------- Elapsed time is 0.343741 seconds.

chp1_ex1_1-编程练习 1.3:闭式轨迹 [可选]

书籍对应:编程练习 Ex1.1.1,第8页

  1. 基于三阶多项式计算一个时间依赖的闭形式轨迹生成器
    • 您可以在 chp1_ex1_1.m 的第51行添加您的实现代码。需要手动创建一个在笛卡尔空间的轨迹,该轨迹从 initial_position 开始,到达 target_position,基于三阶多项式(参见图2)。

计算基于三阶多项式的闭式时变轨迹发生器

通过插值计算,每个时间点的位置信息会逐步从初始位置过渡到目标位置,以确保运动平稳。

原理和公式解释

在这个三阶多项式轨迹生成中,我们希望找到一个平滑的函数,使得机器人的位置从初始位置过渡到目标位置。三阶多项式的形式如下:

p ( t ) = a 0 + a 1 t + a 2 t 2 + a 3 t 3 p(t) = a_0 + a_1 t + a_2 t^2 + a_3 t^3 p(t)=a0+a1t+a2t2+a3t3
其中:

  • a 0 a_0 a0 a 1 a_1 a1 a 2 a_2 a2 a 3 a_3 a3是多项式的系数。
  • t t t是时间变量。

条件设置

使用满足初始和最终位置以及速度的边界条件。

  1. 初始位置条件:当 t = 0 t = 0 t=0时,位置为初始位置 p ( 0 ) = initialPosition p(0) = \text{initialPosition} p(0)=initialPosition
  2. 终点位置条件:当 t = T f t = T_f t=Tf时,位置为目标位置 p ( T f ) = targetPosition p(T_f) = \text{targetPosition} p(Tf)=targetPosition
  3. 初始速度为 0:当 t = 0 t = 0 t=0时,速度 p ′ ( 0 ) = 0 p'(0) = 0 p(0)=0
  4. 最终速度为 0:当 t = T f t = T_f t=Tf 时,速度 p ′ ( T f ) = 0 p'(T_f) = 0 p(Tf)=0

其中 T f T_f Tf是总时间长度。

利用条件求解系数

% 使用符号工具箱推导三阶多项式轨迹生成的公式
syms a0 a1 a2 a3 t T_f initialPosition targetPosition% 定义三阶多项式 p(t) = a0 + a1*t + a2*t^2 + a3*t^3
p = a0 + a1 * t + a2 * t^2 + a3 * t^3;% 计算速度 p'(t)
p_dot = diff(p, t);% 设定边界条件:
% 1. 初始位置条件:p(0) = initialPosition
eq1 = subs(p, t, 0) == initialPosition;% 2. 初始速度条件:p'(0) = 0
eq2 = subs(p_dot, t, 0) == 0;% 3. 终点位置条件:p(T_f) = targetPosition
eq3 = subs(p, t, T_f) == targetPosition;% 4. 最终速度条件:p'(T_f) = 0
eq4 = subs(p_dot, t, T_f) == 0;% 解方程组,求解 a0, a1, a2, a3
solutions = solve([eq1, eq2, eq3, eq4], [a0, a1, a2, a3]);% 展示结果
disp('a0 = '); disp(solutions.a0);
disp('a1 = '); disp(solutions.a1);
disp('a2 = '); disp(solutions.a2);
disp('a3 = '); disp(solutions.a3);% 为验证目的,可以将结果代入并观察
% 定义具体的初始位置、目标位置、总时间,并生成时间序列
initialPosition_val = 0;
targetPosition_val = 10;
T_f_val = 5;
time = linspace(0, T_f_val, 50);% 计算 a2 和 a3 的值
a0_val = subs(solutions.a0, [initialPosition, targetPosition, T_f], [initialPosition_val, targetPosition_val, T_f_val]);
a1_val = subs(solutions.a1, [initialPosition, targetPosition, T_f], [initialPosition_val, targetPosition_val, T_f_val]);
a2_val = subs(simplified_a2, [initialPosition, targetPosition, T_f], [initialPosition_val, targetPosition_val, T_f_val]);
a3_val = subs(simplified_a3, [initialPosition, targetPosition, T_f], [initialPosition_val, targetPosition_val, T_f_val]);% 计算轨迹
cartesianTrajectory = double(a0_val + a1_val * time + a2_val * time.^2 + a3_val * time.^3);% 绘制轨迹
figure;
plot(time, cartesianTrajectory);
xlabel('Time [s]');
ylabel('Position');
title('Smooth Trajectory from Initial to Target Position based on Third-Order Polynomial');
grid on;
第一步:初始位置条件

t = 0 t = 0 t=0时,轨迹位置为初始位置:
p ( 0 ) = a 0 = initialPosition p(0) = a_0 = \text{initialPosition} p(0)=a0=initialPosition
因此得到 a 0 = initialPosition a_0 = \text{initialPosition} a0=initialPosition

第二步:初始速度条件

速度函数是多项式对时间 t t t的一阶导数:
p ′ ( t ) = a 1 + 2 a 2 t + 3 a 3 t 2 p'(t) = a_1 + 2 a_2 t + 3 a_3 t^2 p(t)=a1+2a2t+3a3t2
t = 0 t = 0 t=0 时,初始速度为 0:
p ′ ( 0 ) = a 1 = 0 p'(0) = a_1 = 0 p(0)=a1=0
因此,得到 a 1 = 0 a_1 = 0 a1=0

到目前为止,我们有:
p ( t ) = a 0 + a 2 t 2 + a 3 t 3 p(t) = a_0 + a_2 t^2 + a_3 t^3 p(t)=a0+a2t2+a3t3
其中 a 0 = initialPosition a_0 = \text{initialPosition} a0=initialPosition a 1 = 0 a_1 = 0 a1=0

第三步:终点位置条件

t = T f t = T_f t=Tf时,轨迹位置为目标位置:
p ( T f ) = a 0 + a 2 T f 2 + a 3 T f 3 = targetPosition p(T_f) = a_0 + a_2 T_f^2 + a_3 T_f^3 = \text{targetPosition} p(Tf)=a0+a2Tf2+a3Tf3=targetPosition
代入 a 0 = initialPosition a_0 = \text{initialPosition} a0=initialPosition
initialPosition + a 2 T f 2 + a 3 T f 3 = targetPosition \text{initialPosition} + a_2 T_f^2 + a_3 T_f^3 = \text{targetPosition} initialPosition+a2Tf2+a3Tf3=targetPosition
移项得到:
a 2 T f 2 + a 3 T f 3 = targetPosition − initialPosition a_2 T_f^2 + a_3 T_f^3 = \text{targetPosition} - \text{initialPosition} a2Tf2+a3Tf3=targetPositioninitialPosition

第四步:最终速度条件

t = T f t = T_f t=Tf时,速度为 0:
p ′ ( T f ) = a 1 + 2 a 2 T f + 3 a 3 T f 2 = 0 p'(T_f) = a_1 + 2 a_2 T_f + 3 a_3 T_f^2 = 0 p(Tf)=a1+2a2Tf+3a3Tf2=0
代入 a 1 = 0 a_1 = 0 a1=0,简化为:
2 a 2 T f + 3 a 3 T f 2 = 0 2 a_2 T_f + 3 a_3 T_f^2 = 0 2a2Tf+3a3Tf2=0
解出 a 2 a_2 a2 a 3 a_3 a3 的关系:
a 2 = − 3 2 a 3 T f a_2 = -\frac{3}{2} a_3 T_f a2=23a3Tf

联立方程解 a 2 a_2 a2 a 3 a_3 a3

我们现在有两个方程:
a 2 T f 2 + a 3 T f 3 = targetPosition − initialPosition a_2 T_f^2 + a_3 T_f^3 = \text{targetPosition} - \text{initialPosition} a2Tf2+a3Tf3=targetPositioninitialPosition
a 2 = − 3 2 a 3 T f a_2 = -\frac{3}{2} a_3 T_f a2=23a3Tf

将第二个方程代入第一个方程:
( − 3 2 a 3 T f ) T f 2 + a 3 T f 3 = targetPosition − initialPosition \left(-\frac{3}{2} a_3 T_f\right) T_f^2 + a_3 T_f^3 = \text{targetPosition} - \text{initialPosition} (23a3Tf)Tf2+a3Tf3=targetPositioninitialPosition
− 3 2 a 3 T f 3 + a 3 T f 3 = targetPosition − initialPosition -\frac{3}{2} a_3 T_f^3 + a_3 T_f^3 = \text{targetPosition} - \text{initialPosition} 23a3Tf3+a3Tf3=targetPositioninitialPosition
− 3 + 2 2 a 3 T f 3 = targetPosition − initialPosition \frac{-3 + 2}{2} a_3 T_f^3 = \text{targetPosition} - \text{initialPosition} 23+2a3Tf3=targetPositioninitialPosition
− 1 2 a 3 T f 3 = targetPosition − initialPosition -\frac{1}{2} a_3 T_f^3 = \text{targetPosition} - \text{initialPosition} 21a3Tf3=targetPositioninitialPosition
a 3 = − 2 ( targetPosition − initialPosition ) T f 3 a_3 = -\frac{2 (\text{targetPosition} - \text{initialPosition})}{T_f^3} a3=Tf32(targetPositioninitialPosition)

a 3 a_3 a3的值代入 a 2 = − 3 2 a 3 T f a_2 = -\frac{3}{2} a_3 T_f a2=23a3Tf
a 2 = − 3 2 ( − 2 ( targetPosition − initialPosition ) T f 3 ) T f a_2 = -\frac{3}{2} \left(-\frac{2 (\text{targetPosition} - \text{initialPosition})}{T_f^3}\right) T_f a2=23(Tf32(targetPositioninitialPosition))Tf
a 2 = 3 ( targetPosition − initialPosition ) T f 2 a_2 = \frac{3 (\text{targetPosition} - \text{initialPosition})}{T_f^2} a2=Tf23(targetPositioninitialPosition)

最终结果

因此,我们得到:
a 0 = initialPosition a_0 = \text{initialPosition} a0=initialPosition
a 1 = 0 a_1 = 0 a1=0
a 2 = 3 ( targetPosition − initialPosition ) T f 2 a_2 = \frac{3 (\text{targetPosition} - \text{initialPosition})}{T_f^2} a2=Tf23(targetPositioninitialPosition)
a 3 = − 2 ( targetPosition − initialPosition ) T f 3 a_3 = -\frac{2 (\text{targetPosition} - \text{initialPosition})}{T_f^3} a3=Tf32(targetPositioninitialPosition)

chp1_ex1_1代码实现

在代码中,将三维空间中的每个轴( x x x, y y y, z z z)分别使用三阶多项式插值公式来计算:

for i = 1:3a0 = initialPosition(i);  % 初始位置a1 = 0;                   % 初始速度为0a2 = 3 * (targetPosition(i) - initialPosition(i)) / (5^2);  % 二次项系数a3 = -2 * (targetPosition(i) - initialPosition(i)) / (5^3); % 三次项系数cartesianTrajectory(i, :) = a0 + a1 * time + a2 * time.^2 + a3 * time.^3;
end

在这个循环中,代码针对 x x x y y y z z z 坐标分别计算各自的三阶多项式轨迹,最终生成平滑的轨迹数组 cartesianTrajectory。在此代码中 T f = 5 T_f=5 Tf=5
a0 是起始位置,a1 是初始速度为0,a2 和 a3 的系数用于保证在5秒内到达目标位置。

Press space to continue…
Warning: The provided robot configuration violates the predefined joint limits.
In robotics.manip.internal.warning (line 19)
In robotics.manip.internal/RigidBodyTree/validateConfigurationWithLimits (line 1705)
In inverseKinematics/solve (line 318)
In inverseKinematics/stepImpl (line 163)
In RobotisWrapper/computeInverseKinematics (line 95)
In chp1_ex1_1 (line 76)

该警告信息指出,在尝试计算逆运动学解(将笛卡尔坐标的轨迹转换为关节角度的轨迹)时,机器人当前的某些关节配置超出了其预定义的关节限制。

具体解释

  1. 逆运动学求解
    computeInverseKinematics 函数中,代码尝试通过逆运动学方法将笛卡尔空间的路径(cartesianTrajectory)转换为关节空间路径(即各关节角度的变化轨迹)。逆运动学求解通常涉及将给定的末端执行器位置和姿态转换为每个关节的角度。

  2. 关节限制
    多数机器人在设计时对关节的活动范围有一定的限制(例如旋转角度的上限和下限)。这些限制是为了保证机械结构的安全和控制的稳定性。超出关节限制可能会导致机械损坏或控制失误。

  3. 警告来源
    警告来自于 MATLAB 的 RigidBodyTree 类的 validateConfigurationWithLimits 方法,表明逆运动学求解过程中计算出的某些关节角度值超出了预设的关节活动范围。

解决方法

您可以尝试以下几种方法来解决此警告:

  1. 检查目标位置
    确保 targetPosition 是在机器人的工作空间内的合理位置。如果目标位置太远或不在机器人可达的范围内,逆运动学求解可能会遇到困难,从而导致关节角度超出限制。

  2. 调整初始和目标位置
    尝试将 initialPositiontargetPosition 设置在更靠近中心的位置,避免它们位于机器人关节限制的边界区域。

  3. 使用关节限制优化器
    如果您的机器人类提供了优化选项,可以设置逆运动学求解器考虑关节限制,从而自动避免生成超出关节限制的解。

  4. 调试代码
    如果有调试需求,可以在逆运动学求解过程中打印或记录关节角度,检查哪些关节角度超过了限制,从而可以进一步手动调整目标位置或轨迹。

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

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

相关文章

HTML飞舞的爱心

目录 系列文章 写在前面 完整代码 代码分析 写在后面 系列文章 序号目录1HTML满屏跳动的爱心(可写字)2HTML五彩缤纷的爱心3HTML满屏漂浮爱心4HTML情人节快乐5HTML蓝色爱心射线6HTML跳动的爱心(简易版)7HTML粒子爱心8HTML蓝色…

Excel把其中一张工作表导出成一个新的文件

excel导出一张工作表 一个Excel表里有多个工作表,怎么才能导出一个工作表,让其生成新的Excel文件呢? 第一步:首先打开Excel表格,然后选择要导出的工作表的名字,比如“Sheet1”,把鼠标放到“She…

Redis-09 SpringBoot集成Redis

Jedis 和 lettuce 基本已经过时 集成RedisTemplate 单机 1.建 Modul 2.改pom <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instanc…

git 命令之只提交文件的部分更改

git 命令之只提交文件的部分更改 有时&#xff0c;我们在一个文件中进行了多个更改&#xff0c;但只想提交其中的一部分更改。这时可以使用 使用 git add -p 命令 Git add -p命令允许我们选择并添加文件中的特定更改。它将会显示一个交互式界面&#xff0c;显示出文件中的每个更…

Node.js的http模块:创建HTTP服务器、客户端示例

新书速览|Vue.jsNode.js全栈开发实战-CSDN博客 《Vue.jsNode.js全栈开发实战&#xff08;第2版&#xff09;&#xff08;Web前端技术丛书&#xff09;》(王金柱)【摘要 书评 试读】- 京东图书 (jd.com) 要使用http模块&#xff0c;只需要在文件中通过require(http)引入即可。…

bridge-multicast-igmpsnooping

# 1.topo # 2.创建命名空间 ip netns add ns0 ip netns add ns1 ip netns add ns2 ip netns add ns3 # 3.创建veth设备 ip link add ns0-veth0 type veth peer name hn0-veth0 ip link add ns1-veth0 type veth peer name hn1-veth0 ip link add ns2-veth0 type veth pe…

麒麟部署一套NFS服务器,用于创建网络文件系统

一、服务端共享目录 在本例中,kyserver01(172.16.200.10)作为客户端,创建一个目录/testdir并挂载共享目录;kyserver02(172.16.200.11)作为服务端,创建一个共享目录/test,设置为读写权限,要求客户端使用root登录时映射为nobody用户、非root登录时保持不变。 服务端启…

《线性代数的本质》

之前收藏的一门课&#xff0c;刚好期末复习&#xff0c;顺便看一看哈哈 课程链接&#xff1a;【线性代数的本质】合集-转载于3Blue1Brown官方双语】 向量究竟是什么 线性代数中最基础、最根源的组成部分就是向量&#xff0c;需要先明白什么是向量 不同专业对向量的看法 物理专…

Scala—Collections集合概述

Scala Scala-集合概述 ScalaScala集合概述1 不可变集合&#xff08;Immutable Collections&#xff09;2 可变集合&#xff08;Mutable Collections&#xff09;3 Scala 集合类的层次结构 Scala集合概述 在 Scala 中&#xff0c;集合主要分为两大类&#xff1a;可变集合&#…

LLC与反激电路设计【学习笔记】

LLC电路&#xff1a; LLC电路是由2个电感和1个电容构成的谐振电路&#xff0c;故称之为LLC&#xff1a; LLC电路通过谐振能够实现MOS管的软开(soft switching)&#xff0c;减少开关损耗。另外MOS管的通态损耗也很低&#xff0c;换言之产生的焦耳热也少&#xff0c;这样就可以不…

java基础概念36:正则表达式1

一、正则表达式的作用 作用一&#xff1a;校验字符串是否满足规则&#xff1b;作用二&#xff1a;在一段文本中查找满足要求的内容。——爬虫 二、正则表达式 2-1、字符类 示例&#xff1a; public static void main(String[] args) {System.out.println("a".matc…

误删了照片,甚至对存储卡进行了格式化 都可以找到丢失的图片,并让您恢复它们 支持一键恢复或永久删除丢失的照片、视频、音乐、文档等-供大家学习研究参考

误删了照片&#xff0c;甚至对存储卡进行了格式化 都可以找到丢失的图片&#xff0c;并让您恢复它们 支持一键恢复或永久删除丢失的照片、视频、音乐、文档等。 建议及早恢复&#xff0c;覆盖就不能找回了~ 下载&#xff1a; https://download.csdn.net/download/weixin_43097…

candence: 常用的一些命令: Move / Mirror / Rotate / Spain / Fix / unFix / Flipdesign

常用的一些命令 一、 Move 移动 一个可移动一个&#xff0c;也可多个 移动器件 二、 Mirror 镜像 Mirror 就是top 和 bottom 层的器件进行相互转换 三、 Rotate 旋转 移动过程中旋转 四、旋转 Spain 不能在移动中旋转 可以一次旋转一个&#xff0c;也可多个 一次旋转…

(三)手势识别——动作识别应用【代码+数据集+python环境(免安装)+GUI系统】

&#xff08;三&#xff09;手势识别——动作识别应用【代码数据集python环境&#xff08;免安装&#xff09;GUI系统】 &#xff08;三&#xff09;手势识别——动作识别【代码数据集python环境GUI系统】 背景意义 随着互联网的普及和机器学习技术的进一步发展&#xff0c;手…

滑动窗口篇——如行云流水般的高效解法与智能之道(2)

前言&#xff1a; 上篇我们介绍了滑动窗口的含义并结合基础题型加以练习&#xff0c;本篇将以进阶难度的题目为索引&#xff0c;深化对于滑动窗口的运用与理解。 一. 将x减到0的最小操作数 题目链接&#xff1a;1658. 将 x 减到 0 的最小操作数 - 力扣&#xff08;LeetCode&am…

微信小程序加载商品首页数据时,页码没有更新,老是page=1。

微信小程序加载商品首页数据时&#xff0c;页码没有更新&#xff0c;老是page1。 源代码 const { baseUrl } require(../../config/config); const config require(../../config/config) import { calcViewHeight, iPhone } from ~/utils/device const { getToken } requi…

优化Docker镜像:提升部署效率与降低资源消耗

目录 1. 最小化镜像层 2. 使用轻量级基础镜像 3. 多阶段构建 4. 清理不必要的文件和依赖 5. 使用.dockerignore文件 6. 压缩和优化文件系统 7. 外部化配置和数据 8. 限制容器资源 9. 定期清理未使用的镜像和容器 结论 在云计算和微服务架构的浪潮中&#xff0c;Docke…

自研芯片逾十年,亚马逊云科技Graviton系列芯片全面成熟

在云厂商自研芯片的浪潮中&#xff0c;亚马逊云科技无疑是最早践行这一趋势的先驱。自其迈出自研芯片的第一步起&#xff0c;便如同一颗石子投入平静的湖面&#xff0c;激起了层层涟漪&#xff0c;引领着云服务和云上算力向着更高性能、更低成本的方向演进。 早在2012年&#x…

ApiChain 从迭代到项目 接口调试到文档生成单元测试一体化工具

项目地址&#xff1a;ApiChain 项目主页 ApiChain 简介 ApiChain 是一款类似 PostMan 的接口网络请求与文档生成软件&#xff0c;与 PostMan 不同的是&#xff0c;它基于 项目和迭代两个视角管理我们的接口文档&#xff0c;前端和测试更关注版本迭代中发生变更的接口编写代码…

游戏引擎学习第22天

移除 DllMain() 并成功重新编译 以下是对内容的详细复述与总结&#xff1a; 问题和解决方案&#xff1a; 在编译过程中遇到了一些问题&#xff0c;特别是如何告知编译器不要退出程序&#xff0c;而是继续处理。问题的根源在于编译过程中传递给链接器的参数设置不正确。原本尝试…