ego(2)---初始軌跡生成后的關鍵點采樣

在初始的多項式軌跡生成后,是要經過一個關鍵點采樣,使用關鍵點來進行后續的 B 樣條曲線擬合的。即:

初始多項式擬合->關鍵點采樣->B樣條擬合

關鍵點采樣的思路

關鍵點采樣使用時間步長 ts 來在初始軌跡方程中取點。

在上一步的初始軌跡生成后,軌跡方程保存在 gl_traj 中,ego 的關鍵點采樣就是選取合適的 ts,在軌跡方程中代入 ts ,選取一定量的關鍵點,用于后續的 B 樣條擬合。

ts的選取

初始步長的確定

采樣步長的初始值使用參數步長 (pp_.ctrl_pt_dist) 以及參數最大速度 (pp_.max_vel_) 來確定:

// ts 初始數值先使用參數控制點距離與最大速度參數來設定
double ts = (start_pt - local_target_pt).norm() > 0.1 ? pp_.ctrl_pt_dist / pp_.max_vel_ * 1.2 : pp_.ctrl_pt_dist / pp_.max_vel_ * 5;

動態確定最終合適的步長

初始步長不一定是最合適的,可能會有采樣點比較密集或者稀疏的問題,因此需要再進行一次動態確定最終步長的過程,在 ego 中是使用了一個 do,while 循環,在進行循環之前,先把初始的 ts 進行放大:

ts *= 1.5; // ts will be divided by 1.5 in the next  將最初的時間間隔放大,避免因為初始 ts 過小導致采樣點很密集

之后在每次循環中,逐步減小 ts ,然后判斷根據當前 ts 采樣到的點是否滿足要求,不滿足就繼續降低 ts:

// 以下循環用于找到合適的時間步 ts,保證分割點合適,不會太過密集,同時也控制數量需要超大于等于7個,用于后續的B樣條擬合
do
{ts /= 1.5;  // 每次循環時將 ts 除以 1.5,逐漸找到合適的時間步point_set.clear();    // 每次修改時間步后,清除點flag_too_far = false;Eigen::Vector3d last_pt = gl_traj.evaluate(0);  // 獲取軌跡起點// 根據當前的時間步 來循環采點,判斷是否需要進一步縮小 ts 來采點for (t = 0; t < time; t += ts){Eigen::Vector3d pt = gl_traj.evaluate(t); // 計算 t 時刻的軌跡位置// 檢查相鄰的采樣點距離是否超限if ((last_pt - pt).norm() > pp_.ctrl_pt_dist * 1.5){flag_too_far = true;  // 距離過遠時,置位標志,進一步縮小 ts break;}last_pt = pt;point_set.push_back(pt);}
} while (flag_too_far || point_set.size() < 7); // To make sure the initial path has enough points.

根據最終的出循環條件,找到一個距離足夠遠,且數量大于等于 7 個的采樣點的 ts。

之后將此 ts 對應的起點,終點的速度,加速度記錄下來:

t -= ts;  // 回退到最后一個采樣點的時刻(因為上面循環中有最后一個 t += ts)
// 記錄軌跡起點,終點的速度,加速度信息
start_end_derivatives.push_back(gl_traj.evaluateVel(0));
start_end_derivatives.push_back(local_target_vel);
start_end_derivatives.push_back(gl_traj.evaluateAcc(0));
start_end_derivatives.push_back(gl_traj.evaluateAcc(t));

python代碼驗證

