☰
python的先进制造技术工业场景模拟第八十四篇:编写机器人抓取仿真,模拟工件定位存在偏差,测试位置自适应补偿效果。
2026/10/7 8:12:11 网站建设 项目流程

周四上午,机器人上下料工位。

“这批电机端盖,来料是料仓推出来的,位置每次偏一点,”机器人操作工小周蹲在安全栏外,“视觉给个中心,机械臂就按那个点抓,偏个0.5mm还好,偏到1.2mm,夹爪就咬到法兰边,装到机床主轴上同轴度直接飘。”

我接上导出的来料定位日志、视觉检测坐标、机器人实际抓取位姿、装夹后同轴度检测值。

“这里面有啥?”我问。

“来料X/Y偏置、转角θ、视觉识别中心、机器人TCP执行值、装后同轴度都有,”小周说,“可系统就是‘视觉给啥抓啥’,不模拟‘来料偏差分布→抓取点偏移→自适应补偿后残差→同轴度劣化’。想验证补偿算法管不管用,得真跑几百件看报废率。”

“最亏的是中段,”小周补一句,“偏差在±0.8mm以内看着都装上了,可同轴度从0.02mm爬到0.05mm,检具按批抽,正好没抽到边界件。到1.2mm那几件,直接划伤主轴锥孔。”

“我就想干一件事,”小周说,“给来料偏差分布+视觉测量+补偿模型,模拟抓取点偏移,算补偿前后的残差,反推装后同轴度,标出补偿后还剩多少残差、边界件能不能兜住,像个小抓取自适应仿真器,不用先上真机磨夹爪。”

“机器人不是看TCP走没走准,”我接话,“是看‘来料偏多少、视觉量得准不准、补偿量怎么加、残差剩多少’。用 numpy 做坐标变换+补偿递推,pandas 管来料批次,scipy 做误差分布拟合+插值,matplotlib 画偏差散点+补偿前后对比+同轴度曲线,networkx 建‘来料-视觉-补偿-同轴度’关联,sklearn 做合格分级。”

“对,”小周点头,“要能说清‘来料σ=0.45mm,视觉噪声0.08mm,开补偿前残差1.2mm→同轴度0.06mm超差;开补偿后残差0.15mm→同轴度0.018mm合格,边界件也兜住;主因是来料Y向偏移+转角耦合’。”

“OOP 封好,”我开工程,“来料加载器、视觉测量模型、坐标补偿器、抓取残差计算、同轴度映射、合格分类器、可视化器,合成多批次来料,下载就能跑。”

敲了行原型:

# 目标: 来料偏差 → 视觉测量 → 位置自适应补偿 → 残差 → 同轴度

# 方法: 刚体坐标变换 + 补偿闭环 + RF合格分级 + 关联图

小周凑近看:“那以后看报告:来料偏差散点,补偿前后残差对比,同轴度随偏差曲线,关联网络,合格预测散点。新料盘上机前先跑,红圈就是兜不住的件。”

“对,”我接话,“机器人仿真不是‘画个轨迹’,是‘提前看见哪件偏得补偿也救不回’。数字孪生里挂这个抓取补偿看板,就是小周的‘防划伤镜’。”

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

场景设定:六轴工业机器人做机加产线上下料,抓取电机端盖类盘类件,来料由振动料仓+输送线供给,存在 X/Y 平移偏差与绕 Z 转角偏差。视觉系统给出识别中心,机器人按识别点规划夹爪 TCP。未开自适应补偿时,偏差直接带入装夹,导致主轴同轴度超差,边界件划伤锥孔。

现场原话(叙事化):

“不是机器人精度不行,”小周说,“是料每次站的位置不一样。视觉说中心在(0,0),实际可能偏了0.6mm还转了2°,夹爪按(0,0)抓,就咬在法兰倒角上,装上去同轴度就废了。”

“最亏的是补偿逻辑,”小周说,“以前写死TCP偏移表,换料盘就废。想验证‘在线算偏差再补’这个算法,得先磨坏几十个夹爪、划几根主轴才知道行不行。”

核心矛盾:“视觉给点即抓+固定补偿表” 与 “来料偏差建模→视觉测量→自适应补偿→残差量化→同轴度预测+关联图” 之间的断层。

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

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

工业机器人技术基础:TCP、坐标变换、手眼标定、抓取定位、位姿误差 来料偏差+自适应补偿+残差

数控加工与CAD/CAM技术:装夹同轴度、定位基准 同轴度映射

