【Homework】【8】Learning resources for DQ Robotics in MATLAB

news2025/1/9 1:32:28

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

作业任务

创建一个名为“VS050RobotDH”的类,该类代表Denso VS050机器人,其DH参数如下表所示,并且完全由旋转关节组成。(请记住第6课的内容)

θ \theta θ d d d a a a α \alpha α
− π -\pi π0.3450 π 2 \frac{\pi}{2} 2π
π 2 \frac{\pi}{2} 2π00.250
− π 2 -\frac{\pi}{2} 2π00.01 − π 2 -\frac{\pi}{2} 2π
00.2550 π 2 \frac{\pi}{2} 2π
π \pi π00 π 2 \frac{\pi}{2} 2π
00.0700

末端执行器:在机器人上沿最后一个关节的 z z z轴附加一个20cm长的轴。

初始配置 q ( 0 ) = [ 0 π 3 π 3 0 π 3 0 ] T q(0) = \begin{bmatrix} 0 & \frac{\pi}{3} & \frac{\pi}{3} & 0 & \frac{\pi}{3} & 0 \end{bmatrix}^T q(0)=[03π3π03π0]T

classdef VS050RobotDH

    methods (Static)
        function ret = kinematics()
            %kinematics returns the kinematics of the Denso VS050 robot as DQ_SerialManipulatorDH
            DH_theta=  [-pi,pi/2,-pi/2,0,pi,0];
            DH_d =     [0.345,0,0,0.255,0,0.07];
            DH_a =     [0,0.25,0.01,0,0,0];
            DH_alpha = [pi/2,0,-pi/2,pi/2,pi/2,0];
            DH_type = repmat(DQ_SerialManipulatorDH.JOINT_ROTATIONAL,1,6);
            DH_matrix = [DH_theta;
                DH_d;
                DH_a;
                DH_alpha;
                DH_type];
            
            ret = DQ_SerialManipulatorDH(DH_matrix,'standard');
            ret.name = "Denso VS050 robot";
        end
    end
end

vs050_plane_constraints.m

  1. 创建一个平移控制器,其中 τ = 0.01 \tau = 0.01 τ=0.01。选择其他控制器参数,使得控制平滑(参见本课和之前的课程示例)。
  2. 创建6个平面,中心点为 p 1 = 0.45 i ^ + 0.08 k ^ p_1 = 0.45\hat{i} + 0.08\hat{k} p1=0.45i^+0.08k^,使得所有法线都指向内侧,形成一个5cm的立方体。(请记住第4课的内容)
  3. 在控制过程中,使用点到平面的虚拟力(VFIs)来保持工具尖端始终在立方体区域内。
  4. 依次将末端执行器移动到以下四个期望位置:
    t d = { 0.60 i ^ + 0.08 k ^ , 0.20 i ^ + 0.15 k ^ , 0.45 i ^ + 0.08 k ^ , 0.45 i ^ + 0.0 k ^ } t_d = \left\{0.60\hat{i} + 0.08\hat{k}, 0.20\hat{i} + 0.15\hat{k}, 0.45\hat{i} + 0.08\hat{k}, 0.45\hat{i} + 0.0\hat{k}\right\} td={0.60i^+0.08k^,0.20i^+0.15k^,0.45i^+0.08k^,0.45i^+0.0k^}
    每个位置持续4个仿真时间秒。
  5. 在一个图中绘制任务误差。
  6. 使用子图在另一个图中绘制末端执行器到所有六个平面的距离。
tic;  % 记录程序运行时间的起始点
clear;clc;  % 清除工作区和命令窗口
close all;  % 关闭所有图形窗口
include_namespace_dq;  % 包含DQ库的命名空间

% 初始化六个平面的中心点(相对于基坐标系的偏移)
p1_center = DQ([0.025, 0, 0] + [0.45,0,0.08]); % 平面1中心
p2_center = DQ([-0.025, 0, 0] + [0.45,0,0.08]); % 平面2中心
p3_center = DQ([0, 0.025, 0] + [0.45,0,0.08]); % 平面3中心
p4_center = DQ([0, -0.025, 0] + [0.45,0,0.08]); % 平面4中心
p5_center = DQ([0, 0, 0.025] + [0.45,0,0.08]); % 平面5中心
p6_center = DQ([0, 0, -0.025] + [0.45,0,0.08]); % 平面6中心

