動態避障-圖撲自動尋路 3D 視覺化

hightopo發表於2024-11-06

自動尋路是機器人導航的核心技術,其原理主要涉及機器人與環境之間的複雜資訊互動與處理。在自動尋路過程中,機器人依靠先進的感測器系統,如高畫質攝像頭、精密鐳射雷達和靈敏超聲波裝置,全方位感知周圍環境。這些感測器能夠實時捕捉並分析環境中的障礙物、地形變化和關鍵路標,為機器人提供精確的導航資料。

自動尋路在多個領域發揮著關鍵作用,從圖撲的資料中心機房的自動化巡檢系統,到智慧機器人的導航系統,再到智慧碼頭堆場的智慧化管理,自動尋路技術無處不在。該功能不僅能規劃出最優路線,還能實時考慮障礙物避讓等複雜的實際因素,靈活調整路徑以確保安全和效率。

乍聽之下,自動尋路功能略顯複雜,實現過程中也確實涉及了一些演算法。在具體實施之前,我們需要先解決兩個關鍵問題:

  1. 如何避開場景中的障礙物?
  2. 如何計算最佳路徑?

針對這兩處問題,我們可以利用圖撲軟體自研 HT for Web 提供的 ht-astar.js 外掛。該外掛具備初始化網格和自動搜尋路徑等功能,高效簡化了自動尋路的實現過程。

系統分析

場景網格化

先將場景劃分成二維網格,障礙物分佈於不同的網格單元上,部分較大的障礙物可能會佔據多個網格單元。路徑計算實際上是分析網格的佔用情況,當平臺監測到某個網格被佔用時,系統會自動尋找擇優生成一條繞行路徑。

在開發時,首先需要去例項化 ht.Astar.Finder(view, params)。其中 view 可以是 ht.graph.GraphView 或者 ht.graph3d.Graph3dView。params 是一個包含基礎屬性設定的物件。以下列舉了一些 params 的常用引數:

✧simplify:是否啟用路徑簡化。

✧closest:是否啟用最近路徑最佳化。

✧nodeRectExtend:擴充套件節點範圍。

✧gridSizeY:網格在 Y 方向上的大小。

✧gridSizeX:網格在 X 方向上的大小。

✧diagonal:是否允許沿對角線方向移動。

✧fastOverlap:是否啟用快速監測重疊演算法。

✧filter:過濾函式用於在路徑計算過程中過濾特定節點。

✧turnPunish:轉彎懲罰係數,數值越高表示越傾向於直線路徑。

具體程式碼實現:

const hindrance = dm.getDataByTag(‘hindrance’);
const astar = new ht.Astar.Finder(view, {
    gridSizeX: 50, // 網格 
    gridSizeY: 50,
    nodeRectExtend: 50,
    fastOverlap: false,
    filter: function (data) {
        return data.isDescendantOf(hindrance);
    }
});

路徑計算

在路徑計算過程中,系統需要實時監測每個網格單元的佔用狀態。若規劃的路徑遇到被障礙物佔用的網格,系統會自動尋找繞行路徑,以動態避開障礙物

在開發過程中,我們需要監聽場景背景的點選事件,獲取點選位置的座標。然後,結合起點座標,透過 astar.findPath(pFrom, pTo) 函式計算出具體路徑。計算得到的路徑是一組點位資料,可以利用這些資料在場景中繪製出一條路徑管道。具體程式碼實現:

view.mi(function (e) {
    const { kind, data, event } = e;
    if (kind === 'clickBackground') {
        const animOb = view.dm().getDataByTag('people'); // 獲取人物節點
        let pFrom = animOb.p3(); // 獲取人物節點的座標(起點座標)
        pFrom = { x: pFrom[0], y: pFrom[2] };
        let position = view.getHitPosition(event); // 根據滑鼠事件獲取場景中的邏輯座標
        const pTo = { x: position[0], y: position[2] };
        const path = astar.findPath(pFrom, pTo); // 獲取路徑
        createPloyline(path); // 生成管道
      }
})
// 生成管道
createPloyline(){
  const points: any = [];
  path.forEach((p: any, i: number) => {
      points.push({ x: p.x, y: p.y, e: 0 });
  })
  const polyline = new ht.Polyline();
  polyline.s({
      "shape3d": false,
  });
  polyline.setPoints(points);
  view.dm().add(polyline);
}