先进制造技术基础:几何精度、误差传递、定位误差 误差链量化

智能制造与数字孪生:机器人状态+来料状态数字映射、补偿看板 抓取补偿挂孪生

先进制造新模式:自适应工艺、数据驱动补偿知识库 补偿模型复用

一句话总结:我们需要一个“来料位姿偏差→视觉测量→自适应位置补偿→抓取残差→装后同轴度预测→合格分级+关联图”程序,实现从“写死补偿表”到“在线自适应补偿仿真验证”的闭环。

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

3.1 问题本质:把抓取想成“抓一张歪放的硬币”

把端盖想成桌上放的一堆硬币,每次放的位置都偏一点、还转个角度:

* 来料偏差 = 硬币中心偏了 (Δx, Δy),还转了 θ 角

* 视觉测量 = 你眯眼估中心,估得准但也有误差(视觉噪声)

* 不补偿 = 按你估的中心抓,硬币偏多少抓偏多少

* 自适应补偿 = 先算出“偏了多少+转了多少”,让夹爪跟着偏、跟着转,对准真实中心

* 残差 = 补偿后还差的那一点点(视觉误差+算法截断+夹爪间隙)

* 同轴度 = 装到主轴上后,中心轴和主轴轴的偏移量,残差越大它越飘

* 写死表 = 按上批料记个偏移量,换批就错

* 仿真验证 = 先造一堆偏差数据,算补偿前后残差,看边界件兜不兜得住

3.2 业务逻辑 → 代码映射

输入来料位姿批次+视觉参数

│

▼ WorkpieceLoader (pandas)

读取表:

件号, 真实Δx, 真实Δy, 真实θ, 料盘批次, 直径

│

▼ VisionModel (numpy + scipy)

视觉测量:

测值 = 真值 + 高斯噪声(σ_vis)

θ测量带量化误差

输出 (xv, yv, θv)

│

▼ PoseCompensator (numpy)

自适应补偿:

将测量位姿反算到机器人基坐标系

TCP_target = TCP_nominal + R(θv)·[xv,yv] + 夹爪随转补偿

补偿后理论抓取点对齐真实中心

│

▼ GraspResidual (numpy)

残差计算:

残差 = |真实中心 - 补偿后TCP| (含视觉残差+截断)

分补偿前/补偿后两路输出

│

▼ CoaxialMapper (scipy)

同轴度映射:

同轴度 = k * 残差 + 转角耦合项 + 装夹间隙

用样条拟合残差→同轴度

│

▼ QualifyClassifier (sklearn)

合格分级:

特征: 残差, θ, 直径, 补偿开关

标签: 合格(≤0.03) / 临界 / 超差(>0.05)

RF三分类 + 5折宏F1

│

▼ RobotGraspVisualizer (matplotlib + networkx)

可视化:

1. 来料偏差散点(补偿前红/补偿后绿)

2. 补偿前后残差分布对比直方图

3. 同轴度随来料偏移曲线

4. 来料-视觉-补偿-同轴度关联网络

5. 合格预测vs实际散点

6. 单件抓取俯视示意(箭头=补偿向量)

│

▼ SyntheticWorkpieces (numpy)

合成数据:

多批次, 机制: Y向偏移> X向, θ与偏移耦合, 视觉σ可配

3.3 为什么不能“视觉给点即抓”

视角 问题

看机器人重复定位 ±0.02mm很好,但来料偏1mm

写死补偿表 换料盘失效

只看视觉中心 漏掉转角θ耦合

自适应补偿 每件在线算偏移+转角

残差双路对比 补偿前后量化差异

同轴度反推 直接关联装夹质量

RF分级 边界件提前标红

3.4 分析前后对比

维度 传统方式 本程序

补偿方式 固定偏移表 每件自适应位姿补偿

残差可见性 装后检具才知 仿真前置算残差

边界件 装完划主轴才发现 提前标红

主因分析 凭手感调 Y向+θ耦合量化

知识沉淀 老师傅经验 补偿模型知识库

四、OOP 代码实现

4.1 项目结构

robot_grasp_comp/

├── robot_grasp_comp/

│ ├── __init__.py

│ ├── workpiece_loader.py # 来料加载

│ ├── vision_model.py # 视觉测量(numpy+scipy)

│ ├── pose_compensator.py # 位姿自适应补偿(numpy)

│ ├── grasp_residual.py # 抓取残差

│ ├── coaxial_mapper.py # 同轴度映射(scipy)

│ ├── qualify_classifier.py # 合格分级(sklearn)