% 定义平面方程列表
plane_list = {
    -i_ + E_*dot(-i_, p1_center),  % 平面1
    i_ + E_*dot(i_, p2_center),    % 平面2
    -j_ + E_*dot(-j_, p3_center),  % 平面3
    j_ + E_*dot(j_, p4_center),    % 平面4
    -k_ + E_*dot(-k_, p5_center),  % 平面5
    k_ + E_*dot(k_, p6_center)     % 平面6
};

% 初始化机器人
VS050Robot = VS050RobotDH.kinematics();  % 创建VS050机器人运动学模型
VS050Robot.set_effector(1 + 0.5 * E_ * (0.2 * k_));  % 设置末端执行器(附加一段轴)
q = [0, pi/3, pi/3, 0, pi/3, 0]';  % 初始关节角度

% 初始化QP求解器和控制器
qp_solver = DQ_QuadprogSolver();  % 定义二次规划求解器
translation_controller = DQ_ClassicQPController(VS050Robot, qp_solver); % 创建经典QP控制器
translation_controller.set_control_objective(ControlObjective.Translation); % 设置控制目标为平移
translation_controller.set_gain(10);  % 设置增益
translation_controller.set_damping(1);  % 设置阻尼

% 定义虚拟力场增益和目标位置
eta_d = 1;  % 虚拟力场增益
td_list = { % 定义目标点列表
    0.60 * i_ + 0.08 * k_, 
    0.20 * i_ + 0.15 * k_, 
    0.45 * i_ + 0.08 * k_, 
    0.45 * i_ + 0.0 * k_
};

% 仿真参数
tau = 0.01;  % 采样时间
final_time = 4;  % 每个目标点的仿真时长

% 准备存储误差、时间和与平面距离的变量
total_steps = length(0:tau:final_time) * length(td_list); % 总的时间步长
stored_t_error = zeros(3, total_steps);  % 存储三维任务误差
stored_time = zeros(1, total_steps);    % 存储仿真时间
all_distances_to_planes = zeros(6, total_steps);  % 存储与六个平面的距离

step_counter = 1;% 初始化 step_counter

% 按目标点依次进行仿真
for td_counter = 1:4
    td = td_list{td_counter};  % 当前目标点
    
    % 针对当前目标点的控制循环
    for time = 0:tau:final_time
        [W, w, distances] = compute_inequalities(VS050Robot, q, plane_list, eta_d); % 计算不等式约束
        translation_controller.set_inequality_constraint(W, w); % 设置约束
        
        % 计算误差并存储
        t_error = vec3(translation(VS050Robot.fkm(q)) - td); % 计算任务误差
        stored_t_error(:, step_counter) = t_error; % 存储误差
        stored_time(step_counter) = time + (td_counter-1) * final_time; % 存储时间
        all_distances_to_planes(:, step_counter) = distances;  % 存储与平面的距离
        
        % 计算控制信号并更新关节角
        u = translation_controller.compute_setpoint_control_signal(q, vec4(td)); % 计算控制信号
        q = q + u * tau; % 更新关节状态

        % 增加 step_counter
        step_counter = step_counter + 1;
    end
end

% 绘制任务误差曲线
figure;
hold on;
plot(stored_time, stored_t_error(1,:), 'r', 'LineWidth', 1.5); % x轴误差(红色)
plot(stored_time, stored_t_error(2,:), 'g', 'LineWidth', 1.5); % y轴误差(绿色)
plot(stored_time, stored_t_error(3,:), 'b', 'LineWidth', 1.5); % z轴误差(蓝色)
hold off;
title('任务误差曲线');
xlabel('时间 [s]');
ylabel('任务误差 [m]');
legend({'x轴误差', 'y轴误差', 'z轴误差'});
grid on;
box off;

% 绘制与平面距离的子图
figure;
for i = 1:6
    subplot(2, 3, i);
    plot(stored_time, all_distances_to_planes(i, :), 'LineWidth', 1.5); % 绘制每个平面的距离
    title(['到平面 ' num2str(i) ' 的距离']);
    xlabel('时间 [s]');
    ylabel('距离 [m]');
    grid on;
end

toc; % 记录程序运行时间的结束点