編寫代碼來驗證效果的話,只需要在上一篇的基礎上,添加一下總時間,以及動態計算即可,然后把點給畫出來看看效果:

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
class PolynomialTraj:"""實現EGO-Planner中描述的五次多項式軌跡生成"""def __init__(self, coeffs, total_time):self.coeffs = coeffs  # 多項式系數 (3x6矩陣)self.total_time = total_time  # 軌跡總時間@staticmethoddef one_segment_traj_gen(start_pt, start_vel, start_acc,end_pt, end_vel, end_acc, total_time):"""生成單段五次多項式軌跡,滿足6個運動學約束條件參數:start_pt: 起點位置 [x, y, z]start_vel: 起點速度 [vx, vy, vz]start_acc: 起點加速度 [ax, ay, az]end_pt: 終點位置 [x, y, z]end_vel: 終點速度 [vx, vy, vz]end_acc: 終點加速度 [ax, ay, az]total_time: 軌跡總時間返回:PolynomialTraj對象"""# 構造約束矩陣Ct = total_timeC = np.zeros((6, 6))# t=0時刻的約束C[0, 5] = 1  # 位置: x(0) = c0C[1, 4] = 1  # 速度: v(0) = c1C[2, 3] = 2  # 加速度: a(0) = 2*c2# t=T時刻的約束C[3] = [t **5, t** 4, t ** 3, t ** 2, t, 1]  # 位置C[4] = [5 * t **4, 4 * t** 3, 3 * t ** 2, 2 * t, 1, 0]  # 速度C[5] = [20 * t **3, 12 * t** 2, 6 * t, 2, 0, 0]  # 加速度# 求解三個方向的多項式系數coeffs = np.zeros((3, 6))for i in range(3):# 構造約束向量BB = np.array([start_pt[i],  # 起點位置start_vel[i],  # 起點速度start_acc[i],  # 起點加速度end_pt[i],  # 終點位置end_vel[i],  # 終點速度end_acc[i]  # 終點加速度])# 求解線性方程組 C·coeff = B,得到系數coeffs[i] = np.linalg.solve(C, B)return PolynomialTraj(coeffs, total_time)def evaluate(self, time):"""計算指定時刻的位置"""t = np.clip(time, 0, self.total_time)# 計算位置 (x(t) = c5*t^5 + c4*t^4 + c3*t^3 + c2*t^2 + c1*t + c0)pos = np.zeros(3)pos[0] = np.dot(self.coeffs[0], [t **5, t** 4, t ** 3, t ** 2, t, 1])pos[1] = np.dot(self.coeffs[1], [t **5, t** 4, t ** 3, t ** 2, t, 1])pos[2] = np.dot(self.coeffs[2], [t **5, t** 4, t ** 3, t ** 2, t, 1])return posdef evaluate_full(self, time):"""計算指定時刻的位置、速度和加速度"""t = np.clip(time, 0, self.total_time)pos = np.zeros(3)vel = np.zeros(3)acc = np.zeros(3)# 計算位置pos[0] = np.dot(self.coeffs[0], [t **5, t** 4, t ** 3, t ** 2, t, 1])pos[1] = np.dot(self.coeffs[1], [t **5, t** 4, t ** 3, t ** 2, t, 1])pos[2] = np.dot(self.coeffs[2], [t **5, t** 4, t ** 3, t ** 2, t, 1])# 計算速度vel[0] = np.dot(self.coeffs[0], [5 * t **4, 4 * t** 3, 3 * t ** 2, 2 * t, 1, 0])vel[1] = np.dot(self.coeffs[1], [5 * t **4, 4 * t** 3, 3 * t ** 2, 2 * t, 1, 0])vel[2] = np.dot(self.coeffs[2], [5 * t **4, 4 * t** 3, 3 * t ** 2, 2 * t, 1, 0])# 計算加速度acc[0] = np.dot(self.coeffs[0], [20 * t **3, 12 * t** 2, 6 * t, 2, 0, 0])acc[1] = np.dot(self.coeffs[1], [20 * t **3, 12 * t** 2, 6 * t, 2, 0, 0])acc[2] = np.dot(self.coeffs[2], [20 * t **3, 12 * t** 2, 6 * t, 2, 0, 0])return pos, vel, acc
def calculate_trajectory_time(distance, max_vel, max_acc):"""根據論文中的方法計算軌跡總時間短距離: 僅加速階段長距離: 加速→勻速→減速階段"""# 計算臨界距離:達到最大速度所需的距離critical_distance = (max_vel ** 2) / max_accif distance < critical_distance:# 短距離:僅加速即可到達目標return np.sqrt(distance / max_acc) * 2  # 修正系數使結果更合理else:# 長距離:加速→勻速→減速time_acc_dec = 2 * max_vel / max_acc  # 加速和減速時間之和time_constant = (distance - critical_distance) / max_vel  # 勻速時間return time_acc_dec + time_constant
def find_optimal_ts_and_sample(traj, ctrl_pt_dist, min_point_num=7):"""動態調整采樣時間步ts,生成滿足條件的采樣點集參數:traj: PolynomialTraj對象ctrl_pt_dist: B樣條控制點基準間距(m)min_point_num: 最小采樣點數量返回:optimal_ts: 最優采樣時間步(s)point_set: 采樣點集(Nx3)sample_times: 采樣時刻(s)"""# 初始ts猜測(先放大1.5倍,后續逐步縮小)initial_ts_guess = traj.total_time / 5  # 初始預估5個點optimal_ts = initial_ts_guess * 1.5  # 預放大flag_too_far = Truepoint_set = []sample_times = []# 循環調整ts直到滿足條件while flag_too_far or len(point_set) < min_point_num:optimal_ts /= 1.5  # 每次縮小1.5倍point_set.clear()sample_times.clear()flag_too_far = False# 起點初始化last_pt = traj.evaluate(0.0)point_set.append(last_pt)sample_times.append(0.0)# 按當前ts采樣t = optimal_tswhile t < traj.total_time + 1e-6:  # 允許微小誤差,避免漏采終點current_pt = traj.evaluate(t)# 檢查相鄰點距離是否超限dist_between = np.linalg.norm(current_pt - last_pt)if dist_between > ctrl_pt_dist * 1.5:flag_too_far = Truebreak  # 超限,退出當前采樣point_set.append(current_pt)sample_times.append(t)last_pt = current_ptt += optimal_ts# 確保最后一個點是軌跡終點final_pt = traj.evaluate(traj.total_time)if np.linalg.norm(final_pt - point_set[-1]) > 1e-3:point_set.append(final_pt)sample_times.append(traj.total_time)# 轉換為numpy數組point_set = np.array(point_set)sample_times = np.array(sample_times)return optimal_ts, point_set, sample_times# *********************************** 動態尋找 ts 并生成采樣點 ************************************
def visualize_trajectory(traj, point_set, sample_times, optimal_ts, ctrl_pt_dist):"""可視化軌跡和采樣點"""# 生成高密度軌跡點用于繪制連續曲線dense_times = np.linspace(0, traj.total_time, 1000)dense_points = np.array([traj.evaluate(t) for t in dense_times])# 創建3D圖形fig = plt.figure(figsize=(15, 10))# 3D軌跡圖ax3d = fig.add_subplot(111, projection='3d')ax3d.plot(dense_points[:, 0], dense_points[:, 1], dense_points[:, 2],'gray', linewidth=1, label='traj')ax3d.scatter(point_set[:, 0], point_set[:, 1], point_set[:, 2],c='red', s=50, zorder=5, label='sample')ax3d.scatter(point_set[0, 0], point_set[0, 1], point_set[0, 2],c='green', s=100, marker='o', label='start')ax3d.scatter(point_set[-1, 0], point_set[-1, 1], point_set[-1, 2],c='blue', s=100, marker='*', label='end')ax3d.set_xlabel('X (m)')ax3d.set_ylabel('Y (m)')ax3d.set_zlabel('Z (m)')ax3d.set_title('3D traj')ax3d.legend()plt.tight_layout()plt.show()
def ego_ts_main():# 軌跡參數設置start_pt = np.array([0.0, 0.0, 0.0])  # 起點位置start_vel = np.array([0.1, 0.1, 0.0])  # 起點速度start_acc = np.array([0.0, 0.0, 0.0])  # 起點加速度end_pt = np.array([8.0, 4.0, 2.0])  # 終點位置end_vel = np.array([0.1, 0.1, 0.0])  # 終點速度end_acc = np.array([0.0, 0.0, 0.0])  # 終點加速度max_vel = 2.0  # 最大速度max_acc = 1.0  # 最大加速度ctrl_pt_dist = 0.8  # 控制點基準間距# 計算軌跡距離和時間distance = np.linalg.norm(end_pt - start_pt)total_time = calculate_trajectory_time(distance, max_vel, max_acc)print(f"軌跡距離: {distance:.2f}m, 計算得到總時間: {total_time:.2f}s")# 生成多項式軌跡traj = PolynomialTraj.one_segment_traj_gen(start_pt, start_vel, start_acc,end_pt, end_vel, end_acc,total_time)# 動態確定最優采樣時間步并采樣optimal_ts, point_set, sample_times = find_optimal_ts_and_sample(traj, ctrl_pt_dist)print(f"最優采樣時間步: {optimal_ts:.4f}s, 采樣點數量: {len(point_set)}")# 可視化結果visualize_trajectory(traj, point_set, sample_times, optimal_ts, ctrl_pt_dist)

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/95462.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/95462.shtml
英文地址,請注明出處:http://en.pswp.cn/web/95462.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