│ ├── robot_grasp_visualizer.py # 可视化

│ └── synthetic_workpieces.py # 合成来料

├── tests/

│ ├── __init__.py

│ └── test_grasp.py

├── results/

│ ├── deviation_scatter.png

│ ├── residual_compare_hist.png

│ ├── coaxial_vs_offset_curve.png

│ ├── grasp_chain_network.png

│ ├── qualify_pred_scatter.png

│ ├── single_grasp_arrow.png

│ ├── grasp_detail.csv

│ └── grasp_report.txt

└── run_grasp.py

4.2 核心源码

<details>

<summary></summary>

"""来料位姿加载器。"""

import pandas as pd

from pathlib import Path

class WorkpieceLoader:

"""加载来料真实位姿偏差。"""

def __init__(self, filepath: str = "workpieces.csv",

encoding: str = "utf-8"):

self.filepath = Path(filepath)

self.encoding = encoding

def load(self) -> pd.DataFrame:

if not self.filepath.exists():

raise FileNotFoundError(self.filepath)

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

req = ["pid", "true_dx", "true_dy", "true_theta",

"batch", "diameter"]

miss = [c for c in req if c not in df.columns]

if miss:

raise ValueError(f"缺列: {miss}")

for c in req[1:]:

df[c] = pd.to_numeric(df[c], errors="coerce")

return df.dropna(subset=req).reset_index(drop=True)

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

s = f"件数: {len(df)}\n"

s += f"X偏差σ={df['true_dx'].std():.3f}mm, Y偏差σ={df['true_dy'].std():.3f}mm\n"

s += f"转角θ范围: {df['true_theta'].min():.2f}~{df['true_theta'].max():.2f}rad\n"

s += f"直径: {df['diameter'].iloc[0]}mm, 批次数: {df['batch'].nunique()}"

return s.rstrip()

</details>

<details>

<summary></summary>

"""视觉测量模型 (numpy + scipy)。"""

import numpy as np

from dataclasses import dataclass

from scipy.stats import norm

@dataclass

class VisionResult:

xv: np.ndarray

yv: np.ndarray

thetav: np.ndarray

class VisionModel:

"""

视觉测量 = 真值 + 高斯噪声

x/y: σ_vis

θ: 量化误差+噪声

"""

def __init__(self, sigma_vis: float = 0.08,

theta_noise: float = 0.01,

rng: np.random.RandomState = None):

self.sigma_vis = sigma_vis

self.theta_noise = theta_noise

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

def measure(self, dx, dy, theta) -> VisionResult:

xv = dx + self.rng.normal(0, self.sigma_vis, len(dx))

yv = dy + self.rng.normal(0, self.sigma_vis, len(dy))

thetav = theta + self.rng.normal(0, self.theta_noise, len(theta))

# 模拟像素量化截断到0.005rad

thetav = np.round(thetav, 3)

return VisionResult(xv, yv, thetav)

</details>

<details>

<summary></summary>

"""位姿自适应补偿器 (numpy)。"""

import numpy as np

from dataclasses import dataclass

@dataclass

class CompResult:

tcp_before: np.ndarray # (N,2) 不补偿TCP

tcp_after: np.ndarray # (N,2) 补偿后TCP

comp_vec: np.ndarray # (N,2) 补偿向量

class PoseCompensator:

"""

基坐标系下:

不补偿: TCP = 标称中心 + 视觉测量值(直接信视觉)

自适应补偿:

TCP = 标称中心 + R(θv)·[xv,yv] (随转对齐)

再叠加夹爪中心对准修正

"""

def __init__(self, nominal: np.ndarray = None):

self.nominal = nominal if nominal is not None else np.zeros(2)

def compensate(self, xv, yv, thetav,

enable: bool = True) -> CompResult:

n = len(xv)

vis = np.column_stack([xv, yv])

if not enable:

tcp_before = self.nominal + vis

return CompResult(tcp_before, tcp_before,

np.zeros_like(vis))

# 随转补偿: 把测量偏移旋转到基坐标

out = np.zeros((n, 2))

for i in range(n):

c, s = np.cos(thetav[i]), np.sin(thetav[i])

R = np.array([[c, -s], [s, c]])

out[i] = self.nominal + R @ np.array([xv[i], yv[i]])

tcp_after = out

comp_vec = tcp_after - (self.nominal + vis)

return CompResult(tcp_before=self.nominal+vis,

tcp_after=tcp_after, comp_vec=comp_vec)

</details>

<details>

<summary></summary>

