Bootstrap

移动机器人运动模型

unicycleKinematics

unicycleKinematics 创建了一个独轮车模型,用于模拟类似汽车的简化车辆动力学。车辆状态被定义为一个三元素向量 [x y theta],其中全局 xy 位置以米为单位,车辆航向角 theta 以弧度为单位。该模型近似于一个具有给定车轮半径(WheelRadius)的独轮车,它可以根据航向角(theta)原地旋转。要计算模型的时间导数状态,可使用导数函数,输入指令和机器人当前状态。

创建

语法

kinematicModel = unicycleKinematics

kinematicModel = unicycleKinematics(Name,Value)

描述

kinematicModel = unicycleKinematics 创建一个具有默认属性值的独轮车运动模型对象。

kinematicModel = unicycleKinematics(Name,Value) 将附加属性设置为指定值。可以任意顺序指定多个属性。

属性

WheelRadius - 车辆的车轮半径
0.1(默认) | 正数 值标量
车辆的车轮半径,单位为米。

WheelSpeedRange - 车轮速度范围
[-Inf Inf](默认) | 双元素向量
车速范围是一个双元素向量,提供最小和最大车速[MinSpeed MaxSpeed],单位为米/秒。

VehicleInputs - 车辆运动输入类型
"WheelSpeedHeadingRate"(默认) | 字符向量 | 字符串标量
VehicleInputs 属性用于指定使用derivative函数时模型输入命令的格式。选项指定为以下字符串之一:

"WheelSpeedHeadingRate" - 车轮速度和航向角速度,单位为弧度/秒。

"VehicleSpeedHeadingRate" - 车辆速度和航向角速度,单位为弧度/秒。

对象函数

derivative 车辆状态的时间导数

kinematicModel = unicycleKinematics; %定义一个机器人
initialState = [0 0 0];              %设置初始位置和方向

%模拟机器人运动

%将模拟时间跨度设置为 1 秒,时间步长为 0.05 秒,
%输入指令为 10 m/s,航向角速度为 pi/4 rad/s,以进行左转。
%使用求导函数 ode45 求解器模拟机器人的运动。

tspan = 0:0.05:1;   %模拟的时间
inputs = [10 pi/4]; %匀速左转
[t,y] = ode45(@(t,y)derivative(kinematicModel,y,inputs),tspan,initialState);

%画图
figure
plot(y(:,1),y(:,2))

运行结果

Figure contains an axes object. The axes object contains an object of type line.

differentialDriveKinematics

differentialDriveKinematics 可创建差速驱动车辆模型,模拟简化的车辆动力学。该模型近似于带有单个固定车轴的车辆,车轮之间有指定的轨道宽度。车轮可独立驱动。车速和方向由车轴中心确定。车辆状态被定义为一个三元素向量 [x y theta],其中全局 xy 位置以米为单位,车辆航向 theta 以弧度为单位。要计算模型的时间导数状态,可使用导数函数,输入指令和机器人当前状态。

创建

语法

kinematicModel = differentialDriveKinematics

kinematicModel = differentialDriveKinematics(Name,Value)

描述

kinematicModel = differentialDriveKinematics 将创建具有默认属性值的差分驱动运动模型对象。

kinematicModel = differentialDriveKinematics(Name,Value) 将对象上的属性设置为指定值。可以任意顺序指定多个属性。

属性

WheelRadius - 车辆的车轮半径
0.05(默认值) | 正数 值标量
车辆的车轮半径,单位为米。

WheelSpeedRange - 车轮速度范围
[-Inf Inf](默认) | 双元素向量
车速范围是一个双元素向量,提供最小和最大车速[MinSpeed MaxSpeed],单位为米/秒。

TrackWidth - 车轴上车轮之间的距离
0.2(默认值) | 正数值标量
车辆轨道宽度指车轮之间的距离或车轴长度,单位为米。

VehicleInputs - 车辆运动输入类型
"WheelSpeeds"(默认) | 字符向量 | 字符串标量
VehicleInputs 属性用于指定使用导数函数时模型输入命令的格式。选项指定为以下字符串之一:

"WheelSpeeds" - 每个车轮的角速度,单位为弧度/秒。

"VehicleSpeedHeadingRate" - 车辆速度和航向角速度,分别以米/秒和弧度/秒为单位。

kinematicModel = differentialDriveKinematics;%定于一个机器人
initialState = [0 0 0];                      %设置初始位置和方向
%模拟机器人运动