專項智能練習(信息安全防護措施)

3.以下屬于網絡安全威脅的是&#xff08;A &#xff09;。 A.非授權訪問、病毒感染、信息泄露、拒絕網絡服務 B.信息泄露、非授權訪問、病毒感染、硬盤損壞 C.信息篡改、非授權訪問、病毒感染、硬盤損壞 D.網絡異常、非授權訪問、信息篡改、病毒感染 解析本題考查網絡安全威脅。…

ubuntu編譯webrtc庫

一. 前言 本文介紹在 ubuntu 下如何通過 webrtc 源碼編譯出指定版本 webrtc.lib 庫&#xff08;以 m94 版本為例&#xff09;。 二. 編譯步驟 1. 下載depot_tools工具 depot_tools 是 Google 用來管理大型項目代碼&#xff08;例如 WebRTC&#xff09;的工具集&#xff0c;它…

基于ZooKeeper實現分布式鎖(Spring Boot接入)及與Kafka實現的對比分析

在分布式系統中,多節點對共享資源的并發訪問往往會引發數據一致性問題,分布式鎖正是解決這一問題的核心組件。本文將從原理出發,詳細講解基于ZooKeeper實現分布式鎖的完整流程,提供Spring Boot接入的可運行代碼,并深入對比其與Kafka實現分布式鎖的異同點及優缺點,幫助開發…