"""抓取残差计算 (numpy)。"""

import numpy as np

from dataclasses import dataclass

@dataclass

class ResidualResult:

res_before: np.ndarray

res_after: np.ndarray

class GraspResidual:

"""

真实中心 = nominal + [true_dx, true_dy] (已含转角真实中心)

残差 = |真实中心 - TCP|

补偿后残差主要来自视觉噪声+量化截断

"""

def __init__(self, nominal: np.ndarray = None):

self.nominal = nominal if nominal is not None else np.zeros(2)

def compute(self, true_dx, true_dy, comp: CompResult) -> ResidualResult:

true_center = self.nominal + np.column_stack([true_dx, true_dy])

res_before = np.linalg.norm(true_center - comp.tcp_before, axis=1)

res_after = np.linalg.norm(true_center - comp.tcp_after, axis=1)

return ResidualResult(res_before, res_after)

</details>

<details>

<summary></summary>

"""同轴度映射 (scipy)。"""

import numpy as np

from dataclasses import dataclass

from scipy.interpolate import UnivariateSpline

@dataclass

class CoaxialResult:

coaxial: np.ndarray

class CoaxialMapper:

"""

同轴度 = k*残差 + θ耦合项 + 装夹间隙

教学级线性+耦合模型, 可用样条标定

"""

def __init__(self, k: float = 0.045, gap: float = 0.005):

self.k = k

self.gap = gap

def map(self, residual: np.ndarray,

theta: np.ndarray) -> CoaxialResult:

# θ耦合: 转角越大, 残差对同轴度放大越明显

coupling = 1.0 + 2.0 * np.abs(theta)

coaxial = self.k * residual * coupling + self.gap

return CoaxialResult(coaxial)

def fit_spline(self, residual, coaxial):

s = UnivariateSpline(residual, coaxial, k=3, s=len(residual)*1e-4)

return s

</details>

<details>

<summary></summary>

"""合格分级 (sklearn)。"""

import numpy as np

import pandas as pd

from typing import Dict

from sklearn.ensemble import RandomForestClassifier

from sklearn.model_selection import cross_val_score, KFold

class QualifyClassifier:

"""合格/临界/超差 三分类。"""

def __init__(self, random_state: int = 42):

self.model_ = None

self.feat = ["residual", "theta_abs", "diameter", "comp_on"]

@staticmethod

def _label(c: float) -> str:

if c <= 0.03:

return "合格"

if c <= 0.05:

return "临界"

return "超差"

def fit(self, df: pd.DataFrame, coaxial: np.ndarray):

y = np.array([self._label(c) for c in coaxial])

self.model_ = RandomForestClassifier(

n_estimators=300, max_depth=6, min_samples_leaf=2,

random_state=42, n_jobs=-1)

self.model_.fit(df[self.feat].values, y)

return self

def cv(self, df: pd.DataFrame, coaxial: np.ndarray) -> Dict:

y = np.array([self._label(c) for c in coaxial])

kf = KFold(5, shuffle=True, random_state=42)

sc = cross_val_score(self.model_, df[self.feat].values, y,

cv=kf, scoring="f1_macro")

imp = dict(zip(self.feat, self.model_.feature_importances_))

return {"f1_macro": float(sc.mean()),

"importance": dict(sorted(imp.items(),

key=lambda x: x[1], reverse=True))}

def predict(self, df: pd.DataFrame) -> np.ndarray:

return self.model_.predict(df[self.feat].values)

</details>

<details>

<summary></summary>

"""机器人抓取可视化 (matplotlib + networkx)。"""

import numpy as np

import pandas as pd

import matplotlib.pyplot as plt

from pathlib import Path

import networkx as nx

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

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

GRADE = {"合格":"#27AE60","临界":"#F39C12","超差":"#E74C3C"}

class RobotGraspVisualizer:

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

self.results_dir = Path(results_dir)

self.results_dir.mkdir(exist_ok=True)

def deviation_scatter(self, dx, dy, res_before, res_after):

fig, ax = plt.subplots(figsize=(8,8))

ax.scatter(dx, dy, c=res_before*1000, cmap="Reds",

s=30, alpha=0.7, label="补偿前")

ax.scatter(dx*0.1, dy*0.1, c=res_after*1000, cmap="Greens",

s=20, marker="x", label="补偿后(放大10倍显示)")

ax.set_xlabel("来料Δx (mm)", fontsize=12)

ax.set_ylabel("来料Δy (mm)", fontsize=12)

