news 2026/9/29 22:42:02

python的先进制造技术工业场景模拟第二篇:导入机器人点位坐标数据集,筛选超出安全工作区间的坐标点,输出异常点位数量。

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
python的先进制造技术工业场景模拟第二篇:导入机器人点位坐标数据集,筛选超出安全工作区间的坐标点,输出异常点位数量。

周二下午两点,机器人工作站。

"又撞了。"维修班长老赵蹲在发那科机器人底座旁边,手指着末端执行器上的一道新鲜刮痕,"今早自动运行时,第六轴带着抓手直接怼到了夹具底座上。限位报警,停机四十分钟。"

工艺工程师小周把笔记本电脑转过来:"我查了昨天导入的点位数据集——从 CAD 离线编程软件导出的 500 个目标点,CSV 格式。我肉眼翻了前几十条,没看出问题,就直接下发了。结果……"

"500 个点你肉眼翻?"我拉开椅子坐下,"你有没有先写个程序,把每个点的坐标跟机器人的安全工作区间比对一下?超出去的标红、计数、报警?"

小周愣了一下:"那个……我都是靠离线编程软件自带的仿真检查。但这次夹具改了位置,安全工作区间变了,软件里还是旧参数。"

"这就是问题。"我打开 VS Code,"离线编程软件的仿真环境是理想化的。实际现场,夹具改了、底座垫高了、甚至机器人安装面不平——这些变动不会自动同步到软件里。你需要在部署前,用 Python 把点位数据集拉进来,跟现场实际的安全工作区间做一遍比对,筛出超限点,数清楚有多少个,具体是哪些。"

我敲了几行代码:

import pandas as pd

import numpy as np

# 读取点位数据集

df = pd.read_csv("robot_points.csv")

# 安全工作区间(现场实测)

workspace = {"x_min": -800, "x_max": 800,

"y_min": -600, "y_max": 600,

"z_min": 100, "z_max": 1200}

# 筛选超限点

mask = (

(df["x"] < workspace["x_min"]) | (df["x"] > workspace["x_max"]) |

(df["y"] < workspace["y_min"]) | (df["y"] > workspace["y_max"]) |

(df["z"] < workspace["z_min"]) | (df["z"] > workspace["z_max"])

)

outliers = df[mask]

print(f"异常点位数量: {len(outliers)}")

# 异常点位数量: 23

"这只是核心逻辑,"我说,"完整版会用 OOP 封装:一个类管点位数据加载,一个类管安全工作区间定义和校验,一个类管异常筛选和统计,一个类管可视化——把异常点在 3D 散点图上标红。数据自包含,用 numpy 合成一份点位 CSV,读者下载就能跑。"

老赵站起身:"所以你这东西,本质上就是给机器人点位做'体检'——500 个体检完,23 个不合格,告诉你具体是谁、超了哪个方向。"

"对。而且不用停机、不用冒碰撞风险,在电脑里跑 3 秒钟就出结果。"

一、实际应用场景(真实痛点)

场景设定:工业机器人工作站,从离线编程软件导出目标点位数据集(CSV 格式,含 X/Y/Z 坐标),需要与实际现场的安全工作区间比对,筛出超限点并统计数量。现场常见痛点:离线编程软件中的工作区间参数与实际现场不同步(夹具改动、机器人基座偏移等),直接下发未校验的点位数据可能导致机器人碰撞、限位报警、停机损失。

现场原话(叙事化):

"我不是没有检查,"小周说,"离线软件里仿真过了,轨迹是通的。但我忘了夹具上周改了位置——底座加高了 50mm,软件里还是旧尺寸。结果机器人按旧坐标走,第六轴直接撞上去。"

"你需要的是部署前的最后一道防线,"我说,"不管离线软件怎么仿的,点位数据到现场之后,用 Python 跟实际安全工作区间比一遍。超出去的,一个都别放过。"

核心矛盾:"离线编程的理想化点位"与"现场实际物理约束"之间的不匹配。需要一个"机器人点位安全区间校验程序",用

"pandas" 导入点位数据集,用

"numpy" 做向量化区间校验,用