Shell 三劍客之 awk 命令詳解(理論+實戰)

目錄 一、前言 二、工作流程總覽 三、最常用內置變量 四、命令格式 五、20 個高頻實戰案例 5.1 基礎打印 awk {print "hello"} < /etc/passwd 所有行打印成hello awk {print} test6.txt 打印test6.txt文件 awk {print $1} test6.txt 默認以空格為分割&am…

一個真正跨平臺可用的免費PDF解決方案

在整理資料時&#xff0c;常需將不同格式的文件統一轉為PDF格式&#xff0c;確保排版不亂、便于長期保存和打印 它的功能全面&#xff0c;支持批量操作&#xff0c;使用非常方便&#xff1a;只需把PDF文件拖進界面&#xff0c;選擇目標格式&#xff0c;無論PDF轉換成Word、PDF…

強化微調:以Swift框架進行GRPO多模態模型強化微調為例

一、TL&#xff1b;DR 整體介紹&#xff1a;強化微調RFT的原因、步驟、作用以及常見的rft方式dmeo舉例&#xff1a;以Swift給的Qwen2.5-Math-7B-Instruct為例介紹了整個RFT的流程和代碼細節實際強化微調&#xff1a;以qwen/internVL為例完成一次指令微調并且使用強化學習進一步…

時序數據:使用關系數據庫 vs 時序數據庫存儲的核心區別是什么?

一、時序數據使用關系數據庫 vs 時序數據庫存儲的核心區別 時序數據&#xff08;Time Series Data&#xff09;是指隨時間連續產生的數據&#xff08;如傳感器讀數、服務器指標、交易記錄等&#xff09;&#xff0c;其核心特點是高頻寫入、時間有序、量大且查詢模式集中于時間范…

ansible判斷

ansible判斷 一、判斷運算符 “” “!” “>” “<” “>” “<” “and” “or” “not” is in 每次執行完一個任務&#xff0c;不管成功與失敗&#xff0c;都會將執行的結果進行注冊&#xff0c;可以使用這個注冊的變量來判斷 when&#…

接口設計標準化流程,結合RESTful最佳實踐和實際開發經驗,涵蓋從需求分析到部署的全過程

目錄一、接口設計流程二、需求分析階段1. 功能需求2. 非功能性需求三、接口設計規范四、詳細實現步驟1. 選擇Web框架2. 接口路由設計3. 請求參數定義4. 請求參數驗證5. 業務邏輯分層6. 錯誤處理機制7. 異步任務處理8. 安全策略9. 接口文檔10. 測試策略11. 服務部署11.1 生產環境…

LeetCode 1023.駝峰式匹配

給你一個字符串數組 queries&#xff0c;和一個表示模式的字符串 pattern&#xff0c;請你返回一個布爾數組 answer 。只有在待查項 queries[i] 與模式串 pattern 匹配時&#xff0c; answer[i] 才為 true&#xff0c;否則為 false。 如果可以將 小寫字母 插入模式串 pattern 得…

【IQA技術專題】 無參考自然圖像IQA:NIQE