%将模拟时间跨度设为 1 秒,时间步长为 0.05 秒,
%输入指令左轮为 50 rad/s,右轮为 40 rad/s,以实现右转。
%使用导数函数上的 ode45 求解器模拟机器人的运动。

tspan = 0:0.05:1;
inputs = [50 40]; %左轮转得更快
[t,y] = ode45(@(t,y)derivative(kinematicModel,y,inputs),tspan,initialState);


%画图
figure
plot(y(:,1),y(:,2))


运行结果

Figure contains an axes object. The axes object contains an object of type line.

bicycleKinematics

bicycleKinematics 创建了一个自行车车辆模型,用于模拟类似汽车的简化车辆动力学。该模型表示车辆的两个车轴之间有一定的距离,即轮距(WheelBase)。车辆状态被定义为一个三元素向量 [x y theta],其中全局 xy 位置以米为单位,车辆航向角 theta 以弧度为单位。前轮可通过转向角 \psi转动。车辆航向 Theta 定义在后轴中心。要计算模型的时间导数状态,可使用导数函数和输入指令以及机器人当前状态。

创建

语法

kinematicModel = bicycleKinematics

kinematicModel = bicycleKinematics(Name,Value)

描述

kinematicModel = bicycleKinematics 创建一个具有默认属性值的自行车运动模型对象。

kinematicModel = bicycleKinematics(Name,Value) 将附加属性设置为指定值。您可以按任意顺序指定多个属性。

属性

WheelBase - 前后轴之间的距离
1(默认) | 正数 值标量
轮距是指前后车轴之间的距离,单位为米。

VehicleSpeedRange - 车辆速度范围
[-Inf Inf](默认) | 正数标量
车辆速度范围是一个双元素向量,提供最小和最大车辆速度[MinSpeed MaxSpeed],单位为米/秒。

MaxSteeringAngle - 最大转向角
π/4(默认值) | 数值标量
最大转向角 \psi 是指车辆可向右或向左转向的最大角度,以弧度为单位。该属性用于验证用户提供的状态输入。

如果 MaxSteeringAngle 设置为 pi/2,则最小转弯半径值为 0。

MinimumTurningRadius - 最小车辆转弯半径
1.0000(默认值) | 数值标量
此属性为只读。

车辆最小转弯半径,以数字标量形式指定,单位为米。最小转弯半径使用轮距和最大转向角计算得出。

VehicleInputs - 车辆运动输入类型
"车辆速度转向角"(默认) | 字符向量 | 字符串标量
VehicleInputs 属性用于指定使用derivative函数时模型输入命令的格式。该属性有两个有效选项,分别指定为字符串或字符矢量:

"VehicleSpeedSteeringAngle" - 车辆速度和转向角

"VehicleSpeedHeadingRate" - 车辆速度和航向角速度

kinematicModel=bicycleKinematics; %定义一个机器人
initialState=[0 0 0];             %设置初始位置和方向

%模拟机器人运动

%将模拟时间跨度设为 1 秒,时间步长为 0.05 秒,
%输入指令为 2 米/秒的车速和 pi/4 弧度的转向角,以创建一个左转弯。
%使用导数函数上的 ode45 求解器模拟机器人的运动。

tspan=0:0.05:1;
inputs=[2 pi/4]; %左转弯
[t y]=ode45(@(t,y)derivative(kinematicModel,y,inputs),tspan,initialState);

%画图
figure
plot(y(:,1),y(:,2))

 运行结果

Figure contains an axes object. The axes object contains an object of type line.

ackermannKinematics

ackermannKinematics 创建了一个使用阿克曼转向系统的汽车模型。该模型表示车辆的两个车轴之间的距离(WheelBase)。车辆的状态被定义为一个四元素向量 [x y theta \psi],其全局 xy 位置以米为单位。xy 位置位于后车轴中部。车辆航向(theta)和转向角(\psi)以弧度为单位。车辆航向以后轴中心为基准。角度单位为弧度。要计算模型的时间导数状态,可使用derivative函数,输入转向指令和机器人当前状态。

创建

语法

kinematicModel = ackermannKinematics

kinematicModel = ackermannKinematics(Name,Value)

描述 

kinematicModel = ackermannKinematics 以默认属性值创建阿克曼运动模型对象。