"matplotlib" 做 3D 可视化标注,快速输出异常点位数量和明细。

二、痛点分析(映射到滨州职业学院《先进制造技术》课程模型)

《先进制造技术》模块 本篇痛点对应

工业机器人技术基础:机器人运动学与工作空间 安全工作区间校验:机器人末端执行器必须在限定空间内运动,超限点位是碰撞风险的直接来源。

先进制造技术基础:先进制造系统安全规范 安全边界定义:任何自动化设备都需明确安全作业范围,点位校验是安全规范的数字落地。

智能制造与数字孪生:虚拟-现实映射一致性 从离线仿真到现场部署的"最后一公里":虚拟环境中的点位必须校验与物理环境的一致性。

柔性制造系统FMS与先进生产管理:生产安全管理 防错机制:在自动生产前通过软件手段拦截异常,减少非计划停机。

一句话总结:我们需要构建一个"机器人点位安全区间校验程序",用

"pandas" 导入点位 CSV,用

"numpy" 向量化筛选超限坐标点,用

"matplotlib" 绘制 3D 散点图标注异常,输出异常点位数量和明细,为机器人工作站提供部署前的安全防线。

三、核心逻辑讲解(大白话)

3.1 问题本质:把点位校验想象成"快递柜格子"

把机器人的安全工作区间想象成"小区里的快递柜":

* 点位数据集 = 你要放的 500 个包裹:每个包裹有长、宽、高三个尺寸(对应 X、Y、Z 坐标)。

* 安全工作区间 = 快递柜的格子大小:格子有最大长宽高,包裹放进去不能冒出来。

* 超限点 = 放不进去的包裹:太大了,塞不进格子,硬塞就会卡住(碰撞)。

* 校验程序 = 自动量尺寸:不用你一个一个量,程序 3 秒钟把 500 个包裹全量完,告诉你哪些放不进去、有几个。

工业应用:

* pandas 导入:

"read_csv()" 一行读取 500 个点的坐标。

* numpy 向量化校验:不用 for 循环逐个比,用布尔索引一次性筛出所有超限点。

* matplotlib 3D 图:把正常点画成蓝色,超限点画成红色,一眼看出哪些点跑到了安全框外面。

3.2 业务逻辑 → 代码映射

定义点位数据模型

│

▼ PointCloudLoader (pandas)

导入点位 CSV:

pd.read_csv("robot_points.csv")

解析 X, Y, Z 列

│

▼ WorkspaceValidator (numpy)

定义安全工作区间:

x ∈ [-800, 800], y ∈ [-600, 600], z ∈ [100, 1200]

向量化校验:

mask = (X < x_min) | (X > x_max) | ...

筛选超限点

统计异常数量

│

▼ OutlierReporter

输出异常明细:

异常点位的索引、坐标、超限方向

异常数量汇总

│

▼ Visualizer (matplotlib)

3D 可视化:

1. 正常点位(蓝色散点)

2. 异常点位(红色散点,放大标记)

3. 安全工作区间线框(半透明立方体)

│

▼ SyntheticDataGenerator (numpy)

合成数据生成:

用 numpy 在安全工作区间内生成正常点

在区间外生成超限点

确保数据自包含、可复现

3.3 为什么用向量化而不是 for 循环?

* 问题:500 个点用 for 循环逐个

"if" 判断,代码啰嗦,速度慢。

* 处理策略:

"numpy" 布尔索引一次性对所有点做逻辑运算,速度提升 10 倍以上,代码只有一行。

* 工程合理性:工业现场动辄上万点位(喷涂、焊接轨迹),向量化是必备技能。

3.4 校验前后对比

维度 人工/离线软件检查 Python 程序校验

检查速度 500 个点需数十分钟 3 秒完成

准确性 依赖人眼,易遗漏 100% 覆盖

现场同步 需手动更新软件参数 直接输入现场实测区间

输出结果 "看起来没问题" 异常点 23 个,明细列表

四、OOP 代码实现

4.1 项目结构

robot_workspace_check/

├── robot_workspace_check/

│ ├── __init__.py

│ ├── point_loader.py # 点位数据加载

