ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

python的先进制造技术工业场景模拟第二十七篇:加载机器人标定误差数据集,计算标定前后定位误差的改善幅度。

python的先进制造技术工业场景模拟第二十七篇:加载机器人标定误差数据集,计算标定前后定位误差的改善幅度。 周二下午机器人调试间。标定做完了可我不知道到底改善了多少调试员小赵把两份 CSV 甩在桌上一份是标定前一份是标定后每个点位记录了实际坐标和理论坐标差值就是误差。可二十个点位每个点位 XYZ 三个方向我怎么跟工艺科说标定有效我点开文件。这表里有什么小赵问。每个点位一行理论坐标 X/Y/Z实际坐标 X/Y/Z标定前一份、标定后一份我指着数据问题是你只看了某几个点的单轴误差没算整体定位误差的统计量。我就想干一件事小赵说把标定前后的定位误差做个对比——均值降了多少、最大误差降了多少、每个方向的改善幅度、有没有哪个点位改善不明显甚至变差了。最好画个图让工艺科一眼看出来标定值不值。比如点位 P05标定前误差 2.1mm标定后 0.4mm降了 80%我接话但点位 P12 标定前 1.8mm标定后 1.5mm只降了 16%那就要看是不是那个位置关节柔性大或者标定参数没覆盖到。对小赵点头还有我想看 XYZ 三个方向各自改善了多少是不是某个方向标定效果特别差。以前只能说差不多准了现在要拿数据说话。用 pandas 读两份标定数据numpy 算欧氏距离误差向量scipy 做配对 t 检验验证改善显著性matplotlib 画误差对比散点改善幅度柱状图方向分解图scikit-learn 聚类找改善不明显的异常点位networkx 建点位-方向-改善幅度关系网我开工程数据自包含合成 20 个点位的标定前后坐标下载就能跑。敲了行原型err_before np.linalg.norm(pts[[actual_x,actual_y,actual_z]].values -pts[[theory_x,theory_y,theory_z]].values, axis1)完整版用 OOP 封好我说一个类管数据加载一个类算误差一个类做前后对比统计一个类做显著性检验一个类找改善异常点位一个类建关系网一个类出图。输出标定前后误差分布、改善幅度、异常点位清单存 results/。小赵凑近看那以后看报告标定前均误差 2.34mm标定后 0.52mm整体改善 77.8%X 方向改善 82%Y 方向 71%Z 方向 79%。P12 只改善 16%标红建议重新采集该区域标定数据。对我接话机器人标定不是做了就行得量化改善幅度。数字孪生里机器人模型要校准这张误差对比表就是校准效果的验收单。一、实际应用场景真实痛点场景设定六轴工业机器人现场标定四点法/激光跟踪仪采集标定前后各 N 个示教点的理论坐标与实际坐标。调试员只能肉眼对比个别点位无法统计整体改善幅度也无法识别标定覆盖薄弱区域导致标定有效缺乏量化证据。现场原话叙事化不是标定没用小赵说是没法证明。我花两天标定完工艺科问好了多少我说感觉准了。人家不信让我拿数据。我翻出标定前后坐标表二十个点每个点 XYZ 三个数我总不能让人一个个减吧后来我拿 Excel 减了几个发现大部分点误差从 2mm 降到 0.5mm但有俩点只降了一点我说不清为啥。还有 XYZ 方向有的点 X 方向改善特别明显Z 方向几乎没变这跟标定方法有关系——四点法对 XY 平面敏感Z 方向补偿弱。核心矛盾标定前后坐标流水 与 定位误差向量计算 前后配对统计 方向分解 改善显著性检验 异常点位识别 之间的断层。二、痛点分析映射到滨州职业学院《先进制造技术》课程模型《先进制造技术》模块 本篇痛点对应工业机器人技术基础机器人标定、DH参数修正、定位精度 标定前后定位误差量化对比先进制造技术基础精密测量与误差分析 三维空间误差向量统计智能制造与数字孪生机器人数字模型校准 标定效果验收的数据底座数控加工与CAD/CAM技术加工精度保障 机器人末端精度对标机床精度FMS与先进生产管理设备能力验证 标定作为设备维护标准流程的量化验收一句话总结我们需要一个机器人标定前后定位误差改善幅度分析程序用pandas 加载标定数据numpy 算三维误差向量scipy 做配对 t 检验scikit-learn 聚类找改善异常点位networkx 建点位-方向关系网实现从感觉准了到量化改善幅度 显著性验证 薄弱点位定位。三、核心逻辑讲解大白话3.1 问题本质把机器人想成手眼协调测试把机器人末端想成你的手指去点靶纸* 理论坐标 靶心位置你应该点到的地方* 实际坐标 手指落点实际点到的地方* 定位误差 手指离靶心多远三维空间直线距离* 标定前 没练过的手到处偏* 标定后 练过的手偏差小了* 改善幅度 (标定前误差 - 标定后误差) / 标定前误差* 方向分解 偏左偏右(ΔX) vs 偏高偏低(ΔZ)看哪个方向改善最明显* 异常点位 别人都进步了 80%就它只进步 15%说明那个区域标定没覆盖到* 配对 t 检验 统计学上确认标定确实有用不是运气3.2 业务逻辑 → 代码映射加载标定前后坐标数据│▼ CalibDataLoader (pandas)读取 CSVpoint_id, theory_x, theory_y, theory_z,actual_before_x, actual_before_y, actual_before_z,actual_after_x, actual_after_y, actual_after_z校验坐标完整性│▼ ErrorCalculator (numpy)三维误差向量err √[(Ax-Tx)² (Ay-Ty)² (Az-Tz)²]方向分量误差|Ax-Tx|, |Ay-Ty|, |Az-Tz|│▼ ImprovementAnalyzer (pandas/numpy/scipy)前后对比标定前均值/中位/最大 vs 标定后改善幅度 (err_before - err_after) / err_before方向级改善ΔX/ΔY/ΔZ 各自均值变化scipy 配对 t 检验标定前后误差差异显著性│▼ ImprovementAnomalyDetector (scikit-learn)异常点位识别特征[改善幅度, 标定后误差]KMeans 找改善不明显的点位│▼ CalibGraph (networkx)关系网点位-方向-改善幅度 三层图边权改善幅度(越小越粗越薄弱)│▼ CalibVisualizer (matplotlib)可视化1. 标定前后误差箱线图2. 各点位改善幅度柱状图3. XYZ方向误差分解对比4. 异常点位散点(标定前误差 vs 改善幅度)5. 点位-方向关系网│▼ SyntheticCalibGenerator (numpy)合成数据20点位标定前误差 1.5~3.5mm标定后大部分降 70~85%少量只降 10~20%3.3 为什么需要配对 t 检验方法 问题看均值下降 可能是随机波动不是标定效果看最大误差 受极端值影响配对 t 检验 同一点位前后配对消除点位间差异严格验证3.4 分析前后对比维度 调试员手算 本程序误差计算 单点手减 全点位向量化整体改善 感觉 均值中位最大配对t检验方向分解 无 XYZ 各自改善幅度薄弱点位 靠回忆 聚类自动标红验收报告 口头 统计图表显著性四、OOP 代码实现4.1 项目结构robot_calib_eval/├── robot_calib_eval/│ ├── __init__.py│ ├── calib_loader.py # 标定数据加载│ ├── error_calculator.py # 三维误差计算│ ├── improvement_analyzer.py # 前后对比统计(scipy)│ ├── improvement_anomaly.py # 改善异常点位识别│ ├── calib_graph.py # 点位-方向关系网│ ├── visualizer.py # 可视化│ └── synthetic_data.py # 合成数据├── tests/│ ├── __init__.py│ └── test_calib_eval.py├── results/│ ├── error_box_before_after.png│ ├── improvement_bar.png│ ├── direction_decomp.png│ ├── anomaly_scatter.png│ ├── calib_graph.png│ ├── error_detail.csv│ ├── improvement_summary.csv│ ├── anomaly_points.csv│ └── calib_report.txt└── run_calib_eval.py4.2 核心源码detailssummary/summary机器人标定数据加载器import pandas as pdfrom pathlib import Pathfrom typing import Optional, Tupleclass CalibDataLoader:加载标定前后坐标数据(单文件双时段 或 两个文件)def __init__(self, filepath: str calib_data.csv,encoding: str utf-8):self.filepath Path(filepath)self.encoding encodingself._raw: Optional[pd.DataFrame] Nonedef load(self) - pd.DataFrame:if not self.filepath.exists():raise FileNotFoundError(f文件不存在: {self.filepath})self._raw pd.read_csv(self.filepath, encodingself.encoding)rename {}for tgt, al in {point_id: [point_id, 点位, id],theory_x: [theory_x, 理论X, tx],theory_y: [theory_y, 理论Y, ty],theory_z: [theory_z, 理论Z, tz],actual_before_x: [actual_before_x, 标定前X, abx],actual_before_y: [actual_before_y, 标定前Y, aby],actual_before_z: [actual_before_z, 标定前Z, abz],actual_after_x: [actual_after_x, 标定后X, aax],actual_after_y: [actual_after_y, 标定后Y, aay],actual_after_z: [actual_after_z, 标定后Z, aaz],}.items():if tgt not in self._raw.columns:for a in al:if a in self._raw.columns:rename[a] tgtbreakself._raw self._raw.rename(columnsrename)req [point_id, theory_x, theory_y, theory_z,actual_before_x, actual_before_y, actual_before_z,actual_after_x, actual_after_y, actual_after_z]miss [c for c in req if c not in self._raw.columns]if miss:raise ValueError(f缺少必要列: {miss})for c in req[1:]: # 坐标列转数值self._raw[c] pd.to_numeric(self._raw[c], errorscoerce)self._raw self._raw.dropna(subsetreq[1:]).reset_index(dropTrue)return self._raw.copy()/detailsdetailssummary/summary三维定位误差计算器 (numpy)import numpy as npimport pandas as pdfrom typing import Optional, Tupleclass ErrorCalculator:计算标定前后各点位三维定位误差def __init__(self):passdef calc_errors(self, df: pd.DataFrame) - pd.DataFrame:out df.copy()theory out[[theory_x, theory_y, theory_z]].valuesbefore out[[actual_before_x, actual_before_y, actual_before_z]].valuesafter out[[actual_after_x, actual_after_y, actual_after_z]].values# 欧氏距离err_b np.linalg.norm(before - theory, axis1)err_a np.linalg.norm(after - theory, axis1)out[err_before_mm] np.round(err_b, 4)out[err_after_mm] np.round(err_a, 4)# 方向分量绝对误差d_b np.abs(before - theory)d_a np.abs(after - theory)for i, ax in enumerate([x, y, z]):out[ferr_before_{ax}_mm] np.round(d_b[:, i], 4)out[ferr_after_{ax}_mm] np.round(d_a[:, i], 4)return outdef calc_improvement(self, df: pd.DataFrame) - pd.DataFrame:计算改善幅度out df.copy()# 改善幅度 (err_before - err_after) / err_beforeimp np.where(out[err_before_mm] 0,(out[err_before_mm] - out[err_after_mm]) / out[err_before_mm],0.0)out[improvement_ratio] np.round(imp, 4)# 绝对改善量out[improvement_abs_mm] np.round(out[err_before_mm] - out[err_after_mm], 4)# 方向级改善for ax in [x, y, z]:imp_ax np.where(out[ferr_before_{ax}_mm] 0,(out[ferr_before_{ax}_mm] - out[ferr_after_{ax}_mm]) /out[ferr_before_{ax}_mm],0.0)out[fimp_{ax}] np.round(imp_ax, 4)return out/detailsdetailssummary/summary标定前后改善统计分析 (scipy)import numpy as npimport pandas as pdfrom scipy import statsfrom typing import Optional, Dictclass ImprovementAnalyzer:配对t检验 方向分解统计def __init__(self, conf: float 0.95):self.conf confdef overall_stats(self, df: pd.DataFrame) - Dict:整体统计量eb df[err_before_mm].valuesea df[err_after_mm].valuesreturn {n_points: len(df),before_mean: round(float(eb.mean()), 4),before_median: round(float(np.median(eb)), 4),before_max: round(float(eb.max()), 4),before_std: round(float(eb.std(ddof1)), 4),after_mean: round(float(ea.mean()), 4),after_median: round(float(np.median(ea)), 4),after_max: round(float(ea.max()), 4),after_std: round(float(ea.std(ddof1)), 4),improvement_mean: round((eb.mean() - ea.mean()) / eb.mean() * 100, 2) if eb.mean() 0 else 0.0,}def paired_ttest(self, df: pd.DataFrame) - Dict:配对t检验: 标定前后误差差异eb df[err_before_mm].valuesea df[err_after_mm].valuesif len(eb) 2:return {t_stat: np.nan, p_value: np.nan}t, p stats.ttest_rel(eb, ea)return {t_stat: round(float(t), 4),p_value: round(float(p), 4),significant: bool(p (1 - self.conf)),}def direction_stats(self, df: pd.DataFrame) - pd.DataFrame:各方向改善统计rows []for ax in [x, y, z]:eb df[ferr_before_{ax}_mm].valuesea df[ferr_after_{ax}_mm].valuesimp df[fimp_{ax}].valuesrows.append({axis: ax.upper(),before_mean_mm: round(float(eb.mean()), 4),after_mean_mm: round(float(ea.mean()), 4),improvement_ratio: round(float(imp.mean()), 4),improvement_pct: round(float(imp.mean()) * 100, 2),})return pd.DataFrame(rows).sort_values(improvement_pct, ascendingTrue).reset_index(dropTrue)def point_ranking(self, df: pd.DataFrame) - pd.DataFrame:按改善幅度排序sub df[[point_id, err_before_mm, err_after_mm,improvement_ratio, improvement_abs_mm]].copy()sub sub.sort_values(improvement_ratio).reset_index(dropTrue)return sub/detailsdetailssummary/summary改善异常点位识别 (scikit-learn)import numpy as npimport pandas as pdfrom sklearn.cluster import KMeansfrom sklearn.preprocessing import StandardScalerfrom typing import Optionalclass ImprovementAnomalyDetector:找改善不明显的点位def __init__(self, n_clusters: int 2, random_state: int 42,low_imp_thresh: float 0.3):self.n_clusters n_clustersself.random_state random_stateself.low_imp_thresh low_imp_threshself.scaler StandardScaler()def detect(self, df: pd.DataFrame) - pd.DataFrame:out df.copy()# 特征改善幅度 标定后误差X out[[improvement_ratio, err_after_mm]].valuesXs self.scaler.fit_transform(X)k min(self.n_clusters, len(out))km KMeans(n_clustersk, random_stateself.random_state, n_init10)out[cluster] km.fit_predict(Xs)# 改善幅度低的簇cmean out.groupby(cluster)[improvement_ratio].mean()low_cluster cmean.idxmin()out[cluster_is_low_imp] out[cluster] low_cluster# 规则改善30% 或 标定后误差1.5mmout[rule_low] (out[improvement_ratio] self.low_imp_thresh) | \(out[err_after_mm] 1.5)out[is_anomaly] out[cluster_is_low_imp] | out[rule_low]return out.sort_values(improvement_ratio).reset_index(dropTrue)def summary(self, df: pd.DataFrame) - pd.DataFrame:sub df[df[is_anomaly]]return sub[[point_id, err_before_mm, err_after_mm,improvement_ratio, improvement_abs_mm]].copy()/detailsdetailssummary/summary点位-方向-改善幅度关系网 (networkx)import networkx as nximport pandas as pdfrom typing import Optionalclass CalibGraph:建三层关系网def __init__(self):self.G nx.Graph()def build(self, df: pd.DataFrame) - nx.Graph:self.G.clear()for _, r in df.iterrows():pid fPT:{r[point_id]}self.G.add_node(pid, ntypepoint)for ax in [X, Y, Z]:axn fAX:{ax}self.G.add_node(axn, ntypeaxis)imp_val float(r[fimp_{ax.lower()}])# 改善幅度越小(越薄弱)边越粗w max(0.1, (1.0 - imp_val) * 10)self.G.add_edge(pid, axn, weightround(w, 2),improvementround(imp_val, 4))return self.Gdef weak_combinations(self) - pd.DataFrame:找改善最弱的点位-方向组合rows []for u, v, d in self.G.edges(dataTrue):if self.G.nodes[u].get(ntype) point:rows.append({point: u.split(:)[-1],axis: v.split(:)[-1],improvement: d.get(improvement, 0),weakness_weight: d.get(weight, 0),})elif self.G.nodes[v].get(ntype) point:rows.append({point: v.split(:)[-1],axis: u.split(:)[-1],improvement: d.get(improvement, 0),weakness_weight: d.get(weight, 0),})df pd.DataFrame(rows)if df.empty:return dfreturn df.sort_values(weakness_weight, ascendingFalse).reset_index(dropTrue)/detailsdetailssummary/summary可视化 (matplotlib)import numpy as npimport pandas as pdimport matplotlib.pyplot as pltfrom pathlib import Pathplt.rcParams[font.sans-serif] [SimHei, DejaVu Sans]plt.rcParams[axes.unicode_minus] Falseclass CalibVisualizer:def __init__(self, results_dir: str results):self.results_dir Path(results_dir)self.results_dir.mkdir(exist_okTrue)def error_box_before_after(self, df):fig, ax plt.subplots(figsize(8, 6))data [df[err_before_mm].values, df[err_after_mm].values]ax.boxplot(data, labels[标定前, 标定后], showmeansTrue)ax.set_ylabel(定位误差 (mm))ax.set_title(标定前后定位误差箱线图, fontsize14, fontweightbold)ax.grid(axisy, alpha0.3)plt.tight_layout()plt.savefig(self.results_dir / error_box_before_after.png,dpi150, bbox_inchestight)plt.close()def improvement_bar(self, rank_df):fig, ax plt.subplots(figsize(14, 6))x range(len(rank_df))colors [#E74C3C if r 0.3 else #F39C12 if r 0.6 else #27AE60for r in rank_df[improvement_ratio]]ax.bar(x, rank_df[improvement_ratio] * 100, colorcolors)ax.set_xticks(list(x))ax.set_xticklabels(rank_df[point_id], rotation45, haright, fontsize9)ax.set_ylabel(改善幅度 (%))ax.set_title(各点位标定改善幅度, fontsize14, fontweightbold)ax.axhline(50, ls--, cgray, label50%基准线)ax.axhline(80, ls--, cgreen, label80%优秀线)ax.legend()ax.grid(axisy, alpha0.3)plt.tight_layout()plt.savefig(self.results_dir / improvement_bar.png,dpi150, bbox_inchestight)plt.close()def direction_decomp(self, dir_stat):fig, ax plt.subplots(figsize(10, 6))x np.arange(len(dir_stat))w 0.3ax.bar(x - w/2, dir_stat[before_mean_mm], w,label标定前, color#95A5A6)ax.bar(x w/2, dir_stat[after_mean_mm], w,label标定后, color#3498DB)ax.set_xticks(x)ax.set_xticklabels(dir_stat[axis], fontsize12)ax.set_ylabel(平均误差 (mm))ax.set_title(XYZ方向误差分解对比, fontsize14, fontweightbold)ax.legend()ax.grid(axisy, alpha0.3)# 标注改善百分比for i, r in dir_stat.iterrows():ax.text(i w/2, float(r[after_mean_mm]) 0.05,f{r[improvement_pct]}%, hacenter, fontsize9,colorgreen, fontweightbold)plt.tight_layout()plt.savefig(self.results_dir / direction_decomp.png,dpi150, bbox_inchestight)plt.close()def anomaly_scatter(self, df):fig, ax plt.subplots(figsize(11, 6))normal df[~df[is_anomaly]]anom df[df[is_anomaly]]ax.scatter(normal[err_before_mm], normal[improvement_ratio] * 100,c#3498DB, label正常改善, s40, alpha0.7)ax.scatter(anom[err_before_mm], anom[improvement_ratio] * 100,c#E74C3C, label改善异常, s80, edgecolork)for _, r in anom.iterrows():ax.annotate(r[point_id], (r[err_before_mm],r[improvement_ratio] * 100),fontsize8, colorred)ax.set_xlabel(标定前误差 (mm))ax.set_ylabel(改善幅度 (%))ax.set_title(异常点位识别散点图, fontsize14, fontweightbold)ax.legend()ax.grid(alpha0.3)plt.tight_layout()plt.savefig(self.results_dir / anomaly_scatter.png,dpi150, bbox_inchestight)plt.close()def graph_plot(self, G):fig, ax plt.subplots(figsize(14, 10))pos nx.spring_layout(G, seed42, k0.8)ncolor []for n, d in G.nodes(dataTrue):t d.get(ntype)ncolor.append({point: #2ECC71, axis: #E74C3C}.get(t, #999))sizes [300 G.degree(n) * 40 for n in G.nodes()]nx.draw_networkx_nodes(G, pos, node_colorncolor,node_sizesizes, axax, alpha0.9)edges list(G.edges(dataTrue))ws [d[weight] for *_, d in edges]nx.draw_networkx_edges(G, pos, widthws, alpha0.4, axax,edge_color#E67E22)labels {n: n.split(:)[-1] for n, d in G.nodes(dataTrue)if d.get(ntype) axis}nx.draw_networkx_labels(G, pos, labelslabels, font_size10, axax)ax.set_title(点位-方向改善关系网\n(绿点位 红方向 橙线越粗该方向改善越弱),fontsize13, fontweightbold)ax.axis(off)plt.tight_layout()plt.savefig(self.results_dir / calib_graph.png,dpi150, bbox_inchestight)plt.close()/detailsdetailssummary/summary合成机器人标定数据生成器import numpy as npimport pandas as pdfrom pathlib import Pathfrom typing import Optionalclass SyntheticCalibGenerator:生成 20 个点位的标定前后坐标标定前误差 1.5~3.5mm (随机偏移)标定后大部分降 70~85%少量只降 10~20% (薄弱区域)def __init__(self, rng: Optional[np.random.RandomState] None):self.rng rng or np.random.RandomState(42)def generate(self, output_path: str calib_data.csv,n_points: int 20) - pd.DataFrame:records []for i in range(1, n_points 1):pid fP{i:02d}# 理论坐标 (工作空间内随机点)tx float(self.rng.uniform(-800, 800))ty float(self.rng.uniform(-600利用AI解决实际问题如果你觉得这个工具好用欢迎关注长安牧笛
返回列表