路徑動畫

在場景中生成管道後,人物節點可沿此管道移動。人物節點沿管道運動的程式碼如下:

const animOb = dm.getDataByTag('people');
animOb.playAnimation('walk'); // 示例中人物模型使用的是 fbx 模型,可播放節點上的動畫
const length = view.getLineLength(polyline);
let moveAnim = null;
const params = {
    delay: 100,
    duration: 1000 * (length / 200), // 根據管道的長度設定動畫週期
    easing: function (t) { return t },
    action: function (v, t) {
        var offset = view.getLineOffset(polyline, length * v);
        if (offset) {
            var point = offset.point,
                px = point.x,
                py = point.y,
                pz = point.z,
                tangent = offset.tangent,
                tx = tangent.x,
                ty = tangent.y,
                tz = tangent.z;
            animOb.lookAt([px + tx, py + ty, pz + tz], 'front');
            animOb.p3(px, py, pz);
        }
        // 人物運動時,視角始終跟隨
        view.setCenter([px, py, pz]); 
        view.setEye([px + 400, py + 800, pz + 400]);
},
finishFunc: () => {
    moveAnim = null;
    // 切換場景視角
    view.moveCamera([-84, 3435, 3142],  [-28, -821, -160], {
         duration: 1000
    })
    animOb.pauseAnimation(); // 暫停人物模型動畫
  }
};
moveAnim = ht.Default.startAnim(params);

最佳化視覺效果

基於上述,我們已實現了基本的自動尋路功能。在實際專案中仍需提升一定的視覺效果,讓展示頁面足夠美觀,我們可以採取以下策略:

  • 首先,將管道路徑隱藏(使用 polyline.s('transparent.mask', true));
  • 隨後,利用 ht.Shape 節點並設定貼圖來呈現人物的運動軌跡。這樣不僅能實現功能,還能大幅增強視覺吸引力。

具體實現程式碼如下:

createShape(points) {
    if(uvAnim) uvAnim.pause(); // 建立新的 shape 前將舊shape 的 uv 偏移動畫移除
    const shape = this.shape = new ht.Shape();
    shape.s({
        "shape.border.color": "rgb(255,0,0)",
        "all.visible": false,
        "all.transparent": true,
        "top.visible": true,
        "top.image": "assets/arrow.png",
        "top.uv.scale": [
            length / 500,
            1
        ],
        "texture.cache": true,
        "3d.selectable": true,
        "3d.editable": false,
        "3d.movable": false,
        "3d.visible": true
    })
    dm.add(shape);
    shape.setThickness(30);
    shape.setPoints(points);
    return shape;
}
// ht.Shape 的 uv 偏移動畫
playShapeAnim(shape) {
  if (!shape) return;
  const params = {
    duration: 2000,
    easing: function (t: number) {
      return t;
    },
    action: function (v: number, t: number) {
      shape.s("all.uv.offset", [v, 0]);
    },
    finishFunc: () => {
      uvAnim = null;
      uvAnim = ht.Default.startAnim(params);
    }
  };
  uvAnim = ht.Default.startAnim(params);
}
const points: any = [];
path.forEach((p: any, i: number) => {
    points.push({ x: p.x, y: p.y, e: 0 });
})
const shape = createShape(points);
let uvAnim = null;
playShapeAnim(shape); // 執行shape 的 uv 偏移動畫

總結

作為開發者的我們,將繼續探索和最佳化自動尋路技術,利用圖撲 HT 提供的外掛工具,不斷提升演算法效率和使用者體驗。透過合理的引數設定、精確的網格劃分和智慧的路徑規劃,為各種應用場景提供更加出色的自動尋路解決方案。

您可以至圖撲軟體官網檢視更多案例及效果:

https://www.hightopo.com/demos/index.html

相關文章