│ ├── workspace_validator.py # 安全工作区间校验

│ ├── outlier_reporter.py # 异常报告生成

│ ├── visualizer.py # 3D 可视化

│ └── synthetic_data.py # 合成数据生成

├── tests/

│ ├── __init__.py

│ └── test_workspace_check.py # 单元测试

├── results/

│ ├── workspace_3d.png # 3D 散点图

│ ├── outlier_summary.csv # 异常点位明细

│ └── check_report.txt # 校验报告

└── run_check.py # 主程序入口

4.2 核心源码

<details>

<summary></summary>

"""机器人点位数据加载器"""

import pandas as pd

from pathlib import Path

from typing import Optional, List

class PointCloudLoader:

"""

点位数据集加载器

支持从 CSV 文件读取机器人目标点位坐标。

"""

def __init__(self, filepath: str, encoding: str = "utf-8"):

self.filepath = Path(filepath)

self.encoding = encoding

self._raw_df: Optional[pd.DataFrame] = None

def load(self,

x_col: str = "x",

y_col: str = "y",

z_col: str = "z") -> pd.DataFrame:

"""

加载点位 CSV

Parameters

----------

x_col, y_col, z_col : str

坐标列名

Returns

-------

pd.DataFrame

包含 X, Y, Z 列的数据框

"""

if not self.filepath.exists():

raise FileNotFoundError(f"文件不存在: {self.filepath}")

self._raw_df = pd.read_csv(self.filepath, encoding=self.encoding)

# 列名标准化

col_map = {}

for target, aliases in [

(x_col, ["X", "x_coord", "pos_x", "PX"]),

(y_col, ["Y", "y_coord", "pos_y", "PY"]),

(z_col, ["Z", "z_coord", "pos_z", "PZ"]),

]:

if target not in self._raw_df.columns:

for alias in aliases:

if alias in self._raw_df.columns:

col_map[alias] = target

break

if col_map:

self._raw_df = self._raw_df.rename(columns=col_map)

required = [x_col, y_col, z_col]

missing = [c for c in required if c not in self._raw_df.columns]

if missing:

raise ValueError(f"缺少必要的坐标列: {missing}")

return self._raw_df[required].copy()

def get_raw_data(self) -> Optional[pd.DataFrame]:

return self._raw_df.copy() if self._raw_df is not None else None

</details>

<details>

<summary></summary>

"""安全工作区间校验器"""

import numpy as np

import pandas as pd

from dataclasses import dataclass

from typing import Dict, Optional

@dataclass

class WorkspaceBounds:

"""安全工作区间边界"""

x_min: float = -800.0

x_max: float = 800.0

y_min: float = -600.0

y_max: float = 600.0

z_min: float = 100.0

z_max: float = 1200.0

def __post_init__(self):

if self.x_min >= self.x_max:

raise ValueError("x_min 必须小于 x_max")

if self.y_min >= self.y_max:

raise ValueError("y_min 必须小于 y_max")

if self.z_min >= self.z_max:

raise ValueError("z_min 必须小于 z_max")

class WorkspaceValidator:

"""

机器人安全工作区间校验器

使用 numpy 向量化运算,快速筛选超限点位。

"""

def __init__(self, bounds: Optional[WorkspaceBounds] = None):

self.bounds = bounds or WorkspaceBounds()

def validate(self, df: pd.DataFrame,

x_col: str = "x",

y_col: str = "y",

z_col: str = "z") -> pd.DataFrame:

"""

校验所有点位

Parameters

----------

df : pd.DataFrame

点位数据

x_col, y_col, z_col : str

坐标列名

Returns

-------

pd.DataFrame

包含校验结果的原始数据(新增 is_outlier 列)

"""

coords = df[[x_col, y_col, z_col]].values.astype(float)

b = self.bounds

# 向量化区间校验

outlier_mask = (

(coords[:, 0] < b.x_min) | (coords[:, 0] > b.x_max) |

(coords[:, 1] < b.y_min) | (coords[:, 1] > b.y_max) |

(coords[:, 2] < b.z_min) | (coords[:, 2] > b.z_max)

)