% 定义计算不等式约束的函数
function [W, w, distances] = compute_inequalities(VS050Robot, q, plane_list, eta_d)
    W = []; % 初始化不等式约束矩阵W
    w = []; % 初始化不等式约束向量w
    distances = zeros(6, 1);  % 初始化到六个平面的距离数组
    
    Jx = VS050Robot.pose_jacobian(q); % 计算位姿雅可比矩阵
    x = VS050Robot.fkm(q); % 计算当前位姿
    Jt = DQ_Kinematics.translation_jacobian(Jx, x); % 提取平移部分的雅可比矩阵
    t = translation(x); % 提取当前位姿的平移部分
    
    % 针对每个平面计算约束和距离
    for plane_counter = 1:length(plane_list)
        workspace_plane = plane_list{plane_counter}; % 当前平面
        Jp_pi = DQ_Kinematics.point_to_plane_distance_jacobian(Jt, t, workspace_plane); % 计算点到平面的雅可比
        dp_pi = DQ_Geometry.point_to_plane_distance(t, workspace_plane); % 计算点到平面的距离
        W = [W; -Jp_pi]; % 更新约束矩阵
        w = [w; eta_d * dp_pi]; % 更新约束向量
        distances(plane_counter) = dp_pi; % 存储距离
    end
end

在这里插入图片描述
在这里插入图片描述

vs050_entry_sphere_constraint.m

  1. 创建一个平移控制器,其中 τ = 0.01 \tau = 0.01 τ=0.01。选择其他控制器参数,使得控制平滑(参见本课和之前的课程示例)。
  2. 考虑入口球体的中心位于 p 2 = 0.45 i ^ + 0.2 k ^ p_2 = 0.45\hat{i} + 0.2\hat{k} p2=0.45i^+0.2k^。考虑入口球体的半径为5 mm。
  3. 在控制过程中,使用线到点的虚拟力(VFIs)来保持轴始终在入口球体内。
  4. 依次将末端执行器移动到以下四个期望位置:
    t d = { 0.45 i ^ + 0.03 k ^ , 0.48 i ^ + 0.03 k ^ , 0.41 i ^ + 0.03 k ^ , 0.40 i ^ + 0.01 k ^ } t_d = \left\{0.45\hat{i} + 0.03\hat{k}, 0.48\hat{i} + 0.03\hat{k}, 0.41\hat{i} + 0.03\hat{k}, 0.40\hat{i} + 0.01\hat{k}\right\} td={0.45i^+0.03k^,0.48i^+0.03k^,0.41i^+0.03k^,0.40i^+0.01k^}
    每个位置持续4个仿真时间秒。
  5. 在一个图中绘制任务误差。
  6. 在另一个图中绘制轴到入口球体中心的距离。
tic; % 开始计时
clear; clc; close all; % 清理工作区,关闭所有图形窗口
include_namespace_dq; % 包含双四元数命名空间

% 初始化中心点位置
p = 0.45*i_ + 0.2*k_; % 中心点坐标
d_safe = 0.005; % 安全距离(单位:米)

% 机器人配置
VS050Robot = VS050RobotDH.kinematics(); % 初始化 VS050 机器人
VS050Robot.set_effector(1 + 0.5 * E_ * (0.2 * k_)); % 设置机器人末端执行器
q = [0, pi/3, pi/3, 0, pi/3, 0]'; % 初始关节角度(单位:弧度)

% 解算器和控制器配置
qp_solver = DQ_QuadprogSolver(); % 初始化二次规划解算器
translation_controller = DQ_ClassicQPController(VS050Robot, qp_solver); % 初始化经典二次规划控制器
translation_controller.set_control_objective(ControlObjective.Translation); % 设置为平移控制目标
translation_controller.set_gain(10); % 设置增益
translation_controller.set_damping(1); % 设置阻尼系数

% 虚拟力场增益和目标位置列表
eta_d = 1; % 虚拟力场增益
td_list = {0.45 * i_ + 0.03 * k_, 0.48 * i_ + 0.03 * k_, 0.41 * i_ + 0.03 * k_, 0.40 * i_ + 0.01 * k_}; % 目标点列表

% 仿真参数
tau = 0.01; % 采样时间(单位:秒)
final_time = 4; % 每个目标点的仿真时间(单位:秒)

% 预分配存储任务误差、时间和距离的数组
total_steps = length(0:tau:final_time) * length(td_list); % 总步数
stored_t_error = zeros(3, total_steps); % 存储任务误差(x、y、z 三维)
stored_time = zeros(1, total_steps); % 存储时间
all_distances = zeros(1, total_steps); % 存储距离
step_counter = 0; % 初始化步数计数器

