MATLAB编写的机械臂控制仿真程序,它主要实现了对一个二连杆机械臂的运动控制仿真,比较了PID控制和非线性模型预测控制两种方法在机械臂轨迹跟踪任务中的性能
clc; clear; close all;%% 机械臂参数
l1 = 0.5; l2 = 0.4; Ts = 0.02; sim_time = 60; t = 0:Ts:sim_time;%% 物理参数
m1 = 1.0; m2 = 0.8; g = 9.81;%% 直线轨迹参数
start_point = [0.3; 0.1]; end_point = [0.7; 0.3];
progress = t/sim_time;
xd = start_point(1) + (end_point(1) - start_point(1)) * progress;
yd = start_point(2) + (end_point(2) - start_point(2)) * progress;%% 逆运动学计算
qd = zeros(2, length(t));
for k = 1:length(t)x = xd(k); y = yd(k);r = sqrt(x^2 + y^2);D = (r^2 - l1^2 - l2^2)/(2*l1*l2);if abs(D) > 1warning('步%d: 不可达位置,r=%.3f', k, r);qd(:,k) = qd(:,max(1,k-1));continue;endq2 = acos(D);q1 = atan2(y, x) - atan2(l2*sin(q2), l1 + l2*cos(q2));qd(:,k) = wrapToPi([q1; q2]);
end%% PID参数
Kp = [150; 150]; Ki = [20; 20]; Kd = [25; 25]; tau_max = [30; 30];%% PID控制
q_pid = qd(:,1); dq_pid = zeros(2, length(t));
e_int = zeros(2,1); tau_pid = zeros(2, length(t));
for i = 1:length(t)-1e = qd(:,i) - q_pid(:,i);e_int = e_int + e*Ts;if i > 1prev_error = qd(:,i-1) - q_pid(:,i-1);e_deriv = (e - prev_error)/Ts;elsee_deriv = [0; 0];endtau = Kp.*e + Ki.*e_int + Kd.*e_deriv;tau_pid(:,i) = min(max(tau, -tau_max), tau_max);[M, C, G] = dynamics_model(q_pid(:,i), dq_pid(:,i), m1, m2, l1, l2, g);ddq = M \ (tau_pid(:,i) - C*dq_pid(:,i) - G);dq_pid(:,i+1) = dq_pid(:,i) + ddq*Ts;q_pid(:,i+1) = q_pid(:,i) + dq_pid(:,i+1)*Ts;q2_min = 0.2; q2_max = pi - 0.2;if q_pid(2,i+1) < q2_minq_pid(2,i+1) = q2_min; dq_pid(2,i+1) = 0;elseif q_pid(2,i+1) > q2_maxq_pid(2,i+1) = q2_max; dq_pid(2,i+1) = 0;endq_pid(:,i+1) = wrapToPi(q_pid(:,i+1));
end%% 非线性MPC控制
nlobj = nlmpc(4, 2, 2);
nlobj.Ts = Ts;
nlobj.PredictionHorizon = 10;
nlobj.ControlHorizon = 3;nlobj.Model.StateFcn = @(x, u) stateFcn(x, u, m1, m2, l1, l2, g);
nlobj.Model.OutputFcn = @(x, u) x(1:2);% 权重和约束(优化能耗)
nlobj.Weights.OutputVariables = [500 500];
nlobj.Weights.ManipulatedVariables = [2 2];
nlobj.Weights.ManipulatedVariablesRate = [0.5 0.5];
nlobj.MV(1).Min = -30; nlobj.MV(1).Max = 30;
nlobj.MV(2).Min = -30; nlobj.MV(2).Max = 30;% 初始化状态
q_mpc = qd(:,1); dq_mpc = zeros(2, length(t));
tau_mpc = zeros(2, length(t));
x_mpc = [q_mpc; zeros(2,1)];
u_mpc = [0; 0];% MPC主循环
tic;
for i = 1:length(t)-1ref = zeros(nlobj.PredictionHorizon, 2);for k = 1:nlobj.PredictionHorizonfuture_idx = min(i + k - 1, length(t));ref(k, :) = qd(:, future_idx)';end[tau_mpc(:,i), ~] = nlmpcmove(nlobj, x_mpc, u_mpc, ref);u_mpc = tau_mpc(:,i);[M, C, G] = dynamics_model(q_mpc(:,i), dq_mpc(:,i), m1, m2, l1, l2, g);if any(isnan(M(:))) || any(isinf(M(:))) || det(M) < 1e-6ddq = zeros(2,1);elseddq = M \ (tau_mpc(:,i) - C*dq_mpc(:,i) - G);enddq_mpc(:,i+1) = dq_mpc(:,i) + ddq*Ts;q_mpc(:,i+1) = q_mpc(:,i) + dq_mpc(:,i+1)*Ts;if any(~isfinite(q_mpc(:,i+1))) || any(~isfinite(dq_mpc(:,i+1)))q_mpc(:,i+1) = q_mpc(:,i);dq_mpc(:,i+1) = dq_mpc(:,i);endq2_min = 0.2; q2_max = pi - 0.2;if q_mpc(2,i+1) < q2_minq_mpc(2,i+1) = q2_min; dq_mpc(2,i+1) = 0;elseif q_mpc(2,i+1) > q2_maxq_mpc(2,i+1) = q2_max; dq_mpc(2,i+1) = 0;endq_mpc(:,i+1) = wrapToPi(q_mpc(:,i+1));x_mpc = [q_mpc(:,i+1); dq_mpc(:,i+1)];
end
mpc_time = toc;
fprintf('MPC运行时间: %.2f 秒\n', mpc_time);%% 性能指标计算
error_pid = sqrt(sum((qd - q_pid).^2, 1));
error_mpc = sqrt(sum((qd - q_mpc).^2, 1));
mean_error_pid = mean(error_pid);
mean_error_mpc = mean(error_mpc);
error_improvement = (mean_error_pid - mean_error_mpc) / mean_error_pid * 100;threshold = 0.05;
settling_time_pid = find(error_pid < threshold, 1) * Ts;
if isempty(settling_time_pid), settling_time_pid = sim_time; end
settling_time_mpc = find(error_mpc < threshold, 1) * Ts;
if isempty(settling_time_mpc), settling_time_mpc = sim_time; end
speed_improvement = (settling_time_pid - settling_time_mpc) / settling_time_pid * 100;energy_pid = sum(sum(tau_pid.^2)) * Ts;
energy_mpc = sum(sum(tau_mpc.^2)) * Ts;
energy_reduction = (energy_pid - energy_mpc) / energy_pid * 100;fprintf('平均跟踪误差:PID = %.4f rad, MPC = %.4f rad, 提升 %.2f%%\n', ...mean_error_pid, mean_error_mpc, error_improvement);
fprintf('响应时间:PID = %.2f s, MPC = %.2f s, 提升 %.2f%%\n', ...settling_time_pid, settling_time_mpc, speed_improvement);
fprintf('能耗:PID = %.2f J, MPC = %.2f J, 降低 %.2f%%\n', ...energy_pid, energy_mpc, energy_reduction);%% 原有可视化(角度和轨迹)
figure('Name','PID vs MPC控制结果');
subplot(3,1,1);
plot(t, qd(1,:), 'k--', t, q_pid(1,:), 'b', t, q_mpc(1,:), 'r');
title('关节1角度跟踪'); legend('期望', 'PID', 'MPC');
xlabel('时间 (s)'); ylabel('角度 (rad)');subplot(3,1,2);
plot(t, qd(2,:), 'k--', t, q_pid(2,:), 'b', t, q_mpc(2,:), 'r');
title('关节2角度跟踪'); legend('期望', 'PID', 'MPC');
xlabel('时间 (s)'); ylabel('角度 (rad)');x_act_pid = l1*cos(q_pid(1,:)) + l2*cos(q_pid(1,:)+q_pid(2,:));
y_act_pid = l1*sin(q_pid(1,:)) + l2*sin(q_pid(1,:)+q_pid(2,:));
x_act_mpc = l1*cos(q_mpc(1,:)) + l2*cos(q_mpc(1,:)+q_mpc(2,:));
y_act_mpc = l1*sin(q_mpc(1,:)) + l2*sin(q_mpc(1,:)+q_mpc(2,:));subplot(3,1,3);
plot(xd, yd, 'k--', x_act_pid, y_act_pid, 'b', x_act_mpc, y_act_mpc, 'r');
axis equal; title('末端轨迹跟踪'); legend('期望', 'PID', 'MPC');
xlabel('X位置 (m)'); ylabel('Y位置 (m)');%% 添加机械臂运动动画
figure('Name', '机械臂运动动画');
set(gcf, 'Position', [100, 100, 800, 400]);% 计算关节位置
x1_pid = l1 * cos(q_pid(1,:));
y1_pid = l1 * sin(q_pid(1,:));
x2_pid = x1_pid + l2 * cos(q_pid(1,:) + q_pid(2,:));
y2_pid = y1_pid + l2 * sin(q_pid(1,:) + q_pid(2,:));x1_mpc = l1 * cos(q_mpc(1,:));
y1_mpc = l1 * sin(q_mpc(1,:));
x2_mpc = x1_mpc + l2 * cos(q_mpc(1,:) + q_mpc(2,:));
y2_mpc = y1_mpc + l2 * sin(q_mpc(1,:) + q_mpc(2,:));% 动画循环
for i = 1:10:length(t) % 每10步绘制一次,加速动画clf; % 清除当前图形% PID控制的机械臂(蓝色)subplot(1,2,1);plot([0, x1_pid(i)], [0, y1_pid(i)], 'b-', 'LineWidth', 2); hold on;plot([x1_pid(i), x2_pid(i)], [y1_pid(i), y2_pid(i)], 'b-', 'LineWidth', 2);plot(xd, yd, 'k--', 'LineWidth', 1); % 期望轨迹plot(x2_pid(i), y2_pid(i), 'bo', 'MarkerSize', 5); % 末端点axis equal; axis([-1 1 -1 1]);title('PID控制机械臂运动');xlabel('X位置 (m)'); ylabel('Y位置 (m)');grid on; hold off;% MPC控制的机械臂(红色)subplot(1,2,2);plot([0, x1_mpc(i)], [0, y1_mpc(i)], 'r-', 'LineWidth', 2); hold on;plot([x1_mpc(i), x2_mpc(i)], [y1_mpc(i), y2_mpc(i)], 'r-', 'LineWidth', 2);plot(xd, yd, 'k--', 'LineWidth', 1); % 期望轨迹plot(x2_mpc(i), y2_mpc(i), 'ro', 'MarkerSize', 5); % 末端点axis equal; axis([-1 1 -1 1]);title('MPC控制机械臂运动');xlabel('X位置 (m)'); ylabel('Y位置 (m)');grid on; hold off;drawnow; % 刷新图形pause(0.01); % 控制动画速度
end%% 动力学模型
function [M, C, G] = dynamics_model(q, dq, m1, m2, l1, l2, g)M = [(m1 + m2)*l1^2 + m2*l2^2 + 2*m2*l1*l2*cos(q(2)), m2*l2^2 + m2*l1*l2*cos(q(2)); ...m2*l2^2 + m2*l1*l2*cos(q(2)), m2*l2^2];C = [-m2*l1*l2*sin(q(2))*dq(2), -m2*l1*l2*sin(q(2))*(dq(1) + dq(2)); ...m2*l1*l2*sin(q(2))*dq(1), 0];G = [(m1 + m2)*g*l1*cos(q(1)) + m2*g*l2*cos(q(1)+q(2)); m2*g*l2*cos(q(1)+q(2))];
end%% 状态函数
function dx = stateFcn(x, u, m1, m2, l1, l2, g)q = x(1:2); dq = x(3:4);[M, C, G] = dynamics_model(q, dq, m1, m2, l1, l2, g);ddq = M \ (u - C*dq - G);dx = [dq; ddq];
end%% 角度标准化
function angles = wrapToPi(angles)angles = mod(angles + pi, 2*pi) - pi;
end
上面的代码是一个用MATLAB编写的机械臂控制仿真程序,它主要实现了对一个二连杆机械臂的运动控制仿真,比较了PID控制和非线性模型预测控制(Nonlinear Model Predictive Control, NMPC)两种方法在机械臂轨迹跟踪任务中的性能。以下是对代码各部分功能的详细解释:
1. 初始化与参数设置
clc; clear; close all;%% 机械臂参数
l1 = 0.5; l2 = 0.4; Ts = 0.02; sim_time = 60; t = 0:Ts:sim_time;%% 物理参数
m1 = 1.0; m2 = 0.8; g = 9.81;
这部分代码进行了初始化操作,清除命令窗口、工作区变量并关闭所有图形窗口。同时设置了机械臂的连杆长度、采样时间、仿真时间等参数,以及机械臂连杆的质量和重力加速度。
2. 直线轨迹规划
%% 直线轨迹参数
start_point = [0.3; 0.1]; end_point = [0.7; 0.3];
progress = t/sim_time;
xd = start_point(1) + (end_point(1) - start_point(1)) * progress;
yd = start_point(2) + (end_point(2) - start_point(2)) * progress;
此部分代码规划了机械臂末端执行器的直线运动轨迹,根据起始点和终点的坐标,结合仿真时间计算出每个时刻的期望位置。
3. 逆运动学计算
%% 逆运动学计算
qd = zeros(2, length(t));
for k = 1:length(t)x = xd(k); y = yd(k);r = sqrt(x^2 + y^2);D = (r^2 - l1^2 - l2^2)/(2*l1*l2);if abs(D) > 1warning('步%d: 不可达位置,r=%.3f', k, r);qd(:,k) = qd(:,max(1,k-1));continue;endq2 = acos(D);q1 = atan2(y, x) - atan2(l2*sin(q2), l1 + l2*cos(q2));qd(:,k) = wrapToPi([q1; q2]);
end
通过逆运动学计算,将末端执行器的期望位置转换为机械臂各关节的期望角度。如果计算过程中出现不可达位置,会发出警告并使用上一时刻的关节角度。
4. PID控制
%% PID参数
Kp = [150; 150]; Ki = [20; 20]; Kd = [25; 25]; tau_max = [30; 30];%% PID控制
q_pid = qd(:,1); dq_pid = zeros(2, length(t));
e_int = zeros(2,1); tau_pid = zeros(2, length(t));
for i = 1:length(t)-1e = qd(:,i) - q_pid(:,i);e_int = e_int + e*Ts;if i > 1prev_error = qd(:,i-1) - q_pid(:,i-1);e_deriv = (e - prev_error)/Ts;elsee_deriv = [0; 0];endtau = Kp.*e + Ki.*e_int + Kd.*e_deriv;tau_pid(:,i) = min(max(tau, -tau_max), tau_max);[M, C, G] = dynamics_model(q_pid(:,i), dq_pid(:,i), m1, m2, l1, l2, g);ddq = M \ (tau_pid(:,i) - C*dq_pid(:,i) - G);dq_pid(:,i+1) = dq_pid(:,i) + ddq*Ts;q_pid(:,i+1) = q_pid(:,i) + dq_pid(:,i+1)*Ts;q2_min = 0.2; q2_max = pi - 0.2;if q_pid(2,i+1) < q2_minq_pid(2,i+1) = q2_min; dq_pid(2,i+1) = 0;elseif q_pid(2,i+1) > q2_maxq_pid(2,i+1) = q2_max; dq_pid(2,i+1) = 0;endq_pid(:,i+1) = wrapToPi(q_pid(:,i+1));
end
这部分代码实现了PID控制器,根据关节角度的误差计算控制力矩,并通过机械臂的动力学模型更新关节角度和角速度。同时对关节角度进行了限制,避免超出合理范围。
5. 非线性MPC控制
%% 非线性MPC控制
nlobj = nlmpc(4, 2, 2);
nlobj.Ts = Ts;
nlobj.PredictionHorizon = 10;
nlobj.ControlHorizon = 3;nlobj.Model.StateFcn = @(x, u) stateFcn(x, u, m1, m2, l1, l2, g);
nlobj.Model.OutputFcn = @(x, u) x(1:2);% 权重和约束(优化能耗)
nlobj.Weights.OutputVariables = [500 500];
nlobj.Weights.ManipulatedVariables = [2 2];
nlobj.Weights.ManipulatedVariablesRate = [0.5 0.5];
nlobj.MV(1).Min = -30; nlobj.MV(1).Max = 30;
nlobj.MV(2).Min = -30; nlobj.MV(2).Max = 30;% 初始化状态
q_mpc = qd(:,1); dq_mpc = zeros(2, length(t));
tau_mpc = zeros(2, length(t));
x_mpc = [q_mpc; zeros(2,1)];
u_mpc = [0; 0];% MPC主循环
tic;
for i = 1:length(t)-1ref = zeros(nlobj.PredictionHorizon, 2);for k = 1:nlobj.PredictionHorizonfuture_idx = min(i + k - 1, length(t));ref(k, :) = qd(:, future_idx)';end[tau_mpc(:,i), ~] = nlmpcmove(nlobj, x_mpc, u_mpc, ref);u_mpc = tau_mpc(:,i);[M, C, G] = dynamics_model(q_mpc(:,i), dq_mpc(:,i), m1, m2, l1, l2, g);if any(isnan(M(:))) || any(isinf(M(:))) || det(M) < 1e-6ddq = zeros(2,1);elseddq = M \ (tau_mpc(:,i) - C*dq_mpc(:,i) - G);enddq_mpc(:,i+1) = dq_mpc(:,i) + ddq*Ts;q_mpc(:,i+1) = q_mpc(:,i) + dq_mpc(:,i+1)*Ts;if any(~isfinite(q_mpc(:,i+1))) || any(~isfinite(dq_mpc(:,i+1)))q_mpc(:,i+1) = q_mpc(:,i);dq_mpc(:,i+1) = dq_mpc(:,i);endq2_min = 0.2; q2_max = pi - 0.2;if q_mpc(2,i+1) < q2_minq_mpc(2,i+1) = q2_min; dq_mpc(2,i+1) = 0;elseif q_mpc(2,i+1) > q2_maxq_mpc(2,i+1) = q2_max; dq_mpc(2,i+1) = 0;endq_mpc(:,i+1) = wrapToPi(q_mpc(:,i+1));x_mpc = [q_mpc(:,i+1); dq_mpc(:,i+1)];
end
mpc_time = toc;
fprintf('MPC运行时间: %.2f 秒\n', mpc_time);
此部分代码实现了非线性模型预测控制(NMPC),通过预测未来一段时间内的系统状态,优化控制输入以最小化目标函数。同时记录了MPC控制器的运行时间。
6. 性能指标计算
%% 性能指标计算
error_pid = sqrt(sum((qd - q_pid).^2, 1));
error_mpc = sqrt(sum((qd - q_mpc).^2, 1));
mean_error_pid = mean(error_pid);
mean_error_mpc = mean(error_mpc);
error_improvement = (mean_error_pid - mean_error_mpc) / mean_error_pid * 100;threshold = 0.05;
settling_time_pid = find(error_pid < threshold, 1) * Ts;
if isempty(settling_time_pid), settling_time_pid = sim_time; end
settling_time_mpc = find(error_mpc < threshold, 1) * Ts;
if isempty(settling_time_mpc), settling_time_mpc = sim_time; end
speed_improvement = (settling_time_pid - settling_time_mpc) / settling_time_pid * 100;energy_pid = sum(sum(tau_pid.^2)) * Ts;
energy_mpc = sum(sum(tau_mpc.^2)) * Ts;
energy_reduction = (energy_pid - energy_mpc) / energy_pid * 100;fprintf('平均跟踪误差:PID = %.4f rad, MPC = %.4f rad, 提升 %.2f%%\n', ...mean_error_pid, mean_error_mpc, error_improvement);
fprintf('响应时间:PID = %.2f s, MPC = %.2f s, 提升 %.2f%%\n', ...settling_time_pid, settling_time_mpc, speed_improvement);
fprintf('能耗:PID = %.2f J, MPC = %.2f J, 降低 %.2f%%\n', ...energy_pid, energy_mpc, energy_reduction);
计算了PID控制和NMPC控制的平均跟踪误差、响应时间和能耗,并比较了两种控制方法的性能提升。
7. 可视化
%% 原有可视化(角度和轨迹)
figure('Name','PID vs MPC控制结果');
subplot(3,1,1);
plot(t, qd(1,:), 'k--', t, q_pid(1,:), 'b', t, q_mpc(1,:), 'r');
title('关节1角度跟踪'); legend('期望', 'PID', 'MPC');
xlabel('时间 (s)'); ylabel('角度 (rad)');subplot(3,1,2);
plot(t, qd(2,:), 'k--', t, q_pid(2,:), 'b', t, q_mpc(2,:), 'r');
title('关节2角度跟踪'); legend('期望', 'PID', 'MPC');
xlabel('时间 (s)'); ylabel('角度 (rad)');x_act_pid = l1*cos(q_pid(1,:)) + l2*cos(q_pid(1,:)+q_pid(2,:));
y_act_pid = l1*sin(q_pid(1,:)) + l2*sin(q_pid(1,:)+q_pid(2,:));
x_act_mpc = l1*cos(q_mpc(1,:)) + l2*cos(q_mpc(1,:)+q_mpc(2,:));
y_act_mpc = l1*sin(q_mpc(1,:)) + l2*sin(q_mpc(1,:)+q_mpc(2,:));subplot(3,1,3);
plot(xd, yd, 'k--', x_act_pid, y_act_pid, 'b', x_act_mpc, y_act_mpc, 'r');
axis equal; title('末端轨迹跟踪'); legend('期望', 'PID', 'MPC');
xlabel('X位置 (m)'); ylabel('Y位置 (m)');%% 添加机械臂运动动画
figure('Name', '机械臂运动动画');
set(gcf, 'Position', [100, 100, 800, 400]);% 计算关节位置
x1_pid = l1 * cos(q_pid(1,:));
y1_pid = l1 * sin(q_pid(1,:));
x2_pid = x1_pid + l2 * cos(q_pid(1,:) + q_pid(2,:));
y2_pid = y1_pid + l2 * sin(q_pid(1,:) + q_pid(2,:));x1_mpc = l1 * cos(q_mpc(1,:));
y1_mpc = l1 * sin(q_mpc(1,:));
x2_mpc = x1_mpc + l2 * cos(q_mpc(1,:) + q_mpc(2,:));
y2_mpc = y1_mpc + l2 * sin(q_mpc(1,:) + q_mpc(2,:));% 动画循环
for i = 1:10:length(t) % 每10步绘制一次,加速动画clf; % 清除当前图形% PID控制的机械臂(蓝色)subplot(1,2,1);plot([0, x1_pid(i)], [0, y1_pid(i)], 'b-', 'LineWidth', 2); hold on;plot([x1_pid(i), x2_pid(i)], [y1_pid(i), y2_pid(i)], 'b-', 'LineWidth', 2);plot(xd, yd, 'k--', 'LineWidth', 1); % 期望轨迹plot(x2_pid(i), y2_pid(i), 'bo', 'MarkerSize', 5); % 末端点axis equal; axis([-1 1 -1 1]);title('PID控制机械臂运动');xlabel('X位置 (m)'); ylabel('Y位置 (m)');grid on; hold off;% MPC控制的机械臂(红色)subplot(1,2,2);plot([0, x1_mpc(i)], [0, y1_mpc(i)], 'r-', 'LineWidth', 2); hold on;plot([x1_mpc(i), x2_mpc(i)], [y1_mpc(i), y2_mpc(i)], 'r-', 'LineWidth', 2);plot(xd, yd, 'k--', 'LineWidth', 1); % 期望轨迹plot(x2_mpc(i), y2_mpc(i), 'ro', 'MarkerSize', 5); % 末端点axis equal; axis([-1 1 -1 1]);title('MPC控制机械臂运动');xlabel('X位置 (m)'); ylabel('Y位置 (m)');grid on; hold off;drawnow; % 刷新图形pause(0.01); % 控制动画速度
end
通过绘制图形和动画,直观地展示了两种控制方法下机械臂各关节角度的跟踪情况、末端执行器的轨迹跟踪情况以及机械臂的运动过程。
8. 辅助函数
%% 动力学模型
function [M, C, G] = dynamics_model(q, dq, m1, m2, l1, l2, g)M = [(m1 + m2)*l1^2 + m2*l2^2 + 2*m2*l1*l2*cos(q(2)), m2*l2^2 + m2*l1*l2*cos(q(2)); ...m2*l2^2 + m2*l1*l2*cos(q(2)), m2*l2^2];C = [-m2*l1*l2*sin(q(2))*dq(2), -m2*l1*l2*sin(q(2))*(dq(1) + dq(2)); ...m2*l1*l2*sin(q(2))*dq(1), 0];G = [(m1 + m2)*g*l1*cos(q(1)) + m2*g*l2*cos(q(1)+q(2)); m2*g*l2*cos(q(1)+q(2))];
end%% 状态函数
function dx = stateFcn(x, u, m1, m2, l1, l2, g)q = x(1:2); dq = x(3:4);[M, C, G] = dynamics_model(q, dq, m1, m2, l1, l2, g);ddq = M \ (u - C*dq - G);dx = [dq; ddq];
end%% 角度标准化
function angles = wrapToPi(angles)angles = mod(angles + pi, 2*pi) - pi;
end
定义了机械臂的动力学模型、状态函数和角度标准化函数,用于计算机械臂的动力学参数、更新系统状态和将角度限制在[-π, π]
范围内。
综上所述,这段代码通过仿真比较了PID控制和NMPC控制在机械臂轨迹跟踪任务中的性能,为实际应用中选择合适的控制方法提供了参考。
相关文章:
MATLAB编写的机械臂控制仿真程序,它主要实现了对一个二连杆机械臂的运动控制仿真,比较了PID控制和非线性模型预测控制两种方法在机械臂轨迹跟踪任务中的性能
clc; clear; close all;%% 机械臂参数 l1 0.5; l2 0.4; Ts 0.02; sim_time 60; t 0:Ts:sim_time;%% 物理参数 m1 1.0; m2 0.8; g 9.81;%% 直线轨迹参数 start_point [0.3; 0.1]; end_point [0.7; 0.3]; progress t/sim_time; xd start_point(1) (end_point(1) - s…...
python办公自动化------word文件的操作
一、 word文件的创建 需要安装包:python-docx 例1:创建word文件 from docx import Document# 创建doc对象 doc Document()# 指定路径下创建一个docx文件 doc.save(./dataFile/test1_doc.docx) 运行结果: 例2:word中添加内容 …...
Python小程序 - 文件处理3:正则表达式
正则表达式:文本年鉴表。遗留的问题很多。。。用AI再想想 需求:读入txt文件,过滤文件有关年记录 0)读入txt文件 1)以“。”,中文句号,为界区分一句,最小统计单位 2)年格…...
JAVA中正则表达式的入门与使用
JAVA中正则表达式的入门与使用 一,基础概念 正则表达式(Regex) 用于匹配字符串中的特定模式,Java 中通过 java.util.regex 包实现,核心类为: Pattern:编译后的正则表达式对象。 Matcher&#…...
智慧能源管理平台:驱动电网数字化转型,引领绿色能源新时代
安科瑞 华楠18706163979 一、引言 在全球能源转型和"双碳"目标的推动下,微电网作为分布式能源系统的重要组成部分,正迎来快速发展期。安科瑞电气股份有限公司推出的微电网智慧能源管理平台(EMS 3.0),通过整…...
OpenCV 图形API(30)图像滤波-----腐蚀操作函数erode()
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 使用特定的结构元素腐蚀图像。 cv::gapi::erode 是 OpenCV 的 G-API 模块中用于执行图像腐蚀操作的函数。腐蚀是一种基本的形态学操作࿰…...
02-MySQL 面试题-mk
1.如何定位慢查询? 什么是慢查询? 页面加载过慢、接口压测响应时间过长(超过1s) 慢查询出现的情况有哪些? 聚合查询多表查询表数据量过大查询深度分页查询如何定位慢查询? 方案一:开源工具 调试工具:Arthas运维工具:Prometheus、Skywalking**Arthas:**可以使用命令的…...
利用安固软件实现电脑屏幕录像:四种实用方法分享
在日常工作中,有时我们需要录制电脑屏幕以进行教学演示、软件操作记录或重要会议的存档。安固软件终端安全管理系统提供了强大的屏幕录像功能,可以满足这些需求。 接下来,本文将介绍如何使用安固软件设置电脑实时画面录像,并分享…...
Gitee DevSecOps 以 CBB 驱动军工研发范式革新:平台化管理构件实践
随着军工软件向智能化、标准化与集约化发展,传统研发模式在效率、质量及协同方面面临显著瓶颈。项目规模扩大与系统复杂度的提升,亟需一种创新研发范式。Gitee DevSecOps 平台基于 CBB(通用构件库)理念,通过模块化、标…...
spring:xml方式调用构造方法创建Bean,调用set方法配置字段
如题: 要创建的Bean类UserServiceImpl02 : package com.itheima.service.impl;import com.itheima.dao.interfaces.InterfaceUserDao; import com.itheima.service.interfaces.InterfaceUserService;/*** copyright 2003-2024* author qiao wei* da…...
PM2 完全指南:Node.js 应用后台启动、关闭与重启详解
文章目录 **PM2 完全指南:Node.js 应用后台启动、关闭与重启详解****1. 什么是 PM2?****2. 安装 PM2****全局安装****验证安装** **3. 使用 PM2 启动 Node.js 应用****基本启动****指定应用名称****集群模式(多进程负载均衡)****监…...
LeetCode算法题(Go语言实现)_40
题目 给你一个二叉树的根节点 root。设根节点位于二叉树的第 1 层,而根节点的子节点位于第 2 层,依此类推。 请返回层内元素之和 最大 的那几层(可能只有一层)的层号,并返回其中 最小 的那个。 一、代码实现 import &…...
网关与路由器知识点
1.自治系统是由同构型的网关连接的因特网。自治系统内部的网关之间执行内部网关协议IGP,半天自治系统之间用外部网关协议EGP交换路由信息。 2.BGP4是一种动态路由发现协议,支持无类别域间路由CIDR,应用于不同ISP的网络之间,成为事…...
【Hadoop入门】Hadoop生态之Pig简介
1 什么是Pig? 在大数据分析领域,Apache Pig是一个不可忽视的重要工具。Pig是Apache Hadoop生态系统中的一个高级数据分析平台,它提供了一种称为Pig Latin的脚本语言,用于简化大规模数据集的并行处理。Pig的核心思想是将复杂的数据…...
TPS入门DAY04 服务器篇
1.创建委托并绑定回调,实现解耦 /* 创建会话完成 */ DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FMultiPlayerOnCreateSessionCompleted, bool, bWasSuccessful); /* 开始会话完成 */ DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FMultiPlayerOnStartSessionC…...
YOLO学习笔记 | YOLOv8环境搭建全流程指南(2025.4)
===================================================== github:https://github.com/MichaelBeechan CSDN:https://blog.csdn.net/u011344545 ===================================================== YOLOv8环境搭建 一、环境准备与工具配置1. Conda虚拟环境搭建2. CUDA与…...
Java 设计模式:适配器模式详解
Java 设计模式:适配器模式详解 适配器模式(Adapter Pattern)是一种结构型设计模式,它通过将一个类的接口转换为客户端期望的另一个接口,使原本不兼容的类能够协同工作。适配器模式就像现实生活中的电源适配器…...
Java的基本语法(1)
一、运算符和表达式 举例说明什么是运算符,什么是表达式: int a 1; int b 2; int c a b; 在这个例子当中,是运算符,并且是算术运算符 ab是表达式,因为是运算符,所以ab是算术表达式 1.1算术运算符 …...
Spark-Core编程二
23) sortByKey import org.apache.spark.rdd.RDD import org.apache.spark.{SparkConf, SparkContext} object Cww { def main(args: Array[String]): Unit { // 创建 SparkConf 对象,设置应用名称和运行模式 val conf new SparkConf().setAppName("SortBy…...
【antd + vue】Modal 对话框:修改弹窗标题样式、Modal.confirm自定义使用
一、标题样式 1、目标样式:修改弹窗标题样式 2、问题: 直接在对应css文件中修改样式不生效。 3、原因分析: 可能原因: 选择器权重不够,把在控制台找到的选择器直接复制下来,如果还不够就再加ÿ…...
JavaWeb 课堂笔记 —— 08 请求响应
本系列为笔者学习JavaWeb的课堂笔记,视频资源为B站黑马程序员出品的《黑马程序员JavaWeb开发教程,实现javaweb企业开发全流程(涵盖SpringMyBatisSpringMVCSpringBoot等)》,章节分布参考视频教程,为同样学习…...
DataWorks智能体Agent发布!基于MCP实现数据开发与治理自动化运行
在传统的数据开发工作中,企业用户或者开发者常常需要进行繁琐的配置、复杂的代码撰写、反复的性能调优和大量重复性的操作,才能实现数据开发、数据集成和数据治理等工作,效率十分低下。 近日,阿里云大数据开发治理平台DataWorks基…...
VitePress 项目部署 cloudflare page 提示 Node 构建错误
提示的构建错误信息为: 09:35:29.838 Error: Exit with error code: 1 09:35:29.839 at ChildProcess.<anonymous> (/snapshot/dist/run-build.js) 09:35:29.839 at Object.onceWrapper (node:events:652:26) 09:35:29.839 at ChildProcess.emit …...
VUE的node包缓存很严重,问题及解决办法
以下是一些可能导致缓存问题的地方以及如何检查和解决这些问题的建议: 1. 检查依赖包的版本是否过时 某些依赖包可能有已知的缓存问题或性能问题。以下是需要特别注意的几个包: Vue CLI 相关: vue/cli-service 和 vue/cli-plugin-babel 的版…...
<C#>在 .NET 开发中,依赖注入, 注册一个接口的多个实现
在 .NET 开发里,有时一个接口会有多个实现类,此时就需要向依赖注入容器注册多个实现。下面会详细介绍不同场景下如何注册多个实现,以及怎样从容器中解析这些实现。 1. 注册多个实现 在 .NET 中,依赖注入容器可以通过不同方式注册…...
计算机视觉色彩空间全解析:RGB、HSV与Lab的实战对比
计算机视觉色彩空间全解析:RGB、HSV与Lab的实战对比 一、前言二、RGB 色彩空间2.1 RGB 色彩空间原理2.1.1 基本概念2.1.2 颜色混合机制 2.2 RGB 在计算机视觉中的应用2.2.1 图像读取与显示2.2.2 颜色识别2.2.3 RGB 色彩空间的局限性 三、HSV 色彩空…...
美食推荐小程序
用户端 1. **定位与筛选** - **精准定位**:根据用户所在位置,推荐周边美食餐厅。 - **筛选条件**:支持按菜系(如川菜、粤菜)、价格区间、评分、距离远近等筛选餐厅。 2. **餐厅展示** - **基本信息**:…...
使用django实现windows任务调度管理
在 Django 中实现 Windows 任务调度管理,你可以使用几种不同的方法。最常见的方法是使用 Django 自带的 celery 或者 django-background-tasks 库,或者使用 Windows 自带的任务计划程序。下面我会分别介绍这几种方法: 方法 1:使用…...
【Android】Android 打包 Release 崩溃问题全解析:Lint 错误、混淆类丢失及解决方法大全
摘要: 在 Android 项目的 Release 打包过程中,经常遇到诸如 Lint 校验失败、程序闪退、类找不到等问题。本文将详细分析 Android 打包时常见的崩溃原因,特别是如何应对 Lint 报错、混淆引发的类丢失(NoClassDefFoundError…...
【Python 开源】你的 Windows 关机助手——PyQt5 版定时关机工具
🖥️ 你的 Windows 关机助手——PyQt5 版定时关机工具 相关资源文件已经打包成EXE文件,可双击直接运行程序,且文章末尾已附上相关源码,以供大家学习交流,博主主页还有更多Python相关程序案例,秉着开源精神的…...
布局决定终局:基于开源AI大模型、AI智能名片与S2B2C商城小程序的战略反推思维
摘要:在商业竞争日益激烈的当下,布局与终局预判成为企业成功的关键要素。本文探讨了布局与终局预判的智慧性,强调其虽无法做到百分之百准确,但能显著提升思考能力。终局思维作为重要战略工具,并非一步到位的战略部署&a…...
vue3循环表单【以el-form组件为例】,如何校验所有表单,所有表单校验通过后提交
1.循环时,在组件标签上使用ref绑定组件实例 3.如何校验所有表单都通过后方可提交?利用promise.all()判断 代码如下: <template><div><!-- 循环渲染表单 --><el-formv-for"(formItem, index) in formList":…...
量子代理签名:量子时代的数字授权革命
1. 量子代理签名的定义与核心原理 量子代理签名(Quantum Proxy Signature, QPS)是经典代理签名在量子信息领域的延伸,允许原始签名者(Original Signer)授权给代理签名者(Proxy Signer)代为签署文…...
HTTPS代理的实际优势,如何选择HTTPS代理服务?
在数字化时代,网络请求的安全性和效率成为企业和个人用户关注的焦点。HTTPS代理作为一种强大的工具,不仅在数据安全方面表现出色,还在安全访问、突破地域限制以及支持复杂任务等方面展现出多样化的优势。本文将深入探讨HTTPS代理的实际优势&a…...
Java 中常见的数据结构
目录 1. List (列表) 2)ArrayList 2)LinkedList 2. Set (集合) 1)HashSet 2)TreeSet 3. Map (映射) 1)HashMap 2)TreeMap 4. Queue (队列) 1)LinkedList (也实现了Queue接口) 2&…...
Transformer多卡训练初始化分布式环境:(backend=‘nccl‘)
Transformer多卡训练初始化分布式环境:(backend=‘nccl’) dist.init_process_group(backend=nccl)在多卡环境下初始化分布式训练环境,并为每个进程分配对应的 GPU 设备。下面为你逐行解释代码的含义: 1. 初始化分布式进程组 try:dist.init_process_group(backend=nccl) e…...
云曦月末断网考核复现
Web 先看一个BUUCTF中的文件一个上传题 [BUUCTF] 2020新生赛 Upload 打开后是一个文件上传页面 随便上传一个txt一句话木马后出现js弹窗,提示只能上传图片格式文件 说明有前端验证。我的做法是把一句话改为.jpg格式, 然后上传 访问发现虽然上传成功了…...
SQL Server AlwaysOn (SQL 查询数据详解及监控用途)
修正后的完整查询 SELECT ar.replica_server_name AS [副本名称],ar.availability_mode_desc AS [同步模式],DB_NAME(dbr.database_id) AS [数据库名称],dbr.database_state_desc AS [数据库状态],dbr.synchronization_state_desc AS [同步状态],dbr.synchronization_health_d…...
使用 Q - learning 算法解决迷宫路径规划问题
整体功能概述 这段 Python 代码实现了一个使用 Q - learning 算法解决迷宫路径规划问题的程序。智能体在给定的迷宫环境中学习如何找到从起点到终点的最优路径,以获得最大奖励。 模块导入 python import numpy as np import randomnumpy:用于处理数组…...
SqlYog无限试用方法
1、WinR ,输入 :regedit 回车 2、进入注册表,在 \HEYK_CURRENT_USER\Software\{*********-D8CE-4637-9BC7-93E************}下的【InD100】保存着SQLyog的使用天数 3、在【InD】上右键,点击删除该项,在重启SQLyog后注册表中会重…...
14 nginx 的 dns 缓存的流程
前言 这个是 2020年11月 记录的这个关于 nginx 的 dns 缓存的问题 docker 环境下面 前端A连到后端B 前端B连到后端A 最近从草稿箱发布这个问题的时候, 重新看了一下 发现该问题的记录中仅仅是 定位到了 nginx 这边的 dns 缓存的问题, 但是 并没有到细节, 没有到 具体的 n种…...
Spring Cloud Gateway 具体的实现案例
文章目录 前言✅ 1. **创建 Spring Boot 项目**Maven 依赖:Gradle 依赖: ✅ 2. **配置 application.yml 路由和过滤器**解释: ✅ 3. **创建自定义过滤器**3.1 **前置过滤器(Pre Filter)**3.2 **后置过滤器(…...
css易混淆的知识点
子选择器 (>) vs 后代选择器 (空格) 子选择器 (>) 只匹配直接子元素。后代选择器 (空格) 匹配所有后代元素(无论嵌套多深)。 绝对定位vs相对定位 布局: justify-content 的作用 控制子元素在主轴上的分布方式。常见值包括 flex-start、…...
OpenCV 图形API(27)图像滤波-----膨胀函数dilate()
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 使用特定的结构元素膨胀图像。 cv::gapi::dilate 是 OpenCV G-API 模块中的一个函数,用于对图像执行膨胀操作。膨胀是一种形态学操作…...
13. Git 远程仓库配置
基本步骤 以Gitee为例子,GitHub的步骤也基本一致 1.注册/登录 Gitee 账号 https://gitee.com/ 2.新建仓库 3.配置仓库 根据自己的喜好,配置即可。 4.生成SSH密钥 ssh-keygen -t ed25519 -C "你的邮箱example.com"-t ed25519:使…...
语音识别——根据声波能量、VAD 和 频谱分析实时输出文字
ASR(语音识别)是将音频信息转化为文字的技术。在实时语音识别中,一个关键问题是:如何决定将采集的音频数据输入大模型的最佳时机?固定时间间隔显然不够灵活,太短可能导致频繁调用模型,太长则会延迟文字输出。有没有更智能的方式?答案是肯定的。 一种常见的解决方案是使…...
netty中的ChannelHandler详解
Netty中的ChannelHandler是网络事件和数据处理的核心执行单元,负责处理I/O事件(如连接建立、数据读写)以及业务逻辑的实现。它通过ChannelPipeline形成责任链,实现事件的动态编排与传播。以下从功能分类、核心机制到实际应用进行详细解析: 1. ChannelHandler的核心功能与分…...
介绍一下freertos
FreeRTOS 是一款开源的实时操作系统(RTOS),专为嵌入式系统和微控制器设计,以轻量级、高可靠性、低延迟著称。它广泛应用于物联网(IoT)、工业自动化、消费电子等领域。以下是详细介绍: …...
使用克魔助手查看iOS 应用程序使用历史记录和耗能历史记录
使用克魔助手查看iOS 应用程序使用历史记录和耗能历史记录 功能概述 克魔助手无需越狱即可访问iOS上各个应用程序的历史记录,包括: 最近几个月的app的详细启动时间记录,结束时间,app使用的硬件组件应用的耗能具体情况ÿ…...
mysql和mongodb
1.mongodb 写入更快,数据结构频繁更新,这个不方便工程管理.另外会序列化成json格式,比如为json的成员建立索引,这都是比较损耗性能。字段太多,moondbjson名太多,导致数据冗余, moongodb频繁按字段更新&…...