LingxinMeng 7 ヶ月 前
コミット
b9d43451b1
1 ファイル変更135 行追加15 行削除
  1. 135 15
      src/python3/pjibot_outdoor/jiqiren_outdoor.py

+ 135 - 15
src/python3/pjibot_outdoor/jiqiren_outdoor.py

@@ -5,6 +5,9 @@ import pandas as pd
 import subprocess
 import time
 import multiprocessing
+from pyproj import CRS, Transformer
+from scipy.spatial.transform import Rotation as R
+from scipy.signal import savgol_filter
 import xml.etree.ElementTree as ET
 import sys
 # 导入进程模块
@@ -68,6 +71,32 @@ class Batchrun:
         posdata_ego.rename(columns={'X': 'pos_x'}, inplace=True)
         posdata_ego.rename(columns={'Y': 'pos_y'}, inplace=True)
 
+        def trans_pos(posdata):
+            theta = 1.4
+            input_lat1 = 39.7286896
+            input_lon1 = 116.4885025
+            transformer = Transformer.from_crs("epsg:4326", "epsg:32650")
+            utm50n_x2 = 456256.260152
+            utm50n_y2 = 4397809.886833
+            utm50n_x1, utm50n_y1 = transformer.transform(input_lat1, input_lon1)
+            translation = np.array([utm50n_x1 - utm50n_x2, utm50n_y1 - utm50n_y2])
+            rotation_matrix = R.from_euler('z', theta).as_matrix()
+            # 提取原始坐标
+            original_positions = posdata[['pos_x', 'pos_y']].values
+            # 应用旋转和平移
+            rotated_positions =original_positions @ rotation_matrix[:2,:2].T # 只应用 2D 旋转
+            rotated_positions += translation
+            # 更新 posdata
+            posdata['pos_x'] = rotated_positions[:, 0]
+            posdata['pos_y'] = rotated_positions[:, 1]
+            posdata['HeadingAngle'] += theta
+            return posdata
+
+        posdata_obs = trans_pos(posdata_obs)
+        posdata_ego = trans_pos(posdata_ego)
+        posdata_obs['simtime'] = posdata_obs['simtime'].round(1)
+        posdata_ego['simtime'] = posdata_ego['simtime'].round(1)
+
         # 对障碍物数据进行处理
         def filter_rows(group):
             # 首先对x进行排序
@@ -78,6 +107,21 @@ class Batchrun:
             group = group[diffs >= 0.2]
             return group
 
+        def interpolate_missing_values(df):
+            # 1. 生成一个完整的以0.1秒为间隔的simtime
+            new_simtime = np.arange(df['simtime'].min(), df['simtime'].max() + 0.1, 0.1)
+
+            # 2. 创建新的DataFrame,并与原始DataFrame对齐
+            new_df = pd.DataFrame(new_simtime, columns=['simtime'])
+
+            # 3. 将原始DataFrame与新simtime进行合并
+            new_df = pd.merge(new_df, df, on='simtime', how='left')
+
+            # 4. 对列进行插值(线性插值)
+            new_df = new_df.interpolate(method='linear')
+
+            return new_df
+
         posdata_obs = posdata_obs.groupby(['simtime', 'pos_y'], group_keys=False).apply(filter_rows)
         posdata_obs.reset_index(drop=True, inplace=True)
 
@@ -85,6 +129,7 @@ class Batchrun:
         # posdata_ego['Time'] = posdata_ego['Time'] - start_time_ego
         # posdata_ego['Time'] = (posdata_ego['Time'] - (posdata_ego['Time'] % 100)) / 1000
         posdata_ego = posdata_ego.drop_duplicates(subset='simtime', keep='first')
+        posdata_ego = interpolate_missing_values(posdata_ego)
         posdata_ego['Type'] = 2
         posdata_ego['ID'] = -1
         # posdata_ego['pos_x'] = posdata_ego['pos_x'] - 88.96626