for td_counter = 1:4 % 遍历目标点
    td = td_list{td_counter}; % 当前目标点
    
    % 对每个目标点执行平移控制
    for time = 0:tau:final_time
        step_counter = step_counter + 1; % 增加步数计数器
        
        % 计算姿态雅可比矩阵和姿态
        Jx = VS050Robot.pose_jacobian(q); % 获取雅可比矩阵
        x = VS050Robot.fkm(q); % 正向运动学计算当前位置
        
        % 计算 k 轴的直线雅可比矩阵
        Jl = DQ_Kinematics.line_jacobian(Jx, x, k_);
        
        % 计算相对于基坐标的直线
        t = translation(x); % 平移向量
        r = rotation(x); % 旋转矩阵
        l = Ad(r, k_); % 直线方向
        l_dq = l + E_ * cross(t, l); % 双四元数形式的直线
        
        % 计算点到直线的距离雅可比矩阵
        Jl_p = DQ_Kinematics.line_to_point_distance_jacobian(Jl, l_dq, p);
        
        % 计算点到直线的平方距离
        Dl_p = DQ_Geometry.point_to_line_squared_distance(p, l_dq);
        
        % 计算距离误差
        D_safe = d_safe^2; % 安全距离的平方
        D_tilde = D_safe - Dl_p; % 距离误差

        % 存储误差和距离
        t_error = vec3(translation(VS050Robot.fkm(q)) - td); % 计算任务误差
        stored_t_error(:, step_counter) = t_error; % 存储任务误差
        stored_time(step_counter) = time + (td_counter - 1) * final_time; % 存储时间
        all_distances(:, step_counter) = sqrt(Dl_p); % 存储实际距离
        
        % 设置不等式约束
        W = Jl_p; % 不等式约束矩阵
        w = eta_d * D_tilde; % 不等式约束向量
        translation_controller.set_inequality_constraint(W, w); % 更新控制器约束
        
        % 计算控制信号
        u = translation_controller.compute_setpoint_control_signal(q, vec4(td)); % 计算控制输入
        
        % 更新关节位置
        q = q + u * tau; % 按采样时间步进
    end
end

 % 绘制任务误差曲线
figure;
hold on;
plot(stored_time, stored_t_error(1,:), 'r', 'LineWidth', 1.5); % 绘制 x 轴误差
plot(stored_time, stored_t_error(2,:), 'g', 'LineWidth', 1.5); % 绘制 y 轴误差
plot(stored_time, stored_t_error(3,:), 'b', 'LineWidth', 1.5); % 绘制 z 轴误差
hold off;
title('任务误差曲线');
xlabel('时间 [秒]');
ylabel('误差 [米]');
legend({'x 轴误差', 'y 轴误差', 'z 轴误差'});
grid on;

% 绘制距离曲线
figure;
plot(stored_time, all_distances, 'LineWidth', 1.5); % 绘制距离
title('末端轴到入口球体中心的距离');
xlabel('时间 [秒]');
ylabel('距离 [米]');
grid on;

toc; % 结束计时

在这里插入图片描述
在这里插入图片描述

生成动画

平面距离约束,点到面距离约束

在这里插入图片描述

