Main Content

既知の姿勢を使用する地図作成

この例では、差動駆動型ロボットの距離センサーの読み取り値とロボットの姿勢を使用して環境マップを作成する方法を説明します。rangeSensor オブジェクトを使用してシミュレートされた距離センサー読み取り値から、マップを作成します。differentialDriveKinematics 運動モデルは、速度コマンドに基づいて室内を移動するロボットの駆動をシミュレートします。rangeSensor は、パスを追従しているロボットの姿勢に基づいて、距離の読み取り値を提供します。

参照マップと Figure

exampleMaps から、この例で使用する simpleMap を含む、一連のバイナリ占有グリッド例を読み込みます。

load exampleMaps.mat

simpleMap を分解能 1 で使用して、参照用バイナリ占有マップを作成します。Figure を表示して、その Figure のハンドルを保存します。

refMap = binaryOccupancyMap(simpleMap,1);
refFigure = figure('Name','SimpleMap');
show(refMap);

選択したマップと同じ次元の空のマップを分解能 10 で作成します。Figure を表示して、その Figure のハンドルを保存します。座標軸をマップのサイズにロックします。

[mapdimx,mapdimy] = size(simpleMap);
map = binaryOccupancyMap(mapdimy,mapdimx,10);
mapFigure = figure('Name','Unknown Map');
show(map);

運動モデルとコントローラーの初期化

差動駆動型の運動学的運動モデルを作成します。運動モデルはシミュレートされる差動駆動型ロボットの運動を表します。このモデルは、左右の車輪の速度または線形速度と角速度をロボットの進行方向として取ります。この例では VehicleInputs にビークル速度と向首角速度を使用します。

diffDrive = differentialDriveKinematics("VehicleInputs","VehicleSpeedHeadingRate");

単純追跡コントローラーを作成します。このコントローラーは、シミュレートするロボットが目的のパスを追従するための速度入力を生成します。目的の線形速度を m/s 単位、最大角速度を rad/s 単位でそれぞれ設定します。

controller = controllerPurePursuit('DesiredLinearVelocity',2,'MaxAngularVelocity',3);

距離センサーの設定

最大距離が 10 m のセンサーを作成します。このセンサーは与えられた姿勢とマップに基づいて距離の読み取り値をシミュレートします。この距離センサーとともに参照マップを使用して、未知の環境におけるセンサー読み取り値の収集をシミュレートします。

sensor = rangeSensor;
sensor.Range = [0,10];

計画されたパスの作成

距離センサー読み取り値を収集するために、マップ内の走行パスを作成します。

path = [4 6; 6.5 12.5; 4 22; 12 14; 22 22; 16 12; 20 10; 14 6; 22 3];

参照マップの Figure 上にパスをプロットします。

figure(refFigure);
hold on
plot(path(:,1),path(:,2), 'o-');
hold off

パスを単純追跡コントローラーのウェイポイントとして設定します。

controller.Waypoints = path;

パスの追跡とマップ環境

初期姿勢とパスに基づく最終ゴール位置を設定します。反復を追跡するために、現在の姿勢とインデックスを格納するグローバル変数を作成します。

initPose = [path(1,1) path(1,2), pi/2];
goal = [path(end,1) path(end,2)]';
poses(:,1) = initPose';

提供されている補助関数 exampleHelperDiffDriveCtrl を使用します。補助関数には、パスを通り、距離の読み取り値を取得し、環境を地図作成するためのメイン ループが含まれています。

関数 exampleHelperDiffDriveControl のワークフローは次のとおりです。

  • 距離センサーと現在の姿勢を使用して参照マップをスキャンします。これにより未知の環境で走行するための正常な距離読み取り値をシミュレートします。

  • 距離の読み取り値を使用してマップを更新します。

  • 単純追跡コントローラーから、次のウェイポイントまで走行するための制御コマンドを取得します。

  • 制御コマンドに基づいてロボットの運動の微分を計算します。

  • 微分に基づいてロボットの姿勢をインクリメントします。

空のマップ内を走行するロボットと、距離センサーによって検出された壁が表示されるはずです。

exampleHelperDiffDriveCtrl(diffDrive,controller,initPose,goal,refMap,map,refFigure,mapFigure,sensor)

Goal position reached

差動駆動型の制御関数

関数 exampleHelperDiffDriveControl のワークフローは次のとおりです。

  • 距離センサーと現在の姿勢を使用して参照マップをスキャンします。これにより未知の環境で走行するための正常な距離読み取り値をシミュレートします。

  • 距離の読み取り値を使用してマップを更新します。

  • 単純追跡コントローラーから、次のウェイポイントまで走行するための制御コマンドを取得します。

  • 制御コマンドに基づいてロボットの運動の微分を計算します。

  • 微分に基づいてロボットの姿勢をインクリメントします。

function exampleHelperDiffDriveControl(diffDrive,ppControl,initPose,goal,map1,map2,fig1,fig2,lidar)
sampleTime = 0.05;             % Sample time [s]
t = 0:sampleTime:100;         % Time array
poses = zeros(3,numel(t));    % Pose matrix
poses(:,1) = initPose';

% Set iteration rate
r = rateControl(1/sampleTime);

% Get the axes from the figures
ax1 = fig1.CurrentAxes;
ax2 = fig2.CurrentAxes;

    for idx = 1:numel(t)
        position = poses(:,idx)';
        currPose = position(1:2);
        
        % End if pathfollowing is vehicle has reached goal position within tolerance of 0.2m
        dist = norm(goal'-currPose);
        if (dist < .2)
            disp("Goal position reached")
            break;
        end
        
        % Update map by taking sensor measurements
        figure(2)
        [ranges, angles] = lidar(position, map1);
        scan = lidarScan(ranges,angles);
        validScan = removeInvalidData(scan,'RangeLimits',[0,lidar.Range(2)]);
        insertRay(map2,position,validScan,lidar.Range(2));
        show(map2);
        
        % Run the Pure Pursuit controller and convert output to wheel speeds
        [vRef,wRef] = ppControl(poses(:,idx));
    
        % Perform forward discrete integration step
        vel = derivative(diffDrive, poses(:,idx), [vRef wRef]);
        poses(:,idx+1) = poses(:,idx) + vel*sampleTime; 
    
    
        % Update visualization
        plotTrvec = [poses(1:2, idx+1); 0];
        plotRot = axang2quat([0 0 1 poses(3, idx+1)]);
        
        % Delete image of the last robot to prevent displaying multiple robots
        if idx > 1
           items = get(ax1, 'Children');
           delete(items(1)); 
        end
    
        %plot robot onto known map
        plotTransforms(plotTrvec', plotRot, 'MeshFilePath', 'groundvehicle.stl', 'View', '2D', 'FrameSize', 1, 'Parent', ax1);
        %plot robot on new map
        plotTransforms(plotTrvec', plotRot, 'MeshFilePath', 'groundvehicle.stl', 'View', '2D', 'FrameSize', 1, 'Parent', ax2);
    
        % waiting to iterate at the proper rate
        waitfor(r);
    end
end