news 2026/10/11 5:16:47

C#上位机集成海康相机、雷赛运动控制卡与数据库实战解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C#上位机集成海康相机、雷赛运动控制卡与数据库实战解析

简介:面向工业视觉与运动控制场景的C#工程源码包,整合海康相机取像识别、雷赛运动控制卡联动与数据库上传查询,适合需要完成设备ID追溯与产线信息化的上位机开发、调试人员参考学习。压缩包共205个文件,约22.98MB,以39个C#源文件及界面资源为主,辅以6个DLL、4个config配置、6个TXT说明、2个可执行程序;另有59个dmp调试转储文件,便于追溯程序崩溃现场,降低排查门槛。已有102人学习下载。项目覆盖芯片数字识别、运动控制交互、ID写库与数据库查询模块,涉及相机触发、运动定位、图像识别、数据落库等完整链路;源码目录结构清晰,配pdb符号、resx界面资源、xml配置及运行日志,可帮助理解界面布局、调用关系与排错思路,适合作为联合开发模板直接复用到类似产线项目,减少重复搭建成本。

1. 一份zip里的C#上位机:相机、运动控制卡和数据库到底怎么交接?

C#联合海康相机、雷赛运动控制卡,识别ID并上传数据库——看到这个zip名字,一线的工程师基本能猜出里面装的是什么:一套典型的上位机骨骼,把工业相机、运动控制卡和数据库串在同一个程序里。产线上的场景通常是:工件被送到工位,雷赛控制卡把产品顶到相机正下方,海康相机拍下二维码,C#解析出ID,再把ID、时间和工位号写进数据库。下面我就沿着这套流程,把做这类上位机的拆解、实现和踩坑记录整理出来。适合正在做设备上位机、刚接手视觉集成项目的朋友,也适合准备C#上位机方向的人,手里缺一套完整闭环参考。

2. 先定骨架:海康SDK、雷赛控制卡和数据库在C#里怎么相处

这类项目最大的问题不是某一个SDK不会调,而是三个SDK挤在一个进程里互相抢时间片。我一般会在动手写界面前先画一张模块图:相机负责拿图,运动控制卡负责让产品到位,数据库负责记录,中间用C#做调度。每个模块独立成类,不要在一个Form里堆事件。

2.1 模块划分:为什么把取流、运动、写库拆成三个类

为什么拆?因为海康SDK的回调线程和雷赛DMC库的中断都可能随时被触发,如果相机回调里去查数据库,一个网络抖动就会让采集线程卡住,紧接着丢帧。拆开后,每个类只做一件事,出错时日志也容易定位。

我习惯定义三个核心类:

  • CameraService:封装设备枚举、开流、注册回调、停止。
  • MotionService:封装控制卡初始化、轴运动、IO输出。
  • TraceService:封装数据库连接、写入、重试。

界面层只负责把这三个类的返回值组合起来。这样换相机或换控制卡时,只动对应类,不影响另外两个。对于C#上位机方向的人来说,这种分层也是在设计层面应该最先解决的问题。WinForms还是WPF都可以,核心是逻辑不要和控件耦合。我的做法是让界面事件只做一件事:把指令发给后台线程,后台线程通过事件把结果抛回UI线程。这样即使SDK回调线程和UI线程冲突,也只是能在界面看到“等待中”,不会直接崩掉。

2.2 SDK版本与C#封装:海康MVS和雷赛DMC的调用方式

海康工业相机目前主流的C#例程是MVS SDK里的MvCameraControl.Net,底层通过DllImport封装C++接口。打开相机、注册回调、抓图,都有对应的托管接口。需要注意的坑:MVS的32位和64位运行时不能装混,C#工程目标平台必须是x64,绝大多数工控机是x64,否则会出现“无法加载DLL”的经典问题。

雷赛运动控制卡则很少提供纯C#的SDK,常见做法是把厂商给的DMC动态库用DllImport自己封装一遍。雷赛DMC系列的接口通常以dmc_为前缀,调用约定采用StdCall。初始化板卡、设置脉冲模式、写DO、读DI,都需要在一份静态类里声明。