kinematicModel = ackermannKinematics(Name,Value) 将附加属性设置为指定值。可以任意顺序指定多个属性。

属性

WheelBase - 前后轴之间的距离
1(默认) | 正数值标量
轮距是指前后车轴之间的距离,单位为米。

VehicleSpeedRange - 车辆轮速范围
[-Inf Inf](默认) | 双元素向量
车辆速度范围是一个双元素向量,提供最小和最大车辆速度[MinSpeed MaxSpeed],单位为米/秒。

%模拟移动机器人的不同运动模型

% 该示例展示了如何在一个环境中建立不同的机器人运动学模型,
% 并对它们进行比较。

% 用运动学约束条件定义移动机器人
% 有许多方法可以建立移动机器人的运动学模型。
% 所有方法都规定了车轮速度与机器人状态的关系: 
% [x y theta],即 xy 坐标和以弧度为单位的机器人航向 theta。

% 独轮车运动学模型
% 表示移动机器人车辆运动学的最简单方法是使用独轮车模型,
% 该模型的车轮速度由围绕中心轴的旋转来设定,并可围绕 Z 轴转动。
% 差速驱动和自行车运动学模型都可以简化为独轮车运动学模型,
% 前提是输入的是车辆速度和车辆速度,而不考虑其他约束条件。

unicycle = unicycleKinematics("VehicleInputs","VehicleSpeedHeadingRate");

% 差速器传动运动学模型
% 差速驱动车型使用后驱动桥来控制车速和压头率。驱动桥上的车轮可以双向旋转。
% 由于大多数移动机器人都有一些与低级车轮命令的接口,
% 该模型将再次使用车辆速度和航向率作为输入,以简化车辆控制。
diffDrive = differentialDriveKinematics("VehicleInputs","VehicleSpeedHeadingRate");
% 为了将这种行为与独轮车模型区分开来,可在差速驱动运动学模型中添加车轮速度约束条件
diffDrive.WheelSpeedRange = [-10 10]*2*pi;

% 自行车运动模型
% 自行车模型将机器人视为一个类似汽车的模型,有两个车轴:
% 一个是后驱动车轴,另一个是绕 Z 轴转动的前车轴。
% 自行车模型的工作假设是,每个车轴上的车轮都可以建模为一个居中的车轮,
% 并且可以像自行车一样直接设置前轮的方向。
bicycle = bicycleKinematics("VehicleInputs","VehicleSpeedHeadingRate","MaxSteeringAngle",pi/8);

% 其他模型
% 阿克曼运动学模型是一种假设阿克曼转向的改进型类汽车模型。
% 在大多数类似汽车的车辆中,前轮并不围绕同一轴线转动,
% 而是在略微不同的轴线上转动,以确保它们围绕车辆转弯中心的同心圆行驶。
% 这种转动角度上的差异被称为阿克曼转向,在实际车辆中通常是通过机械装置来实现的。
% 从车辆和车轮运动学的角度来看,可以通过将转向角作为速率输入来实现。
carLike = ackermannKinematics;

% 设置模拟参数
% 这些移动机器人将沿着一组航点前进,这些航点旨在显示不同运动学造成的一些差异。
waypoints = [0  0; 
             0 10; 
            10 10; 
             5 10; 
            11  9; 
             4 -5];
% 定义总时间和采样率
sampleTime = 0.05;               % 采样时间 [s]
tVec = 0:sampleTime:20;          % 时间数组