@@ -159,6 +204,66 @@ class Batchrun:
             pos_obs['ID'] != -1, ['simtime', 'ID', 'pos_x', 'pos_y', 'HeadingAngle', 'AbsVel', 'altitude', 'Type']]
         pos_obs = pos_obs.reset_index(drop=True)
 
+        # def calculate_heading_angle(group):
+        #     start_idx = 0
+        #     length = len(group)
+        #     prev_heading_angle = None  # 用于存储上一个计算的航向角
+        #
+        #     while start_idx < length:
+        #         start_pos_x, start_pos_y = group.iloc[start_idx]['pos_x'], group.iloc[start_idx]['pos_y']
+        #
+        #         # 找到与当前帧距离超过1米的帧
+        #         for i in range(start_idx + 1, length):
+        #             current_pos_x, current_pos_y = group.iloc[i]['pos_x'], group.iloc[i]['pos_y']
+        #             distance = np.sqrt((current_pos_x - start_pos_x) ** 2 + (current_pos_y - start_pos_y) ** 2)
+        #
+        #             if distance >= 1:
+        #                 # 计算航向角
+        #                 heading_angle = np.degrees(np.arctan2(current_pos_y - start_pos_y, current_pos_x - start_pos_x))
+        #
+        #                 # 检查航向角与前一个航向角的差值
+        #                 if prev_heading_angle is not None:
+        #                     angle_diff = np.abs(heading_angle - prev_heading_angle)
+        #                     if angle_diff > 180:
+        #                         angle_diff = 360 - angle_diff
+        #
+        #                     if angle_diff > 20:
+        #                         # 如果航向角差值大于25度,跳过当前点
+        #                         continue
+        #
+        #                 # 将 start_idx 到 i 之间的航向角设置为 heading_angle
+        #                 group.iloc[start_idx:i, group.columns.get_loc('HeadingAngle')] = heading_angle
+        #                 prev_heading_angle = heading_angle
+        #                 start_idx = i
+        #                 break
+        #         else:
+        #             # 如果没有找到超过1米的距离,使用最后一帧的数据计算航向角
+        #             last_pos_x, last_pos_y = group.iloc[-1]['pos_x'], group.iloc[-1]['pos_y']
+        #             heading_angle = np.degrees(np.arctan2(last_pos_y - start_pos_y, last_pos_x - start_pos_x))
+        #
+        #             # 检查航向角与前一个航向角的差值
+        #             if prev_heading_angle is not None:
+        #                 angle_diff = np.abs(heading_angle - prev_heading_angle)
+        #                 if angle_diff > 180:
+        #                     angle_diff = 360 - angle_diff
+        #
+        #                 if angle_diff <= 20:
+        #                     group.iloc[start_idx:length - 1, group.columns.get_loc('HeadingAngle')] = heading_angle
+        #                 else:
+        #                     # 如果差值大于25度,跳过最后的点
+        #                     group.iloc[start_idx:length - 1, group.columns.get_loc('HeadingAngle')] = prev_heading_angle
+        #             else:
+        #                 group.iloc[start_idx:length - 1, group.columns.get_loc('HeadingAngle')] = heading_angle
+        #
+        #             break
+        #
+        #     # 确保最后一行的航向角等于倒数第二行
+        #     if length > 1:
+        #         group.iloc[-1, group.columns.get_loc('HeadingAngle')] = group.iloc[-2]['HeadingAngle']
+        #
+        #     return group
+
+
         def calculate_heading_angle(group):
             start_idx = 0
             length = len(group)
@@ -172,7 +277,7 @@ class Batchrun:
                     current_pos_x, current_pos_y = group.iloc[i]['pos_x'], group.iloc[i]['pos_y']
                     distance = np.sqrt((current_pos_x - start_pos_x) ** 2 + (current_pos_y - start_pos_y) ** 2)
 
-                    if distance >= 1:
+                    if distance >= 0.5:
                         # 计算航向角
                         heading_angle = np.degrees(np.arctan2(current_pos_y - start_pos_y, current_pos_x - start_pos_x))
 