ax.set_title("来料偏差散点(红=补偿前残差,绿=补偿后)",

fontsize=13, fontweight="bold")

ax.legend(); ax.grid(alpha=0.3); ax.set_aspect("equal")

plt.tight_layout()

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

dpi=150, bbox_inches="tight")

plt.close()

def residual_hist(self, res_before, res_after):

fig, ax = plt.subplots(figsize=(10,6))

ax.hist(res_before*1000, bins=30, alpha=0.6,

color="#E74C3C", label=f"补偿前均值{res_before.mean()*1000:.1f}μm")

ax.hist(res_after*1000, bins=30, alpha=0.6,

color="#27AE60", label=f"补偿后均值{res_after.mean()*1000:.1f}μm")

ax.set_xlabel("抓取残差 (μm)", fontsize=12)

ax.set_ylabel("件数", fontsize=12)

ax.set_title("补偿前后残差分布对比", fontsize=13, fontweight="bold")

ax.legend(); ax.grid(alpha=0.3)

plt.tight_layout()

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

dpi=150, bbox_inches="tight")

plt.close()

def coaxial_curve(self, offset_norm, coaxial_before, coaxial_after):

fig, ax = plt.subplots(figsize=(11,6))

x = offset_norm

ax.plot(x, coaxial_before*1000, color="#E74C3C", lw=1.8,

label="补偿前同轴度")

ax.plot(x, coaxial_after*1000, color="#27AE60", lw=1.8,

label="补偿后同轴度")

ax.axhline(30, color="#F39C12", ls="--", lw=1.5, label="合格线30μm")

ax.axhline(50, color="#E74C3C", ls="--", lw=1.5, label="超差线50μm")

ax.set_xlabel("来料偏移幅值 (mm)", fontsize=12)

ax.set_ylabel("同轴度 (μm)", fontsize=12)

ax.set_title("同轴度随来料偏移变化", fontsize=13, fontweight="bold")

ax.legend(); ax.grid(alpha=0.3)

plt.tight_layout()

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

dpi=150, bbox_inches="tight")

plt.close()

def chain_network(self, imp: Dict):

fig, ax = plt.subplots(figsize=(11,7))

G = nx.DiGraph()

nodes = ["来料偏差","视觉测量","自适应补偿","抓取残差","同轴度"]

for n in nodes:

G.add_node(n)

for a,b in zip(nodes[:-1], nodes[1:]):

G.add_edge(a,b, weight=0.8)

for k,v in imp.items():

if k=="residual":

G.add_edge("抓取残差","同轴度", weight=v)

elif k=="theta_abs":

G.add_edge("来料偏差","同轴度", weight=v)

pos = nx.spring_layout(G, seed=42)

nx.draw_networkx_nodes(G,pos,node_color="#3498DB",

node_size=4200,alpha=0.9,ax=ax)

nx.draw_networkx_edges(G,pos,arrowstyle="-|>",arrowsize=22,

edge_color="#555",width=2,ax=ax)

nx.draw_networkx_labels(G,pos,font_size=11,ax=ax,

font_color="white",font_weight="bold")

ax.set_title("来料-视觉-补偿-同轴度关联链",

fontsize=14, fontweight="bold")

ax.axis("off")

plt.tight_layout()

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

dpi=150, bbox_inches="tight")

plt.close()

def pred_scatter(self, y_true, y_pred):

fig, ax = plt.subplots(figsize=(8,8))

labels = ["合格","临界","超差"]

ct = np.array([labels.index(y) for y in y_true])

cp = np.array([labels.index(y) for y in y_pred])

ax.scatter(ct, cp, c="#2980B9", s=50, edgecolors="k", alpha=0.8)

ax.plot([-0.5,2.5],[-0.5,2.5],"r--",lw=2,label="理想")

ax.set_xticks([0,1,2]); ax.set_xticklabels(labels)

ax.set_yticks([0,1,2]); ax.set_yticklabels(labels)

ax.set_xlabel("实际等级", fontsize=12)

ax.set_ylabel("预测等级", fontsize=12)

ax.set_title("合格分级 预测vs实际", fontsize=13, fontweight="bold")

ax.legend(); ax.grid(alpha=0.3)

plt.tight_layout()

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

dpi=150, bbox_inches="tight")

plt.close()

def single_arrow(self, dx, dy, comp_vec, idx=0):

fig, ax = plt.subplots(figsize=(7,7))

ax.quiver(0,0,dx[idx],dy[idx], angles="xy", scale_units="xy",

scale=1, color="#E74C3C", width=0.008, label="来料真偏差")