initPose = [waypoints(1,:)'; 0]; % 初始姿势(x y theta)

% 创建车辆控制器
% 车辆使用 "纯粹追逐 "控制器跟踪一组航点。
% 给定一组航点、机器人当前状态和一些其他参数后,控制器会输出车辆速度和航向率。

% 定义控制器 每个机器人都需要自己的控制器
controller1 = controllerPurePursuit("Waypoints",waypoints,"DesiredLinearVelocity",3,"MaxAngularVelocity",3*pi);
controller2 = controllerPurePursuit("Waypoints",waypoints,"DesiredLinearVelocity",3,"MaxAngularVelocity",3*pi);
controller3 = controllerPurePursuit("Waypoints",waypoints,"DesiredLinearVelocity",3,"MaxAngularVelocity",3*pi);

% 使用 ODE 求解器模拟模型
% 
% 使用导数函数对模型进行模拟,以更新状态。
% 本示例使用常微分方程 (ODE) 求解器生成解决方案。
% 另一种方法是使用循环更新状态,如《差分驱动机器人的路径跟踪》中所示。
% 
% 由于 ODE 求解器要求将所有输出作为单一输出提供,
% 因此必须将纯粹的追逐控制器封装在一个函数中,
% 将线速度和航向角速度作为单一输出输出。
% 为此,我们使用了一个示例辅助函数 exampleHelperMobileRobotController。
% 示例助手还确保机器人在目标指定半径内停止。
goalPoints = waypoints(end,:)';
goalRadius = 1;

% 每种类型的模型都会调用一次 ode45。
% 导数函数根据 initPose 设置的初始状态计算状态输出。
% 每个导数都接受相应的运动模型对象、当前机器人姿态和控制器在该姿态下的输出。
% 为运动控制下的每个运动模型计算轨迹
[tUnicycle,  unicyclePose] = ode45(@(t,y)derivative(unicycle, y,exampleHelperMobileRobotController(controller1,y,goalPoints,goalRadius)),tVec,initPose);
[tBicycle,    bicyclePose] = ode45(@(t,y)derivative(bicycle,  y,exampleHelperMobileRobotController(controller2,y,goalPoints,goalRadius)),tVec,initPose);
[tDiffDrive,diffDrivePose] = ode45(@(t,y)derivative(diffDrive,y,exampleHelperMobileRobotController(controller3,y,goalPoints,goalRadius)),tVec,initPose);

% 绘制结果图
% 
% 使用 plotTransforms 可以在一张图上轻松查看 ODE 求解器的结果,
% 从而一次性直观地看到所有轨迹的结果。
% 
% 首先必须将姿态输出转换为平移和四元数的索引矩阵。

unicycleTranslations = [unicyclePose(:,1:2) zeros(length(unicyclePose),1)];
unicycleRot = axang2quat([repmat([0 0 1],length(unicyclePose),1) unicyclePose(:,3)]);

bicycleTranslations = [bicyclePose(:,1:2) zeros(length(bicyclePose),1)];
bicycleRot = axang2quat([repmat([0 0 1],length(bicyclePose),1) bicyclePose(:,3)]);

diffDriveTranslations = [diffDrivePose(:,1:2) zeros(length(diffDrivePose),1)];
diffDriveRot = axang2quat([repmat([0 0 1],length(diffDrivePose),1) diffDrivePose(:,3)]);

% 接下来,可以绘制所有变换的集合,并从顶部查看。
% 独轮车、自行车和差速驱动机器人的路径分别为红色、蓝色和绿色。
% 为了简化绘图,只显示每十个输出。
figure
plot(waypoints(:,1),waypoints(:,2),"kx-","MarkerSize",20);
hold all
plotTransforms( unicycleTranslations(1:10:end,:), unicycleRot(1:10:end,:),'MeshFilePath','groundvehicle.stl',"MeshColor","r");
plotTransforms(  bicycleTranslations(1:10:end,:),  bicycleRot(1:10:end,:),'MeshFilePath','groundvehicle.stl',"MeshColor","b");
plotTransforms(diffDriveTranslations(1:10:end,:),diffDriveRot(1:10:end,:),'MeshFilePath','groundvehicle.stl',"MeshColor","g");
view(0,90)





function robotRefState = exampleHelperMobileRobotController(purePursuitObj, robotPose, robotGoal, goalRadius)
% exampleHelperMobileRobotController 将纯粹追逐控制器的输出转换为单一输出
%   此函数接受纯粹追随控制器对象 PUREPURSUITOBJ 和受控机器人的当前姿态。
%   该函数将控制器的两个输出合并为一个 2x1 输出,
%   即 ROBOTREFSTATE。这样,控制器就可以轻松地与ode  求解器。

% 获取控制器输出
controller = purePursuitObj;
[vRef, wRef] = controller(robotPose);

% 达到目标后停止控制器
distanceToGoal = norm(robotPose(1:2) - robotGoal(:));
if distanceToGoal < goalRadius
    vRef = 0;
    wRef = 0;
end
robotRefState = [vRef; wRef];
end

运行结果

Figure contains an axes object. The axes object contains 493 objects of type patch, line.

 

% 利用转向角约束模拟阿克曼运动模型

% 模拟一个使用阿克曼转向技术的移动机器人模型,并对其转向角度进行限制。
% 在模拟过程中,模型在达到转向极限后会保持最大转向角。
% 为了解转向饱和的影响,您可以比较两个机器人的轨迹,
% 其中一个有转向角限制,另一个没有任何转向限制。

% 定义模型
% 
% 定义阿克曼运动模型。在这个类似汽车的模型中,前轮之间有一定的距离。
% 为了确保它们在同心圆上转动,车轮具有不同的转向角。
% 转弯时,前轮接收到的转向输入为转向角的变化率。

carLike = ackermannKinematics; 

% 设置模拟参数
% 
% 设置移动机器人以恒定线速度移动,并接收恒定转向率作为输入。
% 对受限机器人进行较长时间的模拟,以显示转向饱和。
velo = 5;    % 恒定线速度
psidot = 1;  % 恒定左转向率 

% 定义总时间和采样率
sampleTime = 0.05;                  % 采样时间 [s]
timeEnd1 = 1.5;                     % 无约束机器人的模拟结束时间
timeEnd2 = 10;                      % 受约束机器人的模拟结束时间
tVec1 = 0:sampleTime:timeEnd1;      % 无约束机器人的时间阵列
tVec2 = 0:sampleTime:timeEnd2;      % 受约束机器人的时间阵列 

initPose = [0;0;0;0];               % 初始姿势(x y theta phi)

% 为 ODE 求解器创建选项结构
% 
% 在本例中,您需要将一个选项结构作为参数传递给 ODE 求解器。
% 该选项结构包含有关转向角限制的信息。
% 要创建选项结构,请使用 odeset 的 Events 选项和创建的事件函数 detectSteeringSaturation。
% 
% 有关如何定义 detectSteeringSaturation 的说明,请参阅本示例末尾的定义事件函数。
options = odeset('Events',@detectSteeringSaturation);

% 使用 ODE 求解器模拟模型
% 
% 接下来,您可以使用导数函数和 ODE 求解器 ode45 来求解模型并生成解决方案。
% 模拟无约束机器人
[t1,pose1]          = ode45(@(t,y)derivative(carLike,y,[velo psidot]),tVec1,initPose);
% 模拟受约束机器人
[t2,pose2,te,ye,ie] = ode45(@(t,y)derivative(carLike,y,[velo psidot]),tVec2,initPose,options);

% 检测转向饱和度
% 
% 当模型达到转向极限时,它会记录下事件的时间戳。达到极限的时间存储在 te 中。
if te < timeEnd2
    str1 = "转向角达到极限值";
    str2 = " 秒";
    comp = str1 + te + str2; 
    disp(comp)
end 

% 用新的初始条件模拟受约束机器人
% 
% 现在,使用积分结束前的受约束机器人状态作为第二次模拟的初始条件。
% 修改输入矢量,以表示转向饱和状态,即把转向率设为零。
saturatedPsiDot = 0;             % 饱和后的转向率
cmds = [velo saturatedPsiDot];   % 指令向量
tVec3 = te:sampleTime:timeEnd2;  % 时间向量
pose3 = pose2(length(pose2),:); 
[t3,pose3,te3,ye3,ie3] = ode45(@(t,y)derivative(carLike,y,cmds), tVec3,pose3, options);

% 绘制结果
% 
% 使用 plot 和存储在姿势中的数据绘制机器人的轨迹。
figure(1)
plot(pose1(:,1),pose1(:,2),'--r','LineWidth',2); 
hold on; 
plot([pose2(:,1); pose3(:,1)],[pose2(:,2);pose3(:,2)],'g'); 
title('X-Y 运动轨迹')
xlabel('X')
ylabel('Y') 
legend('无约束机器人','受约束机器人','Location','northwest')
axis equal

% 定义事件函数
% 设置事件函数,使积分在第 4 个状态 Theta 等于最大转向角时终止。
function [state,isterminal,direction] = detectSteeringSaturation(t,y)
  maxSteerAngle = 0.785;               % 最大转向角(pi/4 弧度)
  state(4) = (y(4) - maxSteerAngle);   % 当第 4 个状态 Theta 等于最大转向角时,饱和事件发生
  isterminal(4) = 1;                   % 事件发生时终止集成 
  direction(4) = 0;                    % 双向终端
end


 

悦读

道可道,非常道;名可名,非常名。 无名,天地之始,有名,万物之母。 故常无欲,以观其妙,常有欲,以观其徼。 此两者,同出而异名,同谓之玄,玄之又玄,众妙之门。

;