用 Qt 控制 Nikon 显微镜的电动物镜转盘

news/2024/10/30 13:33:14/

用 Qt 控制 Nikon 显微镜的电动物镜转盘

最近的一个项目,用到了一台 Nikon 的金相显微镜,并且配了个电动的物镜转盘。为了控制这个电动物镜转盘,我折腾了差不多有4-5天。中间遇到了各种问题,还好,最后都解决了。这里简单纪录了我遇到的各种问题,希望对其他人能有有所帮助。

我的开发环境如下:

win 7 64位操作系统。
qt 5.4.1(32位) + vs2010
Nikon 的物镜转化器通过 USB 接口连接到我的硬件平台。

Nikon 这样的大厂还是比较靠谱的,提供有 LV Series Software Developer’s Kit (SDK)。因为我的操作系统是 64 位的,所以我要了 64 位的 SDK。 要来了 SDK 后发现,Nikon 将他显微镜所有的控制功能都封装到了一个 ActiveX 控件里。它 64 位的 SDK 就只提供了 64 位的 ActiveX 控件。第一个悲剧出现了,我 32 位的应用程序用不了这个 64 位的控件。当然主要还是我水平低,理论来说 ActiveX 控件是可以跨系统调用的,32 位程序用 64 位控件肯定是有办法的。

因为我对 ActiveX 技术了解的太少,这么点小事就折腾了 2 天。后来明白了原因之后又去找 Nikon 要 32 位的 SDK。最后我两个 SDK 都要用到,使用 64 位 SDK 里的 USB 驱动,32 位 SDK 的 COM 组件。

SDK 都准备齐了之后开始写程序。Qt 里有一个模块叫做 “Active Qt”,提供了对 ActiveX 和 COM 组件的支持。这个 “Active Qt” 还是很给力的。用 QAxObject 类就可以访问 COM 组件中的对象。

比如:

    QAxObject *nikon = new QAxObject(parent);nikon->setControl("Nikon.LvMic.NikonLV");

等价于 VBScript 脚本:

dim nikonLV
set nikonLV = CreateObject ("Nikon.LvMic.NikonLV")
    QAxObject* nosepiece = nikon->querySubObject("Nosepiece");

就可以获取子对象 “Nosepiece”。到这里都很顺利。

SDK 中 VBScript 语言写的旋转物镜转盘的例子是这样的:

Public Const StatusUnknown = -1
Public Const StatusFalse = 0
Public Const StatusTrue = 1dim nikonLV
set nikonLV = CreateObject ("Nikon.LvMic.NikonLV")If (nikonLV.Nosepiece.IsMounted = StatusTrue) ThennikonLV.Nosepiece.Forward
End If

我仿照着写的 Qt 代码如下:

    QAxObject *nikon = new QAxObject(parent);nikon->setControl("Nikon.LvMic.NikonLV");QAxObject* nosepiece = nikon->querySubObject("Nosepiece");if(nosepiece->property("IsMounted").toInt() == 1){nosepiece->dynamicCall("Forward()");}

但是这个代码就不能正常工作,nosepiece->property(“IsMounted”).toInt() 每次的返回值都是 0。

    int getPosition(){return nosepiece->property("position").toInt();}

这个代码的本意是获得物镜转盘当前的位置,但是每次的返回值却都是 0。

这个问题卡了我两天。中间试了各种办法都没有作用。甚至装了个 64 位的 qt 5.7.0。
没有头绪时就反复的读文档。看到 Qt 提供了 dumpdoc 和 dumpcpp 这两个工具之后就想用 dumpcpp 来试试。

用 dumpcpp 倒是生成了相应的头文件和 Cpp 文件。但是加入到项目中编译时报了几百个各种错误,试图修改了几处后还是果断放弃了。

直到今天,用 dumpdoc 生成了NikonLV 和 Nosepiece 这两个对象的文档。仔细读了两遍突然眼前一亮。 文档中列出的 Nosepiece 的属性有这些:

  • QVariant IsMounted;
  • QVariant Position;
  • EnumStatus _IsMounted;
  • int _Position;

这里删掉了其余的属性,就留了四个。看到这里之后就恍然大悟了。原来我应该用带下划线的那些属性。之后我的程序就顺利调通了。

不过为啥会多处这些带下划线的属性呢?在 SDK 的文档中是没有的,VBScript 代码中也没有。希望有高手能给我解释一下。

之后我将相关的代码做了整理,放到了一个类中。下面是这个类的代码,首先是头文件:

#ifndef NIKONNOSEPIECE_H
#define NIKONNOSEPIECE_H#include <QObject>
#include <QAxObject>
#include <QTimer>class NikonNosepiece : public QObject
{Q_OBJECT
public:explicit NikonNosepiece(QObject *parent = 0);~NikonNosepiece();bool isMounted();
signals:void positionChanged(int n);
public slots:void setPosition(int n);void forward();void reverse();
private slots:void on_timer();
private:QAxObject *nikon;QAxObject *nosepiece;QTimer *m_timer;int m_pos;
};#endif // NIKONNOSEPIECE_H

之后是 cpp 文件:

#include "nikonNosepiece.h"
#include <QDebug>NikonNosepiece::NikonNosepiece(QObject *parent) : QObject(parent)
{m_pos = 0;nikon = new QAxObject(parent);nikon->setControl("Nikon.LvMic.NikonLV");qDebug() << "objectName = " << nikon->property("objectName");qDebug() << "SystemName = " << nikon->property("SystemName");qDebug() << "VersionOfSDK = " << nikon->property("VersionOfSDK");nosepiece = nikon->querySubObject("Nosepiece");m_timer = new QTimer(this);m_timer->setInterval(500);connect(m_timer, SIGNAL(timeout()), this, SLOT(on_timer()));m_timer->start();
}void NikonNosepiece::on_timer()
{int pos = nosepiece->property("_Position").toInt();if (pos != m_pos){m_pos = pos;if(m_pos != 0){emit positionChanged(m_pos);}}
}bool NikonNosepiece::isMounted()
{return nosepiece->property("_IsMounted").toInt();
}NikonNosepiece::~NikonNosepiece()
{delete nikon;m_timer->stop();
}void NikonNosepiece::setPosition(int n)
{int lowerLimit = nosepiece->property("_LowerLimit").toInt();int upperLimit = nosepiece->property("_UpperLimit").toInt();n = qBound(lowerLimit, n, upperLimit);nosepiece->setProperty("_Position", n);
}void NikonNosepiece::forward()
{nosepiece->dynamicCall("Forward()");
}void NikonNosepiece::reverse()
{nosepiece->dynamicCall("Reverse()");
}

代码很简单,就不多解释了。用起来很方便。比如切换到第二个物镜,就下面两行代码:

NikonNosepiece nosepiece;
nosepiece.setPositon(2);

物镜改变时会发出 SIGNAL : void positionChanged(int n);

我们的程序中只需要把这个 signal 链接到合适的 Slot 上就可以了。

希望对大家有用。


http://www.ppmy.cn/news/347958.html

相关文章

摄像型三目透反射正置金相显微镜

摄像型金相显微镜是将传统的光学显微镜与电脑及工业摄像机通过光电转换有机的结合在一起&#xff0c;不仅可以在目镜上作显微观察&#xff0c;还可在电脑显示器上实时显示显微图像&#xff0c;可单张、定时、连续采集显微图像&#xff0c;可对显微图像定倍缩放&#xff0c;叠加…

CMY-100三目正置金相显微镜

CMY-100工业检测显微镜适用于对工件表面的组织结构与几何形态进行显微观察。采用优良的无限远光学系统与模块化功能设计理念&#xff0c;可以方便升级系统。本产品可实现偏光观察功能&#xff0c;导柱升降装置&#xff0c;可以快速调整工作台与物镜之间的距离&#xff0c;适用于…

摄像型透反射金相显微镜

摄像型金相显微镜是将传统的光学显微镜与电脑及工业摄像机通过光电转换有机的结合在一起&#xff0c;不仅可以在目镜上作显微观察&#xff0c;还可在电脑显示器上实时显示显微图像&#xff0c;可单张、定时、连续采集显微图像&#xff0c;可对显微图像定倍缩放&#xff0c;叠加…

透反射三目正置金相显微镜

CMY-210透反射正置金相显微镜是适用于对不透明物体或透明物体的显微观察。本仪器配置落射与透射照明系统、长距平场消色差物镜(无盖玻片)、大视野目镜和内置偏振观察装置&#xff0c;具有图像清晰、衬度好&#xff0c;操作方便等特点&#xff0c;是生物学、金属学、矿物学、精密…

双目正置金相显微镜

双目金相显微镜51X采用了无限远光学系统&#xff0c;提供了卓越的光学性能&#xff0c;广泛应用于机械、矿产工业进行金属、岩矿等组织鉴别&#xff1b;以及半导体、电子工业进行晶体、集成电路的检验和科学研究。配备透射照明、成像和观察系统&#xff0c;也可用于生物&#x…

三目倒置金相显微镜

三目倒置金相显微镜CMY-40成像清晰&#xff0c;操作灵活&#xff0c;性价比极高。主要用于鉴定和分析金属内部结构组织&#xff0c;或用于观察材料表面的某些特性&#xff0c;如&#xff1a;划痕、裂纹、喷涂的均匀性等。广泛应用在工厂、实验室和教学及科学领域。 总放大倍数&…

摄像型三目正置金相显微镜

摄像型金相显微镜是将传统的光学显微镜与电脑及工业摄像机通过光电转换有机的结合在一起&#xff0c;不仅可以在目镜上作显微观察&#xff0c;还可在电脑显示器上实时显示显微图像&#xff0c;可单张、定时、连续采集显微图像&#xff0c;可对显微图像定倍缩放&#xff0c;叠加…

金相显微镜的常规维护

就目前的形式可以说金相显微镜属于精密光学仪器&#xff0c;为了保证金相显微镜系统正常的发挥功能&#xff0c;特制定本规程。金相显微镜由专人使用&#xff0c;专人负责日常维护、保养。任何人未经许可&#xff0c;不得调试该设备。金相显微镜系统的操作步骤及日常维护、保养…