C#开发的运动控制和视觉项目
最近在车间里折腾了一套基于C#的运动控制+视觉定位系统,今天就跟大伙唠唠实战中的那些代码片段和踩坑经验。这代码有个坑爹的地方——很多运动控制卡的dll是32位的,记得把项目平台目标改成x86,不然运行时直接给你抛DllNotFoundException。有次现场光照变化,这个值没调好,直接把工件旁边的螺丝孔识别成目标了,结果机械臂上演了一出"大力出奇迹",场面一度非常尴尬。有次学徒忘了这个负号,机
C#开发的运动控制和视觉项目

最近在车间里折腾了一套基于C#的运动控制+视觉定位系统,今天就跟大伙唠唠实战中的那些代码片段和踩坑经验。别被工业场景吓到,其实用C#搞自动化比你想象中简单——毕竟.NET的硬件封装库真不是吃素的。

先看运动控制这块硬骨头。我们用过固高、雷塞这些国产卡,它们的C# SDK其实大同小异。初始化运动控制卡时,这个try-catch块救了我无数次:
try
{
// 固高卡初始化示例
if (GTS.mc.GT_Open(0, 1, out short boardId) == GTS.mc.GT_ERR_SUCCESS)
{
GTS.mc.GT_LoadConfig(boardId, "motor.cfg");
GTS.mc.GT_ClrSts(boardId, 1); // 清状态
}
}
catch (DllNotFoundException ex)
{
MessageBox.Show($"驱动文件没找到!检查dll位置\n{ex.Message}");
}
这代码有个坑爹的地方——很多运动控制卡的dll是32位的,记得把项目平台目标改成x86,不然运行时直接给你抛DllNotFoundException。之前因为这个翻车,愣是排查了两个小时...

视觉定位部分更刺激。用AForge.NET做图像采集,配合OpenCVSharp做处理是常规操作。检测圆形工件的代码可能是这样的:
// 找圆大法
var circles = Cv2.HoughCircles(processedImage,
HoughMethods.Gradient,
1.0, // dp值调小能检测更密集的圆
50, // 最小圆心距
param1: 200,
param2: 30, // 这个参数决定误检率
minRadius: 10,
maxRadius: 60);
if (circles.Length > 0)
{
var target = circles.OrderBy(c => c.Center.DistanceTo(centerPoint)).First();
return new PointF(target.Center.X, target.Center.Y);
}
注意HoughCircles的参数2(param2)是个魔鬼参数。有次现场光照变化,这个值没调好,直接把工件旁边的螺丝孔识别成目标了,结果机械臂上演了一出"大力出奇迹",场面一度非常尴尬。

当运动控制遇上视觉反馈,坐标系对齐才是真正的修罗场。这个转换矩阵我刻在DNA里了:
// 像素坐标转机械坐标
public PointF PixelToWorld(PointF pixelPoint)
{
// 标定后的转换参数
double kx = 0.02; // mm/pixel
double ky = -0.02; // Y轴通常要取反
double offsetX = 325.4;
double offsetY = -287.1;
return new PointF(
(float)(pixelPoint.X * kx + offsetX),
(float)(pixelPoint.Y * ky + offsetY)
);
}
重点是这个ky的负号——相机安装方向不同会导致Y轴方向相反。有次学徒忘了这个负号,机械臂运动轨迹直接镜像反转,差点把传送带上的工件全扫到地上。

调试时强烈建议加上运动仿真模式。我通常会封装一个虚拟运动接口:
public interface IMotionController
{
void MoveTo(PointF target);
// 运行时切换真实/虚拟控制器
bool IsSimulation { get; set; }
}
// 虚拟实现
public class SimMotionController : IMotionController
{
public void MoveTo(PointF target)
{
Debug.WriteLine($"虚拟运动到 ({target.X:F2}, {target.Y:F2})");
Thread.Sleep(200); // 模拟运动耗时
}
}
这套机制至少帮我省了80%的调试时间——不用每次都真动设备,在工位上就能验证逻辑。特别是做视觉纠错逻辑时,可以快速模拟各种偏移情况。

最后说个血泪教训:运动控制线程和UI线程一定要分开!用BackgroundWorker太老套,现在推荐用async/await:
public async Task RunAlignmentAsync()
{
try
{
await Task.Run(() =>
{
// 运动控制代码
motion.MoveTo(homePosition);
var img = camera.Capture();
var pos = vision.FindTarget(img);
motion.MoveTo(pos);
});
}
catch (MotionTimeoutException ex)
{
// 处理超时
}
}
但注意!有些运动控制卡的API根本就不是线程安全的,这时候得加锁或者用Control.Invoke。之前遇到过随机出现的GTERRACCESS错误,最后发现是跨线程调用SDK函数导致的。
搞这类项目就像在钢丝上跳舞——既要保证实时性,又要处理各种异常。但看着机械臂按视觉定位精准抓取的那一刻,代码里的那些坑都值了。下次有机会再聊聊怎么用WPF做酷炫的3D运动监控界面,那又是另一个深坑...
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐

所有评论(0)