result = df.copy()

result["is_outlier"] = outlier_mask

result["outlier_reason"] = result.apply(

lambda row: self._get_reason(

row[x_col], row[y_col], row[z_col]

),

axis=1

)

return result

def _get_reason(self, x: float, y: float, z: float) -> str:

"""获取超限原因"""

reasons = []

b = self.bounds

if x < b.x_min:

reasons.append(f"X={x:.1f}<{b.x_min}")

elif x > b.x_max:

reasons.append(f"X={x:.1f}>{b.x_max}")

if y < b.y_min:

reasons.append(f"Y={y:.1f}<{b.y_min}")

elif y > b.y_max:

reasons.append(f"Y={y:.1f}>{b.y_max}")

if z < b.z_min:

reasons.append(f"Z={z:.1f}<{b.z_min}")

elif z > b.z_max:

reasons.append(f"Z={z:.1f}>{b.z_max}")

return "; ".join(reasons) if reasons else "OK"

def count_outliers(self, df: pd.DataFrame) -> int:

"""统计异常点位数量"""

if "is_outlier" not in df.columns:

raise ValueError("请先调用 validate() 进行校验")

return int(df["is_outlier"].sum())

def get_outliers(self, df: pd.DataFrame) -> pd.DataFrame:

"""获取异常点位明细"""

if "is_outlier" not in df.columns:

raise ValueError("请先调用 validate() 进行校验")

return df[df["is_outlier"]].copy()

</details>

<details>

<summary></summary>

"""异常报告生成器"""

import pandas as pd

from pathlib import Path

from typing import Dict

class OutlierReporter:

"""异常点位报告生成器"""

def __init__(self, output_dir: str = "results"):

self.output_dir = Path(output_dir)

self.output_dir.mkdir(exist_ok=True)

def generate_summary(self, df: pd.DataFrame,

total_count: int) -> Dict:

"""

生成异常汇总

Parameters

----------

df : pd.DataFrame

校验后的数据(含 is_outlier 列)

total_count : int

总点位数

Returns

-------

dict

汇总信息

"""

outlier_df = df[df["is_outlier"]]

outlier_count = len(outlier_df)

ratio = outlier_count / total_count * 100 if total_count > 0 else 0

summary = {

"total_points": total_count,

"outlier_count": outlier_count,

"outlier_ratio_percent": ratio,

"normal_count": total_count - outlier_count,

}

return summary

def save_outlier_details(self, df: pd.DataFrame,

filepath: str = "outlier_summary.csv") -> None:

"""保存异常点位明细到 CSV"""

outlier_df = df[df["is_outlier"]]

output_path = self.output_dir / filepath

outlier_df.to_csv(output_path, index=False, encoding="utf-8")

def print_report(self, summary: Dict) -> None:

"""打印文本报告"""

lines = [

"=" * 60,

"机器人点位安全区间校验报告",

"=" * 60,

f"\n总点位数: {summary['total_points']}",

f"异常点位数: {summary['outlier_count']}",

f"异常比例: {summary['outlier_ratio_percent']:.1f}%",

f"正常点位数: {summary['normal_count']}",

"\n" + "=" * 60,

]

report = "\n".join(lines)

print(report)

report_path = self.output_dir / "check_report.txt"

with open(report_path, "w", encoding="utf-8") as f:

f.write(report)

</details>

<details>

<summary></summary>

"""3D 可视化器"""

import numpy as np

import pandas as pd

import matplotlib.pyplot as plt

from mpl_toolkits.mplot3d import Axes3D

from pathlib import Path

from typing import Optional

plt.rcParams["font.sans-serif"] = ["SimHei", "DejaVu Sans"]

plt.rcParams["axes.unicode_minus"] = False

class Visualizer:

"""机器人工作区间 3D 可视化"""

def __init__(self, results_dir: str = "results"):

self.results_dir = Path(results_dir)

self.results_dir.mkdir(exist_ok=True)

def plot_workspace_3d(self, df: pd.DataFrame,

bounds,

x_col: str = "x",

y_col: str = "y",

z_col: str = "z",

title: str = "机器人点位安全区间校验") -> None:

"""

绘制 3D 散点图

Parameters

----------

df : pd.DataFrame

校验后的数据(含 is_outlier 列)

bounds : WorkspaceBounds

安全工作区间

x_col, y_col, z_col : str

坐标列名

title : str

图表标题

"""

fig = plt.figure(figsize=(10, 8))

ax = fig.add_subplot(111, projection="3d")

# 正常点

normal = df[~df["is_outlier"]]

ax.scatter(normal[x_col], normal[y_col], normal[z_col],

c="#3498DB", s=15, alpha=0.6, label="正常点位")

# 异常点

outliers = df[df["is_outlier"]]

if len(outliers) > 0:

ax.scatter(outliers[x_col], outliers[y_col], outliers[z_col],

c="#E74C3C", s=40, marker="^", zorder=5,

label=f"异常点位 ({len(outliers)}个)")

# 安全区间线框(半透明立方体)

self._draw_workspace_cube(ax, bounds)

ax.set_xlabel("X (mm)")

ax.set_ylabel("Y (mm)")

ax.set_zlabel("Z (mm)")

ax.set_title(title, fontsize=13, fontweight="bold")

ax.legend(fontsize=9)

plt.tight_layout()

plt.savefig(self.results_dir / "workspace_3d.png",

dpi=150, bbox_inches="tight")

plt.close()

def _draw_workspace_cube(self, ax, bounds):

"""绘制安全区间线框"""

x_edges = [bounds.x_min, bounds.x_max]

y_edges = [bounds.y_min, bounds.y_max]

z_edges = [bounds.z_min, bounds.z_max]

# 立方体的 12 条边

edges = [

# 底面

([x_edges[0], x_edges[1]], [y_edges[0], y_edges[0]], [z_edges[0], z_edges[0]]),

([x_edges[1], x_edges[1]], [y_edges[0], y_edges[1]], [z_edges[0], z_edges[0]]),

([x_edges[1], x_edges[0]], [y_edges[1], y_edges[1]], [z_edges[0], z_edges[0]]),

([x_edges[0], x_edges[0]], [y_edges[1], y_edges[0]], [z_edges[0], z_edges[0]]),

# 顶面

([x_edges[0], x_edges[1]], [y_edges[0], y_edges[0]], [z_edges[1], z_edges[1]]),

([x_edges[1], x_edges[1]], [y_edges[0], y_edges[1]], [z_edges[1], z_edges[1]]),

([x_edges[1], x_edges[0]], [y_edges[1], y_edges[1]], [z_edges[1], z_edges[1]]),

([x_edges[0], x_edges[0]], [y_edges[1], y_edges[0]], [z_edges[1], z_edges[1]]),

# 侧面竖线

([x_edges[0], x_edges[0]], [y_edges[0], y_edges[0]], [z_edges[0], z_edges[1]]),

([x_edges[1], x_edges[1]], [y_edges[0], y_edges[0]], [z_edges[0], z_edges[1]]),

([x_edges[1], x_edges[1]], [y_edges[1], y_edges[1]], [z_edges[0], z_edges[1]]),

([x_edges[0], x_edges[0]], [y_edges[1], y_edges[1]], [z_edges[0], z_edges[1]]),

]

for x, y, z in edges:

ax.plot(x, y, z, color="#2C3E50", linewidth=1.0,

alpha=0.4, linestyle="--")

</details>

<details>

<summary></summary>

"""合成数据生成器"""

import numpy as np

import pandas as pd

from pathlib import Path

from typing import Optional, Tuple

class SyntheticDataGenerator:

"""

合成机器人点位数据生成器

生成包含正常点和安全区间外异常点的模拟数据集。

"""

def __init__(self, rng: Optional[np.random.RandomState] = None):

self.rng = rng or np.random.RandomState(42)

def generate(self,

n_points: int = 500,

bounds: Optional[Tuple] = None,

outlier_ratio: float = 0.05,

output_path: str = "robot_points.csv") -> pd.DataFrame:

"""

生成合成点位数据

Parameters

----------

n_points : int

总点位数

bounds : tuple, optional

(x_min, x_max, y_min, y_max, z_min, z_max)

outlier_ratio : float

异常点比例

output_path : str

输出 CSV 路径

Returns

-------

pd.DataFrame

"""

if bounds is None:

bounds = (-800, 800, -600, 600, 100, 1200)

x_min, x_max, y_min, y_max, z_min, z_max = bounds

n_outliers = int(n_points * outlier_ratio)

n_normal = n_points - n_outliers

# 正常点:均匀分布在工作区间内

x_normal = self.rng.uniform(x_min * 0.7, x_max * 0.7, n_normal)

y_normal = self.rng.uniform(y_min * 0.7, y_max * 0.7, n_normal)

z_normal = self.rng.uniform(z_min * 1.05, z_max * 0.9, n_normal)

# 异常点:在区间外随机生成

x_out = np.concatenate([

self.rng.uniform(x_min - 200, x_min - 10, n_outliers // 6),

self.rng.uniform(x_max + 10, x_max + 200, n_outliers // 6),

self.rng.uniform(x_min * 0.5, x_max * 0.5, n_outliers - 2 * (n_outliers // 6)),

])

y_out = np.concatenate([

self.rng.uniform(y_min - 150, y_min - 10, n_outliers // 6),

self.rng.uniform(y_max + 10, y_max + 150, n_outliers // 6),

self.rng.uniform(y_min * 0.5, y_max * 0.5, n_outliers - 2 * (n_outliers // 6)),

])

z_out = np.concatenate([

self.rng.uniform(z_min - 80, z_min - 5, n_outliers // 6),

self.rng.uniform(z_max + 5, z_max + 200, n_outliers // 6),

self.rng.uniform(z_min * 0.5, z_max * 0.5, n_outliers - 2 * (n_outliers // 6)),

])

x = np.concatenate([x_normal, x_out[:n_outliers]])

y = np.concatenate([y_normal, y_out[:n_outliers]])

z = np.concatenate([z_normal, z_out[:n_outliers]])

# 打乱顺序

shuffle_idx = self.rng.permutation(n_points)

df = pd.DataFrame({

"point_id": np.arange(n_points),

"x": x[shuffle_idx],

"y": y[shuffle_idx],

"z": z[shuffle_idx],

})

output_path = Path(output_path)

output_path.parent.mkdir(parents=True, exist_ok=True)

df.to_csv(output_path, index=False, encoding="utf-8")

return df

</details>

<details>

<summary></summary>

"""

机器人点位安全区间校验程序

================================================================================

课程映射(滨州职业学院《先进制造技术》):

工业机器人技术基础:机器人工作空间与安全边界

先进制造技术基础:先进制造系统安全规范

智能制造与数字孪生:虚拟-现实映射一致性校验

FMS与先进生产管理:生产安全管理(防错机制)

技术栈(严格):

pandas # 点位数据加载与处理

numpy # 向量化区间校验

matplotlib # 3D 散点图可视化

"""

import sys

import os

sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))

import numpy as np

import pandas as pd

from pathlib import Path

from robot_workspace_check.point_loader import PointCloudLoader

from robot_workspace_check.workspace_validator import (

WorkspaceValidator, WorkspaceBounds

)

from robot_workspace_check.outlier_reporter import OutlierReporter

from robot_workspace_check.visualizer import Visualizer

from robot_workspace_check.synthetic_data import SyntheticDataGenerator

def main():

"""主程序"""

print("=" * 70)

print("机器人点位安全区间校验程序")

print("=" * 70)

results_dir = Path("results")

results_dir.mkdir(exist_ok=True)

# 1. 生成合成数据

print("\n[1/5] 生成合成点位数据...")

generator = SyntheticDataGenerator(rng=np.random.RandomState(42))

bounds_tuple = (-800, 800, -600, 600, 100, 1200)

csv_path = "robot_points.csv"

df_raw = generator.generate(

n_points=500,

bounds=bounds_tuple,

outlier_ratio=0.05,

output_path=csv_path,

)

print(f" 生成 {len(df_raw)} 个点位(含约 5% 异常点)")

# 2. 加载数据

print("\n[2/5] 加载点位数据...")

loader = PointCloudLoader(csv_path)

df = loader.load()

print(f" 加载 {len(df)} 个点位")

# 3. 校验安全区间

print("\n[3/5] 校验安全工作区间...")

bounds = WorkspaceBounds(*bounds_tuple)

validator = WorkspaceValidator(bounds)

df_checked = validator.validate(df)

outlier_count = validator.count_outliers(df_checked)

print(f" 安全工作区间: X[{bounds.x_min},{bounds.x_max}] "

f"Y[{bounds.y_min},{bounds.y_max}] "

f"Z[{bounds.z_min},{bounds.z_max}]")

print(f" 异常点位数量: {outlier_count}")

# 4. 生成报告

print("\n[4/5] 生成校验报告...")

reporter = OutlierReporter(str(results_dir))

summary = reporter.generate_summary(df_checked, total_count=len(df))

reporter.print_report(summary)

reporter.save_outlier_details(df_checked)

# 5. 可视化

print("\n[5/5] 生成 3D 可视化...")

vis = Visualizer(str(results_dir))

vis.plot_workspace_3d(df_checked, bounds)

print(f" 3D 图已保存: {results_dir / 'workspace_3d.png'}")

print(f"\n{'='*70}")

print("校验完成!结果已保存至 results/ 目录")

print(f"{'='*70}")

if __name__ == "__main__":

main()

</details>

<details>

<summary></summary>

import sys

import os

sys.path.ins

利用AI解决实际问题,如果你觉得这个工具好用,欢迎关注长安牧笛!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/29 22:41:41

allfile‑preview|一款适配局域网,开箱即用的前端统一文件预览方案

在内网、局域网业务系统开发中&#xff0c;文件预览一直是非常头疼的痛点。 很多现有预览组件依赖构建工具、需要引入一堆零散依赖库&#xff1b;在内网离线环境下&#xff0c;CDN资源无法加载&#xff0c;组件直接失效&#xff1b;file://本地协议下浏览器安全策略限制fetch请…

作者头像 李华
网站建设 2026/9/29 22:40:29

智能客服API开放能力解析:对话、转写与质检接口如何赋能企业服务

关键词&#xff1a;智能客服、API开放、对话接口、语音转写、质检接口、Webhook、系统集成智能客服系统不再是封闭的工具。通过开放API&#xff0c;企业可以把对话能力、语音转写能力和质检能力嵌入自己的CRM、工单或数据平台&#xff0c;让客服数据流动起来&#xff0c;服务流…

作者头像 李华
网站建设 2026/9/29 22:40:26

智慧文博数字化系统架构设计:从三维采集到平台应用的全链路方案

智慧文博数字化系统架构设计&#xff1a;从三维采集到平台应用的全链路方案 摘要&#xff1a; 本文给出智慧文博数字化全链路架构设计&#xff0c;覆盖采集、处理、平台、应用四层。核心方案是"结构光扫描AI后处理智慧管理平台"一体化架构&#xff1a;采集层实现0.01…

作者头像 李华
网站建设 2026/9/29 22:40:16

智能家居开源硬件项目怎么选?四层拆解与实操学习路径

1. 找智能家居开源硬件项目&#xff0c;先搞清楚你要的是哪一层很多人一上来就问“有没有好的智能家居开源项目推荐”&#xff0c;这个问题其实没法回答。智能家居硬件开源项目不是一个单一品类&#xff0c;它至少分成四个层面&#xff1a;硬件设计层&#xff08;PCB、原理图、…

作者头像 李华
网站建设 2026/9/29 22:40:14

C++在单片机上的工程实践:从配置到外设驱动封装

很多人一听到“C在单片机的应用”第一反应就是&#xff1a;这玩意儿在单片机上跑得动吗&#xff1f;我搞了十几年单片机开发&#xff0c;早些年也完全只用C&#xff0c;后来被项目里越来越复杂的逻辑逼得开始用C&#xff0c;用完之后确实回不去。这个系列的第二篇&#xff0c;我…

作者头像 李华