@@ -180,10 +285,14 @@ class Batchrun:
                         if prev_heading_angle is not None:
                             angle_diff = np.abs(heading_angle - prev_heading_angle)
                             if angle_diff > 180:
+                                if heading_angle < 0:
+                                    heading_angle += 360
+                                else:
+                                    heading_angle -= 360
                                 angle_diff = 360 - angle_diff
 
-                            if angle_diff > 20:
-                                # 如果航向角差值大于25度,跳过当前点
+                            if angle_diff > 30:
+                                # 如果航向角差值大于30度,跳过当前点
                                 continue
 
                         # 将 start_idx 到 i 之间的航向角设置为 heading_angle
@@ -200,15 +309,19 @@ class Batchrun:
                     if prev_heading_angle is not None:
                         angle_diff = np.abs(heading_angle - prev_heading_angle)
                         if angle_diff > 180:
+                            if heading_angle < 0:
+                                heading_angle += angle_diff
+                            else:
+                                heading_angle -= angle_diff
                             angle_diff = 360 - angle_diff
 
-                        if angle_diff <= 20:
+                        if angle_diff <= 30:
                             group.iloc[start_idx:length - 1, group.columns.get_loc('HeadingAngle')] = heading_angle
                         else:
-                            # 如果差值大于25度,跳过最后的点
+                            # 如果差值大于20度,跳过最后的点
                             group.iloc[start_idx:length - 1, group.columns.get_loc('HeadingAngle')] = prev_heading_angle
                     else:
-                        group.iloc[start_idx:length - 1, group.columns.get_loc('HeadingAngle')] = heading_angle
+                        group.iloc[start_idx:length - 1, group.columns.get_loc('HeadingAngle')] = group.iloc[0]['HeadingAngle']
 
                     break
 
@@ -218,17 +331,23 @@ class Batchrun:
 
             return group
 
+        def apply_savgol(row, window_size, poly_order):
+            if len(row) < window_size:
+                return row
+            else:
+                return savgol_filter(row, window_size, poly_order)
+
         # 应用到分组数据
         pos_obs = pos_obs.groupby('ID').apply(calculate_heading_angle).reset_index(drop=True)
-        while (pos_obs['HeadingAngle'] < 0).any():
-            # 将负角度值转换为正值
-            pos_obs['HeadingAngle'] = pos_obs['HeadingAngle'].apply(lambda x: x + 360 if x < 0 else x) 
-
+        # while (pos_obs['HeadingAngle'] < 0).any():
+        #     # 将负角度值转换为正值
+        #     pos_obs['HeadingAngle'] = pos_obs['HeadingAngle'].apply(lambda x: x + 360 if x < 0 else x)
+        pos_obs['HeadingAngle'] = pos_obs.groupby('ID')['HeadingAngle'].transform(lambda x: apply_savgol(x, 45, 2))
         groups = pos_obs.groupby('ID')
         object_points = []
         for key, value in groups:
-            # if len(value) < 5:
-            #     continue
+            if len(value) < 5:
+                continue
             # value = smooth_1(value)
             object_points.append(
                 Scenario.getXoscPosition(value, 'simtime', 'pos_x', 'pos_y', 'HeadingAngle', 'altitude', 'Type', 0, 0, 0,
@@ -324,9 +443,10 @@ class Batchrun:
 
 
 if __name__ == "__main__":
-    # rootPath = "/media/hancheng/Simulation5/pujin/pujin_outdoor/pjioutrobot_2024-08-21-15-12-04"  # 跟车
-    rootPath = sys.argv[1]
-    vehicle_type = sys.argv[2]   # 0 配送 1 巡检
+    rootPath = "/media/hancheng/Simulation5/pujin/pujin_outdoor/10_23"  # 跟车
+    # rootPath = sys.argv[1]
+    # vehicle_type = sys.argv[2]
+    vehicle_type = "0"
     # 生成场景
     a = Batchrun(rootPath, "pos_pji.csv")
     a.batchRun(rootPath, vehicle_type)  # 0为占位参数