public static class RishonDmcWrapper { // 这里以DMC系列常见接口示意,函数名以随卡头文件为准 [DllImport("dMC3000.dll", CallingConvention = CallingConvention.StdCall)] public static extern Int32 dmc_board_init(); [DllImport("dMC3000.dll", CallingConvention = CallingConvention.StdCall)] public static extern Int32 dmc_set_axis_pulse(Int32 cardId, Int32 axis, Int32 mode, Int32 polarity); [DllImport("dMC3000.dll", CallingConvention = CallingConvention.StdCall)] public static extern Int32 dmc_dopulse(Int32 cardId, Int32 axis, Int32 pulseCount, Int32 speed, Int32 acc, Int32 dec); }

DllImport里的dll名称、入口点必须和随卡SDK匹配,不能凭记忆猜测。我第一次做雷赛时把入口点名写错,编译没问题,运行时一调用就抛EntryPointNotFoundException。解决的办法是打开SDK头文件,逐个核对函数名和参数,不要靠IDE的智能提示。

数据库层的封装相对简单,选择SQL Server还是MySQL根据现场IT环境定。我倾向于用Dapper做轻量封装,因为这类上位机通常只有几张表,不需要引入重量级ORM。连接串里设置Pooling=true,避免频繁建连。用C#高级编程里的async/await时要注意,异步数据库操作不要躲在同步上下文里,不然会出现SynchronizationContext死锁,这在WinForms里很常见。

2.3 线程模型与消息队列:别在相机回调里直接跑运动控制

这是整个架构里最重要的一条规则:相机回调是硬实时线程,不能放任何可能阻塞的逻辑。识别二维码、访问数据库、控制雷赛,这些都必须把数据“扔”到另一个线程去做。

我的做法是使用ConcurrentQueue + 信号量组成一个简单的生产消费者队列。相机回调只做一件事:把图像封装成对象,然后入队。消费者线程负责解码、运动判断、写库。

public class FrameQueue { private readonly ConcurrentQueue<FrameData> _queue = new ConcurrentQueue<FrameData>(); private readonly AutoResetEvent _signal = new AutoResetEvent(false); public void Enqueue(FrameData frame) { _queue.Enqueue(frame); _signal.Set(); // 通知消费者有新的帧 } public bool TryDequeue(out FrameData frame, int timeoutMs) { WaitHandle.WaitAny(new[] { _signal }, timeoutMs); return _queue.TryDequeue(out frame); } }

入队后消费者线程循环调用TryDequeue,超时时间设为200ms,避免空转把CPU占满。为什么超时而不是无限等待?因为生产者偶尔停止时,消费者还可以去检查心跳和IO状态,防止整个流程“死静”。

线程间的UI更新也要小心。识别结果回到界面时,不能直接在消费者线程里操作TextBox,需要调用Control.BeginInvoke。我见过很多因为用了Invoke同步等待UI线程,导致回调线程和UI线程互相等待的案例,表现是程序卡死,只有关掉窗口进程才能退出。所以统一用BeginInvoke,不仅不会死锁,响应也更流畅。

骨架定了,后面的相机取流、雷赛运动和数据库操作都是往这三个类里填实现。

3. 海康相机抓拍与ID识别:从像素到字符串的完整链路

3.1 最小取流配置:枚举设备、开流、注册回调

海康MVS的上位机例程虽然多,但最小闭环其实就那么几步:枚举相机、打开设备、设置采集参数、注册回调、开始取流。下面的代码是我在MVS工程里整理出来的最小配置,SDK版本更新后部分方法名可能带MV_CC_前缀,以随包文档为准。

MvCamera device = new MvCamera(); // 枚举设备,取第一个网口相机 List<MvCameraInfo> deviceList = device.EnumDevices(); if (deviceList.Count == 0) throw new Exception("未找到海康相机"); device.Open(deviceList[0]); // 触发模式:0=连续,1=软触发,2=硬触发 device.SetEnumValue("TriggerMode", 1); // 调试阶段先用软触发 device.SetEnumValue("TriggerSource", 0); // 0=软件触发 device.SetEnumValue("PixelFormat", "Mono8"); // 灰度图,读码够用 device.SetFloatValue("ExposureTime", 5000f); // 曝光时间,单位us // 注册回调并开始取流 device.RegisterImageCallback(OnCameraImage); device.StartGrabbing();

代码背后的逻辑是:先把相机配置成需要的图像格式和曝光,再注册回调。PixelFormat选Mono8能减少一半以上的数据量,读二维码和一维码都足够;如果产线上需要识别彩色码,再换成BGR8。ExposureTime要根据产线节拍调整,静止抓拍一般2000~8000us,运动抓拍要缩短到500us以下并且配合光源。SetEnumValue的取值在不同固件版本里可能有差异,最好打开MVS调试工具,看属性树里实际枚举值。

在回调里,图像数据需要转成OpenCVSharp的Mat,否则后续识别不方便。这里有一个关键点:ConvertToMat是轻量操作,可以放在回调里;但识别算法不能放在这里,否则会拖垮采集线程。我们3.2节再展开。

3.2 识别ID的三种做法:读码、OCR、图像处理

识别ID在大多数上位机里就是读二维码或一维码,返回一串字符。业内常见做法有三种。

第一种是海康机器视觉SDK自带的读码工具。如果你的MVS版本开放相应算法库,可以直接调用,好处是不需要额外依赖,坏处是不同机型/固件能力差异大,不一定所有现场都支持。我不建议一上来就依赖它,先用通用开源库把流程跑通再说。

第二种是OpenCVSharp的QRCodeDetector,适合二维码。代码很短:

public string DecodeQrCode(Mat gray) { QRCodeDetector detector = new QRCodeDetector(); Point2f[] corners; string text = detector.DetectAndDecode(gray, out corners); // 返回null表示没解出来 return string.IsNullOrEmpty(text) ? null : text.Trim(); }

第三种是ZXing.Net,对一维码和二维码兼容性好,尤其适合Code128、EAN、DataMatrix这类一维/二维混合场景。ZXing吃的是Bitmap,不是Mat,所以要先转一下。很多C# OpenCVSharp的例子里都会写一个BitmapConverter.ToBitmap,实际上ZXing在Net Standard 2.0下也能直接用:

public string DecodeBarCode(Mat gray) { using (var ms = new MemoryStream()) { Bitmap bmp = BitmapConverter.ToBitmap(gray); var reader = new BarcodeReaderGeneric(); Result result = reader.Decode(bmp); return result?.Text; } }

两种算法在调用前都建议先对图像做预处理。工业现场最常见的是对比度不够和反光,我一般先转灰度,再做一次3x3中值滤波或高斯滤波。中值滤波去椒盐噪点效果好,高斯滤波去环境噪声效果好,具体用哪个可以A/B对比一下,没有定式。

如果ID不是码,而是打印在工件上的数字字符,就要用OCR。C#侧可以用Tesseract的NuGet包,或者PaddleOCR的C#推理接口。OCR的精度完全依赖样本,批量测试时要把字符倾斜、笔画残缺、光照变化这些情况都覆盖到,否则上线会不断翻车。我的建议是:能用读码解决的就不上OCR,OCR只处理无法打印条码的场合。

3.3 参数调优:曝光、触发模式、识别ROI

读码失败不是玄学,基本都是以下几个参数没配合好。我习惯把参数列成一张表,每次调试都按表调。

参数推荐值作用
曝光时间3000~8000us调节整体亮度,运动场景缩短
增益尽量低增益高会让噪点增加,读码失败率上升
ROI只保留码区域减少处理时间,排除背景干扰
二值化阈值自适应光照变化时用自适应阈值更稳

ROI可以用海康SDK的参数设置,也可以把相机回调拿到的Mat先裁剪再识别。注意ROI不能裁太死,二维码/条码的边缘一旦被切掉,解码必然失败。我一般让ROI比码的实际范围四周各大20~30像素,这样产品在工位上有一点位置偏移也仍然能读到。

曝光和增益的配合有一个原则:先调曝光,曝光不够再加光源,最后才考虑增益。增益是备选方案,不是优先项,因为增益放大了信号的同时也放大了噪点。还有一个小技巧:把相机设置为固定的手动曝光,不要用自动曝光。自动曝光在产线上会因为工件颜色变化而波动,导致同一条码时而过曝时而偏暗,识别率忽高忽低。

4. 雷赛运动控制卡联动:让相机在正确的时间看到正确的ID

4.1 初始化运动控制卡和轴参数

雷赛控制卡的初始化比相机要直接:打开设备、设置脉冲输出模式、设置速度和加减速。常见做法是把DMC动态库的常用函数封装到一个静态类里,然后在一个后台任务中初始化。

int cardId = 0; // 初始化板卡,返回0表示成功 int ret = RishonDmcWrapper.dmc_board_init(); if (ret != 0) throw new Exception("雷赛控制卡初始化失败"); // 设置轴0脉冲模式:0=脉冲+方向,极性0=正脉冲 RishonDmcWrapper.dmc_set_axis_pulse(cardId, 0, 0, 0); // 设置速度、加速度和减速度 RishonDmcWrapper.dmc_set_axis_speed(cardId, 0, 1000, 500, 500);

参数说明:脉冲模式必须和驱动器拨码一致,如果是差分信号或集电极开路,模式参数不同,错了电机就不动或方向反。速度单位是pps,也就是脉冲/秒。比如驱动器细分设置为2000脉冲/转,那么1000pps就是每秒转半圈,具体对应多少毫米要按机械减速比换算。加速度和减速度是同样的单位,值太小导致响应慢,值太大容易机械振动。

初始化后的第一件事不是直接跑流程,而是做一次回零或者复位操作。运动控制卡上电后轴位置可能不在已知点,直接绝对定位会撞机。回零完成后,再设置当前坐标为零点,后续运动才有意义。很多新手容易忽略这一步,结果一上电就飞车。

4.2 IO触发拍照:硬件触发比软件延时稳一个量级

先把结论放在这里:如果视觉系统和运动系统是同一套设备,尽量用运动控制卡的IO输出直接触发相机硬件触发,不要用上位机软件在运动到位后发指令拍照。软件延时的误差受Windows线程调度影响,可能波动几十毫秒,而产线节拍往往经不起这个波动。

我的接线方式是:雷赛控制卡的DO0接到海康相机的Line0,相机的TriggerSource设置为硬件触发,TriggerSource选择Line0。运动到位后,控制卡输出一个短脉冲,相机自己开始曝光。这样触发时机由运动卡保证,和上位机线程调度无关。

// 移动到拍照位,绝对定位 RishonDmcWrapper.dmc_dopulse(cardId, 0, 12000, 1000, 500, 500); // 等待到位:读取轴状态,1表示运动中 while (RishonDmcWrapper.dmc_get_axis_status(cardId, 0) == 1) { Thread.Sleep(1); } // DO0输出50ms高电平,接到相机触发输入端 RishonDmcWrapper.dmc_write_do(cardId, 0, 1); Thread.Sleep(50); RishonDmcWrapper.dmc_write_do(cardId, 0, 0);

代码里的等待到位很重要。如果不等轴停稳就触发,工件还在振动,拍出来的图是糊的,识别率会直线下降。DO输出时间太短,光电隔离可能还没饱和;时间太长,相机可能收到多个上升沿,从而重复触发。50ms是我常用的起点,实际可以通过示波器看波形再调整。如果相机支持下降沿触发,DO反接一下也是一个办法。

硬件触发配好后,相机端会看到帧率完全由外部IO控制。调试时可以用MVS的取流工具直接看触发信号是否正常,如果相机画面没有变化,先去查触发线和GND,再去查TriggerMode设置。

4.3 运动到判断结果:分拣/剔除的实现

识别结果出来之后,运动控制卡要根据ID是否读取成功决定是放行还是剔除。这个判断不能在相机回调里做,应该通过消息队列把结果交给运动线程。我的做法是在MotionService里暴露一个结果属性,运动线程在执行“等待放行/剔除”动作时去读这个属性。

// 消费者线程 while (true) { FrameData frame; if (frameQueue.TryDequeue(out frame, 200)) { string id = DecodeQrCode(frame.Gray); bool ok = !string.IsNullOrEmpty(id); // 通知运动线程:识别结果已产生 motionService.SetJudgement(ok); } motionService.ProcessPending(); }

MotionService内部会维护一个bool字段,用锁或Interlocked保护。ProcessPending方法会检查当前是否处于等待判定的状态:数控系统在工件到位后,先发起拍照,然后阻塞在“等待结果”信号上。消费者线程把解码结果写入后,运动线程被唤醒,决定下一步是走到放行位还是剔除位。这样做的好处是,即使识别耗时偶尔波动,运动的等待逻辑也不会乱套。

这种“识别结果异步送达”的模式也是这个zip里最值得复用的部分。如果直接把识别放在运动到位后的同步调用里,每个工件的节拍会被最慢的一次识别拖累,整体产能直接下降。

5. 把识别ID上传数据库:事务、防重和掉线恢复

5.1 选SQL Server还是MySQL:连接串与批量写入

上位机数据库选型没有绝对,SQL Server在工厂MES系统里偏多,MySQL胜在轻量且社区资料多。关键是要把连接串和连接池配置好。下面是我常用的两组连接串,注意Password要放在配置文件里,不要硬编码进代码。

-- SQL Server Server=192.168.1.50;Database=MES;User Id=sa;Password=****;Pooling=True;Min Pool Size=5;Max Pool Size=50; -- MySQL Server=192.168.1.50;Database=MES;User Id=mes;Password=****;CharSet=utf8;Pooling=True;

数据库同步是这类设备最常见的痛点了。上位机和MES数据库同步时,最怕的就是频繁建连接,所以Pooling必须开。Min Pool Size设5,可以让程序启动时预热连接池,避免产线一开工就卡在第一次建连上。MySQL连接串里的CharSet=utf8也是必须的,不然中文写入后会变成乱码,这是血泪经验。

批量写入时,我一般用Dapper加事务。Dapper的Execute传入List会展开成多条命令,但都在事务里,要么全成要么全回滚。

public void SaveTrace(List<DbRecord> list) { using (var conn = CreateConnection()) { string sql = @" INSERT INTO ProductTrace (ProductCode, ProcessCode, Result, CaptureTime) VALUES (@ProductCode, @ProcessCode, @Result, @CaptureTime);"; using (var tx = conn.BeginTransaction()) { conn.Execute(sql, list, transaction: tx); tx.Commit(); } } }

批量写不是因为性能,而是为了保证一致性。如果一条记录失败,整个批次回滚,程序可以通过日志重试,不会把“半个批次”写入库。到这个项目的数据量级别,不需要考虑分库分表,事务一致性才是第一优先。

5.2 防重设计的核心:唯一索引与ID+工序联合幂等

重复写入是这类上位机最容易出现的数据污染。相机可能因为机械抖动对同一工件拍了两次,网络重试也可能把同一条消息发两次。如果数据库里留下两笔一样的ID+工序记录,后期追溯会误判成两个产品。

解决方式是在数据库里加唯一约束:

ALTER TABLE ProductTrace ADD CONSTRAINT UQ_ProductProcess UNIQUE (ProductCode, ProcessCode);

然后在写入语句里用幂等写法。SQL Server用MERGE,MySQL用ON DUPLICATE KEY UPDATE。我以SQL Server为例:

MERGE ProductTrace AS t USING (SELECT @ProductCode AS ProductCode, @ProcessCode AS ProcessCode, @Result AS Result, @CaptureTime AS CaptureTime) AS s ON t.ProductCode = s.ProductCode AND t.ProcessCode = s.ProcessCode WHEN MATCHED THEN UPDATE SET Result = s.Result, CaptureTime = s.CaptureTime WHEN NOT MATCHED THEN INSERT (ProductCode, ProcessCode, Result, CaptureTime) VALUES (s.ProductCode, s.ProcessCode, s.Result, s.CaptureTime);

这段SQL的逻辑是:存在就更新,不存在就插入。这个幂等设计是数据库层的兜底,即使上位机逻辑漏了,数据库也会把数据合并而不是多插。ProcessCode表示工序编号,比如“贴标01”“焊接02”,同一次识别的ID和工序组合是唯一的。

注意:MERGE在并发极高时会有锁问题,但上位机识别的节拍一般也就几秒一次,完全够用。如果现场要求更高,可以在应用层再加一个请求锁,不过我目前没有遇到必须做的程度。

5.3 异常与重试:数据库连接打断时怎么排队补传

产线网络不是永远稳定,数据库服务器重启、网线松动、防火墙策略调整,都会让写入失败。最关键的是:写库失败不能阻塞相机采集和运动控制,否则整条线都会停下来。我采用内存重试队列,独立线程负责写库。

private BlockingCollection<DbRecord> _retryBuffer = new BlockingCollection<DbRecord>(boundedCapacity: 1000); private void DbWriteWorker() { while (!_retryBuffer.IsCompleted) { DbRecord rec; if (_retryBuffer.TryTake(out rec, TimeSpan.FromSeconds(2))) { try { SaveTrace(rec); // 单条写入 } catch (Exception ex) { rec.RetryCount++; // 最多重试5次,超出后写入本地日志 if (rec.RetryCount < 5) _retryBuffer.Add(rec); else File.AppendAllText("db_error.log", ex.ToString()); } } } }

boundedCapacity=1000很关键。如果数据库断连超过几分钟,重试队列会堆积,生产者往队列里Add时会被阻塞,这相当于一个背压机制:相机和运动不会被无限拖死,但也不会让内存无限制增长。如果队列满到阻塞了识别流程,那说明数据库已经不是暂时抖动,而是长期故障,这时候应该停线检查,而不是继续空转。

重试次数我通常设5次,每次间隔用指数退避会更好,但简单的加时间戳再重试也够用。这里有一个容易忽略的细节:写入失败时,可能数据库端已经写成功了,但网络断开导致返回超时。这时候重试会触发重复更新,但5.2节里的唯一索引和MERGE幂等逻辑会兜住,不会插成两行。这就是为什么防重必须做在数据库层,应用层永远无法保证不重发。

6. 联调避坑:从丢帧到写库失败的五类翻车现场

6.1 相机回调里做识别导致丢帧

现象:MVS回调每来一帧就跑一次二维码识别,帧率从30掉到12,画面一卡一卡。 原因:识别耗时50~100ms,回调线程被占用,SDK来不及取下一帧,缓冲区满就丢帧。 解决:回调里只做ConvertToMat和入队,识别全部放到消费者线程。改完后回调用时控制在5ms以内,帧率恢复正常。

6.2 雷赛IO触发和海康外触发没共地

现象:硬件触发方式下,相机偶尔不触发,触发线一长甚至完全没反应。 原因:雷赛的DO和相机触发输入没有统一GND,两端电源地电位不同,信号电平不确定。 解决:把雷赛的GND端子、相机触发GND、开关电源GND接在一起,信号线用屏蔽双绞线,屏蔽层单端接地。这个不改,后面排查会浪费大量时间。

6.3 数据库写入阻塞UI线程

现象:连续识别很多ID后,界面卡死,鼠标都移动困难。 原因:在识别线程里直接调用SqlClient.ExecuteNonQuery,数据库网络超时等待30秒,识别线程堵住,UI线程通过事件等待也一起被拖住。 解决:数据库写入走独立线程和重试队列,UI线程只通过BeginInvoke接收结果。异步写库以后,即使数据库断了,界面依然可以操作。

6.4 识别ID时好时坏:ROI和焦距的坑

现象:二维码中心和边缘的识别率差异大,换一箱产品后识别率骤降。 原因:ROI裁得太靠近码边缘,产品位置稍有偏移就切掉部分码;镜头手动对焦没锁紧,温度变化后焦平面漂移。 解决:ROI四周留20%以上边距;镜头对焦后锁紧螺丝;曝光时间固定,不要自动曝光。上线前把一张标准码贴在工装件上反复测试,直到识别率稳定。

6.5 一个最小自检流程:让系统上线前跑24小时

我每套设备上线前都会写一个自检脚本,统计相机帧率、解码成功率、数据库写入条数和重试次数。连续24小时高低温老化,如果解码成功率低于99.5%,就去查光源和焦距;如果数据库重试次数不为0,就去查网络和连接池。这样可以把联调里的玄学问题转成数据问题,也能在交付前把雷赛和相机的信号干扰提前暴露出来。这个习惯帮我挡掉了很多次产线半夜的求助电话,希望帮到你。

本文还有配套的精品资源,点击获取

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

智能体工程化实践:Sub-Agent角色分工与Skills能力封装

1. 项目概述&#xff1a;这不是在搭积木&#xff0c;而是在构建可演化的智能体组织架构“Sub-Agents 角色分工与 Skills 能力封装&#xff1a;角色、权限、技能包与 V1 知识库跑通”——这个标题里没有一个词是虚的&#xff0c;每个词都对应着当前智能体&#xff08;Agent&…

作者头像 李华
网站建设 2026/10/11 5:14:50

【动态规划-6】96.不同的二叉搜索树

题目描述&#xff1a;给你一个整数 n &#xff0c;求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种&#xff1f;返回满足题意的二叉搜索树的种数。示例 1&#xff1a;输入&#xff1a;n 3 输出&#xff1a;5示例 2&#xff1a;输入&#xff1a;n 1 输出…

作者头像 李华
网站建设 2026/10/11 5:14:43

具身智能创新原理(总论):TVA-World创新具身架构内涵与原理

前沿技术探索&#xff1a;TVA智能体&#xff08;简称TVA&#xff09; TVA智能体&#xff08;亦称“AI智能体视觉”&#xff09;是依托Transformer架构与“因式智能体”理论构建的新型工业视觉系统&#xff0c;也是当前最具代表性的具身视觉技术之一。它有机融合深度强化学习&a…

作者头像 李华
网站建设 2026/10/11 5:11:21

霜钻连续三年荣登《亚洲品牌500强》

2026年9月20日第21届亚洲品牌盛典在香港举办&#xff0c;同期发布亚洲品牌500强榜单。中国高端院线护肤品牌霜钻第三次荣膺亚洲500强品牌&#xff0c;位列第370位&#xff0c;排名相比上年大幅跃升68位&#xff0c;品牌价值突破230亿元&#xff0c;与华为、抖音、丰田、三星等品…

作者头像 李华