for td_counter = 1:4
    td = td_list{td_counter};
     
    % Translation controller loop for each target
    for time = 0:tau:final_time
        
        
        [W, w, distances] = compute_inequalities(VS050Robot, q, plane_list, eta_d);
        translation_controller.set_inequality_constraint(W, w);
        step_counter = step_counter +1;
        % 记录误差
        t_error = vec3(translation(VS050Robot.fkm(q)) - td);
        stored_t_error(:, step_counter) = t_error;
        stored_time(step_counter) = time + (td_counter-1) * final_time;
        all_distances_to_planes(:, step_counter) = distances;  % 存储距离
        
        % 计算控制信号并更新关节状态
        u = translation_controller.compute_setpoint_control_signal(q, vec4(td));
        q = q + u * tau;

        % Plot
        % Plot the robot
        plot(VS050Robot,q);
        title(['td' num2str(td_counter) '----Translation control' ' time = ' num2str(time) 's out of ' num2str(final_time) 's'])
        % Plot the desired pose
        hold on
        plot3(td.q(2),td.q(3),td.q(4), 'ko');
        % % Plot the shaft in blue
        t_1 = translation(VS050Robot.raw_fkm(q));
        t_2 = translation(VS050Robot.fkm(q));
        plot3([t_1.q(2) t_2.q(2)],[t_1.q(3) t_2.q(3)],[t_1.q(4) t_2.q(4)],'g','LineWidth',2)
        % Plot the walls
        plot(plane_list{1}, 'plane', 0.10, 'location', p1_center);  
        plot(plane_list{2}, 'plane', 0.10, 'location', p2_center); 
        plot(plane_list{3}, 'plane', 0.10, 'location', p3_center);  
        plot(plane_list{4}, 'plane', 0.10, 'location', p4_center); 
        plot(plane_list{5}, 'plane', 0.10, 'location', p5_center);  
        plot(plane_list{6}, 'plane', 0.10, 'location', p6_center); 
        % Define the 8 vertices of a cube with side length 5 (from -2.5 to 2.5)
        vertices = 0.01.*[
            -2.5, -2.5, -2.5;
            2.5, -2.5, -2.5;
            2.5, 2.5, -2.5;
            -2.5, 2.5, -2.5;
            -2.5, -2.5, 2.5;
            2.5, -2.5, 2.5;
            2.5, 2.5, 2.5;
            -2.5, 2.5, 2.5
        ]+repmat([0.45,0,0.08],8,1);
        % Define the edges connecting the vertices to form the cube's edges
        edges = [
            1, 2; 2, 3; 3, 4; 4, 1;   % Bottom square
            5, 6; 6, 7; 7, 8; 8, 5;   % Top square
            1, 5; 2, 6; 3, 7; 4, 8    % Vertical edges connecting top and bottom
        ];
        % Plot the edges
        for i = 1:size(edges, 1)
            plot3([vertices(edges(i, 1), 1), vertices(edges(i, 2), 1)], ...
                  [vertices(edges(i, 1), 2), vertices(edges(i, 2), 2)], ...
                  [vertices(edges(i, 1), 3), vertices(edges(i, 2), 3)], 'k-', 'LineWidth', 2);
        end
        % Add grid and labels
        grid on
        xlabel('X-axis');
        ylabel('Y-axis');
        zlabel('Z-axis');
        % Set the view to a 3D perspective
        view(3);

        hold off
        % [For animations only]
        drawnow limitrate % [For animations only] Ask MATLAB to draw the plot now
    end
end

入口球体,点到线距离约束

在这里插入图片描述

for td_counter = 1:4
    td = td_list{td_counter};
    
    % Translation controller loop for each target
    for time = 0:tau:final_time
        step_counter = step_counter + 1; % 记录当前步数
        
        % Get the pose Jacobian and the pose
        Jx = VS050Robot.pose_jacobian(q);
        x = VS050Robot.fkm(q);
        
        % Get the line Jacobian for the k-axis
        Jl = DQ_Kinematics.line_jacobian(Jx, x, k_);
        
        % Get the line with respect to the base
        t = translation(x);
        r = rotation(x);
        l = Ad(r, k_);
        l_dq = l + E_*cross(t, l);
        
        % Get the line-to-point distance Jacobian
        Jl_p = DQ_Kinematics.line_to_point_distance_jacobian(Jl, l_dq, p);
        
        % Get the line-to-point square distance
        Dl_p = DQ_Geometry.point_to_line_squared_distance(p, l_dq);
        
        % Get the distance error
        D_safe = d_safe^2;
        D_tilde = D_safe - Dl_p;

        % 记录误差
        t_error = vec3(translation(VS050Robot.fkm(q)) - td);
        stored_t_error(:, step_counter) = t_error;
        stored_time(step_counter) = time + (td_counter-1) * final_time;
        all_distances(:, step_counter) = sqrt(Dl_p);
        
        % The inequality matrix and vector
        W = Jl_p;
        w = eta_d*D_tilde;
        
        % Update the linear inequalities in the controller
        translation_controller.set_inequality_constraint(W, w);
        
        % Get the next control signal [rad/s]
        u = translation_controller.compute_setpoint_control_signal(q,vec4(td));
        
        % Move the robot
        q = q + u*tau;

        % Clear plot
        plot(VS050Robot, q)
        clf(f)
        % Plot the robot
        plot(VS050Robot, q)
        view(3)
        title(['target td' num2str(td_counter) '---Translation control' ' time = ' num2str(time) 's out of ' num2str(final_time) 's'])
        hold on
        % Plot the desired pose
        hold on
        plot3(td.q(2),td.q(3),td.q(4), 'ko');
        % Plot the shaft in blue
        t_1 = translation(VS050Robot.raw_fkm(q));
        t_2 = translation(VS050Robot.fkm(q));
        plot3([t_1.q(2) t_2.q(2)],[t_1.q(3) t_2.q(3)],[t_1.q(4) t_2.q(4)],'b','LineWidth',2)
        % Plot the entry sphere
        % 绘制一个半径为 5 mm 的球体
        [x, y, z] = sphere(50); % 生成球体数据,50 表示分辨率
        sphere_radius = d_safe; % 球体半径为 5 mm
        x = sphere_radius * x + p.q(2); % 球体中心偏移
        y = sphere_radius * y + p.q(3);
        z = sphere_radius * z + p.q(4);

        % 使用 surf 绘制球体
        surf(x, y, z, 'FaceAlpha', 0.3, 'EdgeColor', 'none', 'FaceColor', 'r'); % 半透明红色
        axis equal; % 固定坐标轴比例
        grid on; % 启用网格线方便观察


        % [For animations only]
        drawnow limitrate % [For animations only] Ask MATLAB to draw the plot now
    end