ax.quiver(dx[idx],dy[idx], comp_vec[idx,0], comp_vec[idx,1],

angles="xy", scale_units="xy", scale=1, color="#27AE60",

width=0.008, label="补偿向量")

ax.scatter(0,0,c="#2C3E50",s=80,zorder=5,label="标称中心")

ax.set_xlim(-2,2); ax.set_ylim(-2,2)

ax.set_aspect("equal")

ax.set_xlabel("X (mm)", fontsize=12); ax.set_ylabel("Y (mm)", fontsize=12)

ax.set_title(f"单件抓取补偿向量示意(件{idx+1})",

fontsize=13, fontweight="bold")

ax.legend(); ax.grid(alpha=0.3)

plt.tight_layout()

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

dpi=150, bbox_inches="tight")

plt.close()

</details>

<details>

<summary></summary>

"""合成来料位姿数据。"""

import numpy as np

import pandas as pd

from pathlib import Path

from typing import Optional

class SyntheticWorkpieces:

"""

多批次盘类件

机制:

Y向偏移σ > X向

θ与偏移幅值弱耦合

视觉σ可配

"""

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

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

def generate(self, out_path: str = "workpieces.csv",

n: int = 200, batch: int = 1,

sigma_x: float = 0.35, sigma_y: float = 0.45,

diameter: float = 120.0) -> pd.DataFrame:

dx = self.rng.normal(0, sigma_x, n)

dy = self.rng.normal(0, sigma_y, n)

r = np.hypot(dx, dy)

theta = 0.02 * r + self.rng.normal(0, 0.015, n) # 偏移越大转角略大

rows = [{

"pid": f"B{batch}_P{i+1:03d}",

"true_dx": round(dx[i], 4),

"true_dy": round(dy[i], 4),

"true_theta": round(theta[i], 4),

"batch": batch,

"diameter": diameter,

} for i in range(n)]

df = pd.DataFrame(rows)

Path(out_path).parent.mkdir(parents=True, exist_ok=True)

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

return df

</details>

<details>

<summary></summary>

"""

机器人抓取仿真: 来料偏差→视觉测量→自适应补偿→残差→同轴度

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

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

工业机器人技术基础:TCP/坐标变换/手眼标定/位姿误差/抓取定位

数控加工与CAD/CAM:装夹同轴度/定位基准

先进制造技术基础:几何精度/误差传递

智能制造与数字孪生:来料+机器人补偿看板

先进制造新模式:自适应工艺/补偿知识库

技术栈(严格):

pandas / numpy # 来料表/坐标变换

scipy # 样条+分布

scikit-learn # RF合格分级

matplotlib / networkx# 散点+关联链

"""

import sys, 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_grasp_comp.workpiece_loader import WorkpieceLoader

from robot_grasp_comp.vision_model import VisionModel

from robot_grasp_comp.pose_compensator import PoseCompensator, CompResult

from robot_grasp_comp.grasp_residual import GraspResidual

from robot_grasp_comp.coaxial_mapper import CoaxialMapper

from robot_grasp_comp.qualify_classifier import QualifyClassifier

from robot_grasp_comp.robot_grasp_visualizer import RobotGraspVisualizer

from robot_grasp_comp.synthetic_workpieces import SyntheticWorkpieces

def main():

print("=" * 70)

print("机器人抓取仿真: 来料偏差→自适应补偿→同轴度预测")

print("=" * 70)

results_dir = Path("results"); results_dir.mkdir(exist_ok=True)

# 1. 合成多批次

print("\n[1/8] 合成来料批次...")

gen = SyntheticWorkpieces(rng=np.random.RandomState(42))

dfs = []

for b in range(3):

d = gen.generate(f"workpieces_b{b+1}.csv", n=200, batch=b+1,

sigma_x=0.35, sigma_y=0.45)

dfs.append(d)

df = pd.concat(dfs, ignore_index=True)

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

print(f" 3批次共{len(df)}件, σx=0.35mm, σy=0.45mm")

# 2. 加载

print("\n[2/8] 加载来料...")

df = WorkpieceLoader("workpieces.csv").load()

print(WorkpieceLoader().summary(df))

dx = df["true_dx"].values

dy = df["true_dy"].values

th = df["true_theta"].values

dia = df["diameter"].values

# 3. 视觉测量

print("\n[3/8] 视觉测量(σ=0.08mm)...")

vm = VisionModel(sigma_vis=0.08, theta_n

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询