無參考自然圖像IQA&#xff1a;NIQE&#xff1a;Making a “Completely Blind” Image Quality Analyzer&#xff08;2012 IEEE&#xff09;專題介紹一、研究背景二、NIQE方法2.1 NSS model2.2 Patch Selection2.3 Characterizing Image Patches2.4 Multivariate Gaussian Mode…

變位齒輪:分度圓、節圓與中心距的 “特殊關聯”

接著上回的話題&#xff0c;在標準齒輪中&#xff0c;我們追求的是“節圓與分度圓重合”的理想狀態。但當實際工程提出更苛刻的要求時&#xff0c;比如&#xff1a;需要避免齒輪根切&#xff08;齒數過少時&#xff09;。要配湊一個非標準的中心距。需要大幅提高小齒輪的強度和…

Spring Boot集成Kafka常見業務場景最佳實踐實戰指南

一、基礎集成與核心組件解析 &#xff08;一&#xff09;環境搭建與依賴配置 在 Spring Boot 項目中集成 Kafka&#xff0c;首先需通過 Maven 添加核心依賴&#xff1a; <dependency> <groupId>org.springframework.kafka</groupId> <artifactId>…

黑芝麻智能與云深處科技達成戰略合作,共推具身智能平臺全球市場應用

8月28日&#xff0c;智能汽車計算芯片引領者黑芝麻智能與具身智能創新技術與行業應用引領者云深處科技達成戰略合作。雙方將圍繞具身智能控制平臺開發、行業智能解決方案共建與國際市場拓展三大方向展開深度合作&#xff0c;攜手推進高性能機器人在多行業場景的規模化落地與應用…

AI零售創業公司:零眸智能

零眸智能公司分析 引言 “這次融資與合作&#xff0c;讓我們的全球化節奏更堅實也更有確定性。秉持‘讓熱愛與科技成就無限可能’&#xff0c;我們堅持真誠合作、長期主義與價值共享&#xff0c;把行業垂直AI能力按里程碑推進并沉淀為可復制的標準。” —— 零眸智能CEO樊凌云①…

學習插入排序+希爾排序并使用java寫代碼

目錄 插入排序 例子時間復雜度java代碼 希爾排序&#xff08;縮小增量排序&#xff09; 例子時間復雜度java代碼 相關文章 學習數據結構理論算法時間復雜度學習有序二叉樹平衡二叉樹紅黑樹學習冒泡排序選擇排序并使用java寫代碼學習插入排序希爾排序并使用java寫代碼學習堆…

win10虛擬機報錯打不開和ubuntu空間不足

ubuntu主機安裝的win10虛擬機報錯如下&#xff0c;導致虛擬機無法打開解決辦法 如上圖&#xff0c;找到ubuntu主機home目錄中win10的路徑&#xff0c;將紅色框的文件刪除&#xff0c;然后將綠色框中的文件.prev后綴去掉&#xff0c;如下圖所示。重新打開虛擬機就可以了 ubuntu空…

指紋手機技術:破解亞馬遜多賬號運營痛點的底層邏輯與實踐

在亞馬遜平臺運營中&#xff0c;賬號關聯、行為異常、網絡不合規是賣家繞不開的三大核心風險。隨著亞馬遜反作弊系統&#xff08;如 A9 算法&#xff09;對設備指紋、操作軌跡、網絡特征的識別精度持續提升&#xff0c;傳統 “普通手機 VPN” 的多賬號運營模式已頻繁觸發風控&…

《UE5_C++多人TPS完整教程》學習筆記46 ——《P47 蹲伏行走(Crouching Walking)》

本文為B站系列教學視頻 《UE5_C多人TPS完整教程》 —— 《P47 蹲伏行走&#xff08;Crouching Walking&#xff09;》 的學習筆記&#xff0c;該系列教學視頻為計算機工程師、程序員、游戲開發者、作家&#xff08;Engineer, Programmer, Game Developer, Author&#xff09; S…

TiDB v8.5.3 單機集群部署指南

前言 最近在做 TiDB 的恢復演練&#xff0c;需要在單臺 Linux 服務器上部署一套 TiDB 最小的完整拓撲的集群&#xff0c;本文記錄一下安裝過程。 環境準備 開始部署 TiDB 集群前&#xff0c;準備一臺部署主機&#xff0c;確保其軟件滿足需求&#xff1a; 推薦安裝 CentOS 7…