end

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

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

相关文章

如何防御ARP欺骗 保护IP安全

在数字化浪潮席卷全球的今天,网络安全威胁如同暗流涌动,时刻考验着我们的防范能力。其中,ARP欺骗攻击作为一种隐蔽性强、成本低廉且危害严重的网络攻击手段,成为众多网络安全事件中的一颗“毒瘤”。那么我们究竟是如何防御ARP欺骗…

低代码场景案例配置——复杂数据模型下表单与表格关联字段的保存

主子表的场景是每个业务系统都绕不过的功能点,低代码能不能在业务上用的起来,这个是必须过的门槛。那么什么主子表有哪些场景的应用,如何配置呢,接下来我们就举个例详细说明 订单管理系统,场景描述: 在电…

方案拆解 | 打击矩阵新规频出!2025矩阵营销该怎么玩?

社媒平台的矩阵营销又要“变天”了?! 11月18日,小红书官方发表了被安全薯 称为“小红书史上最严打击黑灰产专项”新规,其中就包括黑灰产矩阵号的公告。 ▲ 图源:小红书 实际上,不包括这次,今年…

C51小车项目-笔记11-SU-03T语音控制模块

一、网页配置 网站:智能公元/AI产品零代码平台 配置步骤: 发布版本,输入版本名字 等待SDK生成成功 成功之后下载SDK,完成之后将压缩包放到一个没有中文的文件目录中解压 二、接线 三、操作步骤 解压,以管理员身份打…

Springboot3介绍

一、Springboot3简介: https://docs.spring.io/spring-boot/docs/current/reference/html/getting-started.html?spmwolai.workspace.0.0.68b62306Q6jtTw#getting-started.introducing-spring-boot 无论使用XML、注解、Java配置类还是他们的混合用法,配置文件过于…

Mac上基于pyenv管理Python多版本的最佳实践

首先声明,你可以选择使用 Homebrew 来安装pyenv。我这里主要是想和我 Linux 设备上一致,所以选择使用脚本来安装pyenv。 准备安装脚本 这个安装的脚本来源于官方的的github仓库。 关于安装脚本的解读请看《pyenv 安装脚本解读》。 pyenv-installer.sh …

生成:安卓证书uniapp

地址: https://ask.dcloud.net.cn/article/35777 // 使用keytool -genkey命令生成证书: 官网: keytool -genkey -alias testalias -keyalg RSA -keysize 2048 -validity 36500 -keystore test.keystore ----------------------------------…

SpringBoot基于Redis+WebSocket 实现账号单设备登录.

引言 在现代应用中,一个账号在多个设备上的同时登录可能带来安全隐患。为了解决这个问题,许多应用实现了单设备登录,确保同一个用户只能在一个设备上登录。当用户在新的设备上登录时,旧设备会被强制下线。 本文将介绍如何使用 Spr…

【MySQL 进阶之路】事务并发情况分析

