TS30/TS50 GeoCOM二次开发:状态机驱动的测量机器人通信协议实战
简介:本资源是徕卡TS30、TS50系列测量机器人Geocom二次开发的权威中文技术指南,面向测绘工程技术人员、自动化测量系统开发者及高校相关专业师生,解决Geocom接口理解难、协议调用不规范、C/C++与VBA跨语言开发适配等核心问题。文档为单个1.49MB的Word(.docx)文件,结构完整,覆盖GEOCOM使用背景、ASCII通信协议详解、数据类型定义、C/C++与VBA双语言函数调用协议、基础编程框架、典型程序示例及TPS1200仪器操作方式等关键模块,特别包含常见通信错误分析与编程提示,便于快速上手与排错。目前已有2426人学习下载,内容直击二次开发实操痛点——如自动数据采集与实时回传的程序实现逻辑、无需深入硬件即可调用底层功能的接口机制,以及如何基于ASCII协议构建稳定可靠的测量控制流程,是开展高精度工程测量定制化开发不可或缺的参考依据。
1. TS30/TS50测量机器人二次开发不是“调API”,而是把GeoCOM当通信黑匣子来驯服
你手上有台TS30或TS50,想让它自动照准棱镜、连续测角测距、把数据实时推到本地数据库——但打开官方SDK,满屏是COM_OpenPort、AUT_Search、BAP_MeasDistanceAngle这类函数,参数表里写着“double *pHz, double *pV, double *pDist”,却没告诉你pHz到底返回的是弧度还是度分秒字符串;调试时串口灯狂闪,仪器没反应,COM_GetLastError()只返回一个-127,查遍文档也找不到这个错误码对应哪条链路断了。这不是你代码写错了,是GeoCOM根本就不是标准RPC接口,而是一套带状态机的二进制+ASCII混合协议栈:它要求你先COM_Init(),再COM_OpenPort(),再CSV_GetInstrumentName()握手成功,最后才能调用AUT_Search()——漏一步,全链路静默失败。这份2019年发布的中文说明书,恰恰是目前全网唯一完整覆盖TS30/TS50系列GeoCOM全函数族、含C/VBA双语言范例、明确标注每个函数前置依赖和状态约束的实操手册。它不教你怎么写漂亮代码,只告诉你:在TS30上执行一次自动照准,必须按什么顺序调哪7个函数、每个函数返回值为多少才算进入下一阶段、超时该设几毫秒才不卡死仪器。适合正在做桥梁位移监测、大坝变形预警、工业机器人标定等需要高确定性控制的工程师,不适合只想“调个接口拿个数”的轻量用户。
2. GeoCOM不是SDK,是状态驱动的仪器通信协议:从ASCII到二进制的三层封装结构
GeoCOM常被误认为是徕卡提供的“C语言SDK”,实际它是一套协议抽象层:底层是RS232/USB虚拟串口上的原始字节流,中层是ASCII命令帧(如"GET:POS")或二进制RPC包,上层才是C/VBA函数封装。理解这三层,才能避开90%的通信失败。本章拆解其真实结构,并给出可验证的初始化脚本。
2.1 为什么COM_OpenPort()总返回-1?——串口参数必须与仪器固件硬匹配
TS30/TS50的串口不是即插即用设备。其波特率、校验位、停止位由仪器固件固化,不能通过软件协商。说明书第5章明确列出:
- 默认波特率:9600(TS30)或 115200(TS50,需确认固件版本)
- 数据位:8
- 校验位:None
- 停止位:1
- 流控:None
若用stty -F /dev/ttyUSB0 115200强行设错,COM_OpenPort()会静默失败(返回-1),且COM_GetLastError()仍为0——因为错误发生在物理层握手阶段,GeoCOM层尚未介入。正确做法是先用串口调试工具(如screen /dev/ttyUSB0 9600)发送GET:VER,看是否返回VER:TS30 V8.30。只有硬件层通了,再调COM_OpenPort()才有意义。
# 验证串口连通性的Linux命令(替换/dev/ttyUSB0为你的端口) stty -F /dev/ttyUSB0 9600 cs8 -cstopb -parenb -echo echo -ne "GET:VER\r\n" > /dev/ttyUSB0 # 等待2秒后读回显 timeout 2 cat /dev/ttyUSB0 | hexdump -C # 应看到类似"56 45 52 3a 54 53 33 30..."的ASCII响应提示:Windows下用PuTTY配置相同参数,发送
GET:VER(注意结尾\r\n)。若无响应,检查仪器是否处于“PC模式”(非测量模式),TS30需按FUNC + F4切换。
2.2 ASCII协议帧格式:不是HTTP,没有状态码,靠回车换行切帧
GeoCOM的ASCII协议本质是行协议(Line Protocol),每条命令以\r\n结尾,响应也以\r\n结尾。但关键细节在说明书3.2.1节:
- 命令帧最大长度:128字节(含
\r\n) - 响应帧无长度限制,但单行不超过256字节
- 空格敏感:
GET:POS有效,GET: POS(冒号后多空格)无效 - 大小写敏感:
get:pos会被忽略
这意味着你不能用通用HTTP库发请求,必须手写帧组装。下面是一个C语言安全发送函数:
// C语言安全发送ASCII命令(带超时和帧校验) int geo_send_ascii_command(int com_handle, const char* cmd) { char frame[130]; // 128字节命令 + \r\n int len = strlen(cmd); if (len > 126) return -1; // 超长截断 strcpy(frame, cmd); strcat(frame, "\r\n"); // 必须双字符结尾 // 发送前清空接收缓冲区(防旧数据干扰) COM_FlushInput(com_handle); // 实际发送(假设com_handle是GeoCOM句柄) int ret = COM_Write(com_handle, frame, strlen(frame)); if (ret != strlen(frame)) return -2; return 0; }逻辑说明:COM_Write()是GeoCOM底层写函数,参数com_handle来自COM_OpenPort()返回值;COM_FlushInput()必须在每次发送前调用,否则上次未读完的响应会混入本次解析——这是新手最常踩的坑,现象是GET:POS返回乱码,原因却是上一条SET:PRISM的响应还没读完。
2.3 二进制RPC协议:AUT_Search()背后是16字节结构体序列
当需要高性能(如高速跟踪),必须用二进制协议。说明书第4章指出:所有AUT_*、EDM_*函数均走二进制通道。以AUT_Search()为例,它不发字符串,而是发送一个16字节结构体:
| 字节偏移 | 含义 | 值示例 |
|---|---|---|
| 0-1 | 函数ID(小端) | 0x002A(AUT_Search固定ID) |
| 2-3 | 参数长度 | 0x0008(后续8字节参数) |
| 4-7 | 搜索中心Hz角(double,小端) | 0x40490FDB(≈50.0°) |
| 8-11 | 搜索中心V角(double,小端) | 0x40000000(≈2.0°) |
| 12-15 | 搜索窗口半宽(double,小端) | 0x3F800000(≈1.0°) |
若用ASCII方式调AUT_Search(),仪器会返回ERR:NOT SUPPORTED。必须用COM_SetBinaryMode(1)启用二进制模式后,再调用。而COM_SetBinaryMode()本身又必须在COM_OpenPort()之后、任何业务函数之前调用——这就是“状态驱动”的典型体现:协议栈有明确的状态机,跳步即失败。
3. C/C++与VBA双语言开发框架:为什么VBA在产线调试中反而更稳
说明书第3.3和3.4节分别给出C/C++与VBA的完整应用框架。很多人以为C性能高就该首选,但在TS30/TS50现场,VBA常因环境确定性高成为首选:Windows系统自带,无需部署VC++运行库,Excel可直接嵌入按钮触发测量流程。本章对比两种框架的核心差异,并给出可直接编译的C工程最小依赖清单。
3.1 C/C++框架:必须链接geocom.lib,且动态库路径要硬编码
说明书3.3.2节的“基本GeoCOM应用框架”隐含一个致命约束:geocom.dll(Windows)或libgeocom.so(Linux)必须与仪器固件版本严格匹配。TS30 V8.30固件只能用GeoCOM SDK v8.30,混用v9.x会导致COM_Init()崩溃。C工程最小可运行结构如下:
// main.c - TS30 C开发最小可运行示例 #include "geocom.h" // 官方头文件,定义所有函数原型 int main() { int hCom = 0; char errText[256]; // 1. 初始化GeoCOM(必须第一步) if (COM_Init() != 0) { COM_GetErrorText(-1, errText, 255); // -1表示最近错误 printf("COM_Init failed: %s\n", errText); return -1; } // 2. 打开串口(端口号需根据系统调整) hCom = COM_OpenPort("COM3", 9600); if (hCom <= 0) { COM_GetErrorText(COM_GetLastError(), errText, 255); printf("OpenPort failed: %s\n", errText); COM_Exit(); return -2; } // 3. 握手确认仪器在线(关键!) char instName[64]; if (CSV_GetInstrumentName(hCom, instName, 63) != 0) { printf("Instrument not responding!\n"); COM_ClosePort(hCom); COM_Exit(); return -3; } printf("Connected to: %s\n", instName); // 应输出"TS30" // 4. 执行测量(示例:单次角度距离测量) double Hz, V, Dist; if (BAP_MeasDistanceAngle(hCom, &Hz, &V, &Dist) == 0) { printf("Meas: Hz=%.6f°, V=%.6f°, Dist=%.3fm\n", Hz, V, Dist); } COM_ClosePort(hCom); COM_Exit(); return 0; }编译命令(Windows MinGW):
gcc -o ts30_test.exe main.c -L./lib -lgeocom -I./include参数说明:-L./lib指定geocom.lib所在目录;-lgeocom链接静态库;-I./include包含头文件。若漏掉-lgeocom,链接时报undefined reference to 'COM_Init'——这是C开发者最常遇到的“找不到函数”问题,根源是GeoCOM不提供头文件内联实现,所有函数都在.lib中。
3.2 VBA框架:Excel宏直接调用,但字符串传参有玄学陷阱
VBA优势在于调试直观:Excel单元格可实时显示Hz、V值,按钮一键触发。但说明书3.4.1节警告:VBA中所有字符串参数必须声明为String类型,且长度固定。例如CSV_GetInstrumentName的VBA声明:
' 正确声明(说明书3.4.2节示例) Public Declare Function CSV_GetInstrumentName Lib "geocom.dll" _ (ByVal hCom As Long, ByVal pName As String, ByVal nSize As Long) As Long Sub TestConnection() Dim hCom As Long Dim instName As String * 64 ' 必须用String * N,不能用Dim instName As String hCom = COM_OpenPort("COM3", 9600) If hCom > 0 Then If CSV_GetInstrumentName(hCom, instName, 63) = 0 Then MsgBox "Connected to: " & Trim(instName) ' Trim去除末尾\0 End If COM_ClosePort hCom End If End Sub现象→原因→解决:若用Dim instName As String(动态字符串),CSV_GetInstrumentName会写入内存越界,导致Excel崩溃。因为GeoCOM DLL期望接收一个固定长度的缓冲区地址,而VBA动态字符串地址在堆上,DLL写入时破坏堆结构。血泪经验:所有pName、pText类参数,必须用String * N声明,N至少比实际需要大1(留\0位置)。
3.3 开发环境选择决策树:什么时候该用C,什么时候该用VBA
| 场景 | 推荐语言 | 原因 |
|---|---|---|
| 产线自动化(PLC联动、MES集成) | C/C++ | 需要后台服务长期运行,避免Excel进程占用资源 |
| 现场快速验证(桥梁挠度初测) | VBA | Excel表格直接存原始数据,宏按钮一键启动,无需编译部署 |
| 高频测量(>10Hz采样) | C/C++ | VBA调用DLL有约15ms调度延迟,C可压到2ms内 |
| 多仪器集群控制(5台TS30同步) | C/C++ | VBA多线程支持弱,易出现串口句柄冲突 |
| 教学演示(学生实验) | VBA | 代码少、界面直观,学生能立即看到Hz/V值变化 |
注意:说明书第3.3.4节强调,C项目必须用
COM_SetTimeout()设置超时(默认0=无限等待),否则BAP_MeasDistanceAngle()在棱镜丢失时会永久阻塞。VBA中同理,但Excel会弹出“程序无响应”对话框,掩盖真实问题。
4. 避坑:TS30/TS50二次开发中5个让工程师凌晨三点还在抓头发的真问题
这些不是文档里写的“注意事项”,而是某高校实验室用TS30做大坝监测时,连续翻车两周总结出的硬核排错清单。每一条都对应一个具体现象、根本原因和可验证的解决步骤。
4.1 现象:AUT_Search()返回0但望远镜不动,AUT_GetFineAdjustMode()始终返回-1
原因:仪器ATR(自动目标识别)模块未激活,或棱镜类型未正确设置。AUT_Search()只负责搜索,不负责开启ATR。
解决:
- 先调
AUS_GetATRState()确认ATR状态(0=关闭,1=开启) - 若为0,调
AUS_SetATRState(1)开启 - 再调
BAP_SetPrismType(1)设置棱镜类型(1=标准棱镜,2=微型棱镜) - 最后调
AUT_Search()
验证:开启ATR后,仪器目镜中应看到红色十字线自动收缩聚焦。若无,检查棱镜是否清洁、光照是否过强。
4.2 现象:COM_OpenPort()成功,但CSV_GetInstrumentName()返回-127
原因:说明书第3.7节“常见通信错误”明确:-127= “仪器未进入PC通信模式”。TS30/TS50有独立的通信模式开关。
解决:
- TS30:按
FUNC + F4,屏幕显示PC MODE ON - TS50:按
MENU → SYSTEM → COMMUNICATION → PC MODE - 若仍失败,在PC模式下长按
POWER键3秒重启仪器
提示:某些固件版本要求PC模式下必须连接USB线(非RS232),否则拒绝响应。
4.3 现象:VBA中BAP_MeasDistanceAngle()返回0,但Hz、V值为极小浮点数(如1.2e-38)
原因:VBA变量未初始化,且GeoCOM未写入有效值。说明书3.4.4节提示:所有double *参数必须预先赋值,否则DLL可能不覆盖内存。
解决:
Dim Hz As Double, V As Double, Dist As Double Hz = 0: V = 0: Dist = 0 ' 强制初始化! If BAP_MeasDistanceAngle(hCom, Hz, V, Dist) = 0 Then ' 此时Hz/V/Dist才可信 End If4.4 现象:C程序中COM_Write()返回字节数正确,但仪器无响应
原因:未发送\r\n结尾,或发送了\n(Unix换行)而非\r\n(DOS换行)。说明书2.3.1节强调ASCII协议必须\r\n。
解决:
- 用十六进制编辑器检查发送缓冲区:
0D 0A(即\r\n)必须存在 - 在C中强制使用:
sprintf(buf, "%s\r\n", cmd); - Linux下用
echo -ne "CMD\r\n"测试,勿用echo "CMD"(自动加\n)
4.5 现象:EDM_Laserpointer(1)开启激光指针,但目镜中无红点
原因:激光指针功能受仪器安全等级限制。说明书12.4.1节注明:仅当仪器处于LEVEL 1(最低安全等级)时可用。
解决:
- 调用
CSV_GetSecurityLevel()获取当前等级(0=LEVEL 1,1=LEVEL 2) - 若为1,需物理操作:关机→按住
F1开机→进入服务菜单→将安全等级设为0 - 重启后
EDM_Laserpointer(1)才生效
血泪经验:某公司因未降安全等级,调试3天以为激光模块坏了,最后发现是固件锁。
5. 自动化测量全流程实战:从初始化到数据落库的7步不可跳过动作
用TS30做边坡位移监测时,一个完整的自动化周期不是“调一次AUT_Search()”,而是包含仪器唤醒、模式切换、参数预置、搜索、测量、数据处理、休眠的闭环。说明书第7章(AUT)、第8章(BAP)、第11章(CSV)共同构成此流程。本章给出可直接复用的C语言状态机伪代码,并标注每个动作的超时阈值——这些数值来自某跨平台系统实测,非理论值。
5.1 7步状态机:为什么第3步必须是CSV_SetDateTime()
| 步骤 | 动作 | 超时 | 为什么必须 |
|---|---|---|---|
| 1 | COM_OpenPort()+CSV_GetInstrumentName() | 3000ms | 确认物理链路和仪器型号 |
| 2 | CSV_GetSecurityLevel()+ 必要时降级 | 1000ms | 避免后续EDM_*函数被拒 |
| 3 | CSV_SetDateTime() | 500ms | 关键!TS30固件bug:若系统时间与仪器时间差>5分钟,AUT_Search()概率性失败 |
| 4 | BAP_SetPrismType(1)+BAP_SetEDMMode(2) | 800ms | 预置棱镜和测距模式,避免测量中切换 |
| 5 | AUT_Search()+AUT_FineAdjust() | 8000ms | 搜索耗时最长,需足够超时 |
| 6 | BAP_MeasDistanceAngle()× 3次取平均 | 3000ms | 单次测量易受抖动影响 |
| 7 | COM_ClosePort()+COM_Exit() | 200ms | 清理资源,为下次启动准备 |
// C语言状态机核心逻辑(简化版) typedef enum { INIT, SET_TIME, CONFIG, SEARCH, MEASURE, DONE } State; State current_state = INIT; int hCom = 0; while (current_state != DONE) { switch(current_state) { case INIT: hCom = COM_OpenPort("COM3", 9600); if (hCom > 0 && CSV_GetInstrumentName(hCom, name, 63)==0) { current_state = SET_TIME; COM_SetTimeout(hCom, 3000); // 全局超时设3秒 } break; case SET_TIME: // 获取PC时间并同步到仪器 time_t now = time(NULL); struct tm *t = localtime(&now); if (CSV_SetDateTime(hCom, t->tm_year+1900, t->tm_mon+1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec) == 0) { current_state = CONFIG; } break; case CONFIG: BAP_SetPrismType(hCom, 1); // 标准棱镜 BAP_SetEDMMode(hCom, 2); // 精密模式 current_state = SEARCH; break; case SEARCH: COM_SetTimeout(hCom, 8000); // 搜索阶段超时加长 if (AUT_Search(hCom) == 0 && AUT_FineAdjust(hCom) == 0) { current_state = MEASURE; } break; case MEASURE: double Hz[3], V[3], Dist[3]; for(int i=0; i<3; i++) { BAP_MeasDistanceAngle(hCom, &Hz[i], &V[i], &Dist[i]); Sleep(200); // 间隔200ms防抖 } // 计算平均值并存入数据库... current_state = DONE; break; } } COM_ClosePort(hCom); COM_Exit();参数说明:COM_SetTimeout()在每步前重设,因不同操作对实时性要求不同;Sleep(200)是经验值,TS30机械臂响应时间约180ms,间隔太短会导致BAP_MeasDistanceAngle()返回ERR:BUSY。
5.2 数据落库技巧:用BMM_BeepAlarm()做测量完成哨兵
说明书第9章BMM_*函数常被忽略,但它提供了一个低成本的硬件反馈机制。在无人值守监测中,BMM_BeepAlarm()(三声短鸣)可作为“本次测量完成”的物理信号,配合录音笔或手机APP,实现离线审计。某地质勘探队用此法,在无网络山区记录了237次有效测量,误差率0%——因为每次三声后必有数据入库,无声则重试。
// 测量完成后触发声响反馈 if (current_state == DONE) { BMM_BeepAlarm(hCom); // 仪器发出三声“嘀嘀嘀” // 此时可安全认为数据已采集完毕,开始写数据库 save_to_sqlite(Hz_avg, V_avg, Dist_avg); }从那以后我每次部署TS30自动化脚本,都强制在
DONE状态后加BMM_BeepAlarm(),并用手机录下声音。去年某次暴雨导致供电中断,恢复后听录音发现第142次测量无声,立刻知道那次数据丢了,不用翻日志——希望帮到你。
本文还有配套的精品资源,点击获取