MySQL事务并发控制分析笔记 在数据库系统中,事务并发控制至关重要,能够确保多个事务并发执行时的数据一致性、隔离性和正确性。MySQL通过不同的锁机制控制并发操作,以确保事务的隔离性。以下是对事务A和事务B并发行为的详细分析,…

如何在小米平板5上运行 deepin 23 ?

deepin 23 加入了 ARM64 支持,这里尝试将 deepin 系统刷入平板中,平常使用中,带个笔记本电脑有时候也会嫌比较麻烦,把 Linux 系统刷入平板中既满足了使用需要,又满足了轻便的需求。为什么不使用 Termux ?虽…

华为HarmonyOS 快速构建各种文本识别应用 -- 通用文字识别

适用场景 通用文字识别,是通过拍照、扫描等光学输入方式,将各种票据、卡证、表格、报刊、书籍等印刷品文字转化为图像信息,再利用文字识别技术将图像信息转化为计算机等设备可以使用的字符信息的技术。 可以对文档翻拍、街景翻拍等图片进行…

【系统架构核心服务设计】使用 Redis ZSET 实现排行榜服务

目录 一、排行榜的应用场景 二、排行榜技术的特点 三、使用Redis ZSET实现排行榜 3.1 引入依赖 3.2 配置Redis连接 3.3 创建实体类(可选) 3.4 编写 Redis 操作服务层 3.5 编写控制器层 3.6 测试 3.6.1 测试 addMovieScore 接口 3.6.2 测试 g…

【Docker】如何在Docker中配置防火墙规则?

Docker本身并不直接管理防火墙规则;它依赖于主机系统的防火墙设置。不过,Docker在启动容器时会自动配置一些iptables规则来管理容器网络流量。如果你需要更细粒度地控制进出容器的流量,你需要在主机系统上配置防火墙规则。以下是如何在Linux主…

java+ssm+mysql美妆论坛

项目介绍: 使用javassmmysql开发的美妆论坛,系统包含超级管理员,系统管理员、用户角色,功能如下: 用户:主要是前台功能使用,包括注册、登录;查看论坛板块和板块下帖子;…

【MFC】vs2019中使用sqlite3完成学生管理系统

目录 效果图list Contral 控件的简单使用使用sqlite3 效果图 使用sqlite3完成简单的数据库操作。 list Contral 控件的简单使用 本章只介绍基本应用 添加表头:语法: int InsertColumn(int nCol, LPCTSTR lpszColumnHeading, int nFormat LVCFMT_LEFT…

Java设计模式 —— 【创建型模式】建造者模式详解

文章目录 一、建造者模式二、案例实现三、优缺点四、模式拓展五、对比1、工厂方法模式VS建造者模式2、抽象工厂模式VS建造者模式 一、建造者模式 建造者模式(Builder Pattern) 又叫生成器模式,是一种对象构建模式。它可以将复杂对象的建造过…

单链表(C语言版本)

前提 不探讨头结点空链表可以插入和查找,不可删除一般不选择phead移动,定义一个新结点把phead赋给他,移动新结点即可单链表不适合在前面和后面插入或删除,适合在后面插入删除 头插 void SLPushFront(SLTNode** pphead, SLTDataTy…

VMware虚拟机搭建和镜像配置

VMware虚拟机搭建和镜像配置 下载安装VMware 开始下载 更改安装路径,需要一个大空间的盘 更改后下一步 下一步后,选择不主动升级更新 一直下一步 直到安装完毕 输入许可密钥,我下载的版本是12,输入完成点击输入&#xff…

使用PPT科研绘图导出PDF边缘留白问题解决方案

使用PPT画图导出PDF格式后,边缘有空白,插入latex不美观,解决方案为自定义PPT幻灯片母版大小,如题步骤为: 1、查看已制作好的图片的大小,即长度和宽度 2、选择自定义幻灯片大小 3、自定义幻灯片大小为第1…

在Ubuntu上使用docker compose安装N卡GPU的Ollama服务

在现代计算环境中,利用 GPU 进行计算加速变得越来越重要。下面将讲解如何在Ubuntu上使用docker compose安装N卡GPU的Ollama服务。 1、安装 NVIDIA 容器工具 首先,需要确保你的系统已经安装了 NVIDIA 容器工具 nvidia-container-toolkit。这是让 Docker 容器访问 GPU 的关键…