本文主要是介绍EPICS motor驱动程序实例,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
本驱动程序是控制https://blog.csdn.net/yuyuyuliang00/article/details/132483050中描述的模拟电机控制器。其余基于字符串通信方式的电机控制器,都可以使用这个模板进行修改,开发对应的EPICS电机驱动程序。
源程序如下:
头文件vm.h:
#include "asynMotorController.h"
#include "asynMotorAxis.h"#define MAX_VIRTUAL_MOTOR_AXES 32 /* motor.h设置最大轴数 */
//#define BUFF_SIZE 20 /* 和VirtualMotor之间来回传递字符串的最大长度 */// 还没有控制器专用参数
#define NUM_VIRTUAL_MOTOR_PARAMS 0class epicsShareClass VirtualMotorAxis : public asynMotorAxis
{
public:/* 这些是我们重写自基类的方法 *//* 参数:1)指向本轴所属的控制器对象的指针 2)本轴的编号 */VirtualMotorAxis(class VirtualMotorController *pC, int axisNo);//VirtualMotorAxis(class VirtualMotorController *pC, int axisNo, double stepSize);void report(FILE *fp, int level);/* 位置,相对/绝对,最低速度,最高速度,加速度*/asynStatus move(double position, int relative, double min_velocity, double max_velocity, double acceleration);/* 最低速度,最高速度,加速度 */asynStatus moveVelocity(double min_velocity, double max_velocity, double acceleration);//asynStatus home(double min_velocity, double max_velocity, double acceleration, int forwards);asynStatus stop(double acceleration);asynStatus poll(bool *moving);asynStatus setPosition(double position);//asynStatus setClosedLoop(bool closedLoop);private:VirtualMotorController *pC_; /**< 指向本轴所属的控制器对象的指针。因为使用非常频繁,缩写。*/int axisIndex_;//double stepsSize_;// 设定加速度,速度,基速度asynStatus sendAccelAndVelocity(double accel, double velocity, double baseVelocity);friend class VirtualMotorController;
};class epicsShareClass VirtualMotorController : public asynMotorController {
public:VirtualMotorController(const char *portName, const char *VirtualMotorPortName, int numAxes, double movingPollPeriod, double idlePollPeriod);void report(FILE *fp, int level);VirtualMotorAxis* getAxis(asynUser *pasynUser);VirtualMotorAxis* getAxis(int axisNo);//private:
// char buff_[BUFF_SIZE];friend class VirtualMotorAxis;
};
实现文件:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>#include <iocsh.h>
#include <epicsThread.h>#include <asynOctetSyncIO.h>#include "asynMotorController.h"
#include "asynMotorAxis.h"#include <epicsExport.h>
#include "vm.h"#define NINT(f) (int)((f)>0 ? (f)+0.5 : (f)-0.5)/************************************************* 这些是虚拟电机控制器的方法 *************************************************/
/** Creates a new VirtualMotorController object.创建一个新的虚拟电机控制器对象,* 参数[in] portName: 为这个驱动创建的asyn端口的名称* 参数[in] VirtualMotorPortName 先前创建的连接到虚拟电机控制器的drvAsynSerialPort或drvAsynIPPortConfigure的名称.* 参数[in] numAxes 这个控制器支持的轴数* 参数[in] movingPollPeriod 当任何轴在移动时,轮询之间的时间* 参数[in] idlePollPeriod 当没有轴在移动时,轮询之间的时间*/
VirtualMotorController::VirtualMotorController(const char *portName, const char *VirtualMotorPortName, int numAxes,double movingPollPeriod,double idlePollPeriod): asynMotorController(portName, numAxes, NUM_VIRTUAL_MOTOR_PARAMS,0, // 除了基类中接口外,没有其它接口0, // 除了基类中那些回调外,没有其它回调接口ASYN_CANBLOCK | ASYN_MULTIDEVICE,1, // 自动连接0, 0) // 默认优先级和栈尺寸
{asynStatus status;int axis;VirtualMotorAxis *pAxis;static const char *functionName = "VirtualMotorController::VirtualMotorController";/* 连接到虚拟电机控制器 */status = pasynOctetSyncIO->connect(VirtualMotorPortName, 0, &pasynUserController_, NULL);if (status) {asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,"%s: cannot connect to virtual motor controller\n",functionName);}/** Controller, NOT axis-specific, initialization can go here 控制器,非轴相关的,初始化在这里进行*/// 如果创建轴(每个单位步数),需要其它信息,注释掉以下循环并且从cmd文件并且使用户调用VirtualMotorCreateAxisfor (axis=0; axis<numAxes; axis++) {pAxis = new VirtualMotorAxis(this, axis);}startPoller(movingPollPeriod, idlePollPeriod, 2);
}/** 创建一个新的虚拟电机控制器对象。* 配置的命令,直接被调用或者从iocsh* 参数[in] portName 将为这个驱动创建的asyn端口的名称* 参数[in] VirtualMotorPortName 先前被创建来连接到虚拟电机控制器的drvAsynSerialPort或drvAsynIPPortConfigure的名称* 参数[in] numAxes 这个控制器支持的轴数* 参数[in] movingPollPeriod 当任何轴在移动时,轮询之间的时间(ms)* 参数[in] idlePollPeriod 当没有轴在移动时,轮询之间的时间(ms)*/
extern "C" int VirtualMotorCreateController(const char *portName, const char *VirtualMotorPortName, int numAxes,int movingPollPeriod, int idlePollPeriod)
{VirtualMotorController *pVirtualMotorController= new VirtualMotorController(portName, VirtualMotorPortName, numAxes, movingPollPeriod/1000., idlePollPeriod/1000.);pVirtualMotorController = NULL;return(asynSuccess);
}/** 报告驱动的状态。* 参数[in] fp 文件指针, 报告将写入这个文件* 参数[in] level 所需报告细节的等级* 如果detail>0,则将输出每个轴的信息。* 在输出控制器专用信息后,它调用asynMotorController::report()*/
void VirtualMotorController::report(FILE *fp, int level)
{fprintf(fp, "Virtual Motor Controller driver %s\n", this->portName); // 这个驱动的端口名fprintf(fp, " numAxes=%d\n", numAxes_); // 这个驱动支持的轴数fprintf(fp, " moving poll period=%f\n", movingPollPeriod_); //电机移动时的轮询时间fprintf(fp, " idle poll period=%f\n", idlePollPeriod_); //电机运动时的轮询时间/* 打印在VirtualMotorDriver.h中添加到VirtualMotorController类中的私有变量是个好想法,* 这使得你可以通过从iocsh运行"dbior"看到发生了什么。*/// 调用基类方法asynMotorController::report(fp, level);
}/** 返回一个指向一个VirtualMotorAxis对象的指针。如果在pasynUser中编码的轴编号无效,返回NULL。** 参数[in] pasynUser 编码这个轴索引号的asynUser结构体 */
VirtualMotorAxis* VirtualMotorController::getAxis(asynUser *pasynUser)
{return static_cast<VirtualMotorAxis*>(asynMotorController::getAxis(pasynUser));
}/**返回一个指向一个VirtualMotorAxis对象的指针。如果在pasynUser中编码的轴编号无效,返回NULL。** 参数[in] axisNo Axis索引编码. */
VirtualMotorAxis* VirtualMotorController::getAxis(int axisNo)
{return static_cast<VirtualMotorAxis*>(asynMotorController::getAxis(axisNo));
}/******************************************* 这些是轴方法 *******************************************//** Creates a new VirtualMotorAxis object. 创建一个新的虚拟电机轴对象。* 参数[in] pC :指向这个轴所属的VirtualMotorController的指针* 参数[in] axisNo : 这个轴的索引编号,范围0到pC->numAxes_-1.** 初始化寄存器数值等*/
// 注意:如果从iocsh调用VirtualMotorCreateAxis,以下构造器需要被修改,来接收stepSize,
// 这是使用EGU而不是steps控制器必需的。
VirtualMotorAxis::VirtualMotorAxis(VirtualMotorController *pC, int axisNo): asynMotorAxis(pC, axisNo),pC_(pC)
{//asynStatus status;axisIndex_ = axisNo + 1;/** 轴特定的初始化,在此进行。编码器位置归零(这似乎只在windows上是一个问题)*/setDoubleParam(pC_->motorEncoderPosition_, 0.0);// 允许CNEN开启/关闭电机//setIntegerParam(pC->motorStatusGainSupport_, 1);//setIntegerParam(pC->motorStatusHasEncoder_, 1);// 使得更改的参数生效callParamCallbacks();
}/** 如果控制器用EGU而不是整数steps报告位置,并且stepsPerUnit的数值可以在轴之间不同,* 使用者需要配置每个轴。在本文件末尾的以下函数以及相应的注册代码应该被取消注释。* 在VirtualMotorDriver.h中的声明也需要被取消注释。VirtualMotorAxis构造器将炫耀被修改来接收(double)stepSize参数。* Newport XPS支持是一个如何为一个真实控制器做这件事的示例。*/
/*
extern "C" int VirtualMotorCreateAxis(const char *VirtualMotorName, int axisNo, const char *setpsPerUnit)
{VirtualMotorController *pC;double stepSize;static const char *functionName = "VirtualMotorCreateAxis";pC = (VirtualMotorController*) findAsynPortDriver(VirtualMotorName);if (!pC){printf("Error port %s not found\n", VirtualMotorName);return asynError;}stepSize = strtod(stepsPerUnit, NULL);pC->lock();new VirtualMotorAxis(pC, axisNo, 1./stepSize);pC->unlock();return asynSuccess;
}
*//** 报告这个轴的状态* 参数[in] fp 文件指针,报告信息将写入这个文件* 参数[in] level 所需报告细节的层度* 在打印设备相信息后,调用asynMotorAxis:report()*/
void VirtualMotorAxis::report(FILE *fp, int level)
{if (level > 0) {fprintf(fp, " Axis #%d\n", axisNo_);fprintf(fp, " axisIndex_=%d\n", axisIndex_);}/* 打印添加到VirtualMotorDriver.h中VirtualMotorAxis中的私有变量是一个好想法,* 这使得你通过从iocsh运行"dbior"能够看到发生了什么*/// 调用基类方法asynMotorAxis::report(fp, level);
}/** sendAccelAndVelocity()被VirtualMotorAxis方法调用,其导致电机移动:move(), moveVelocity(), home()* motor记录字段中的参数:* baseVelocity (steps/s) = VBAS / abs(MRES)* velocity (step/s) = VELO / abs(MRES)* acceleration (step/s/s) = (velocity - baseVelocity) / ACCL* VBAS MRES VELO ACCL都是motor记录中的字段*/
asynStatus VirtualMotorAxis::sendAccelAndVelocity(double acceleration, double velocity, double baseVelocity)
{asynStatus status;// static const char *functionName = "VirtualMotor::sendAccelAndVelocity";// 发送基速度sprintf(pC_->outString_, "%d BAS %f", axisIndex_, baseVelocity);status = pC_->writeReadController();// 发送速度sprintf(pC_->outString_, "%d VEL %f", axisIndex_, velocity);status = pC_->writeReadController();// 发送加速度sprintf(pC_->outString_, "%d ACC %f", axisIndex_, acceleration);status = pC_->writeReadController();return status;
}/** 当请求绝对或相对移动时,move()被asynMotor设备支持调用。* 如果BDST > 0 或 RTRY > 0,它可以被调用多次。** motor记录字段中的参数:* position (steps) = RVAL = DVAL / MRES* baseVelocity (steps/s) = VBAS / abs(MRES)* velocity (step/s) = VELO / abs(MRES)* acceleration (step/s/s) = (velocity - baseVelocity) / ACCL*/
asynStatus VirtualMotorAxis::move(double position, int relative, double minVelocity, double maxVelocity, double acceleration)
{asynStatus status;// static const char *functionName = "VirtualMotorAxis::move";status = sendAccelAndVelocity(acceleration, maxVelocity, minVelocity);printf("position: %f; relative:%d; minVelocity=%f,maxVelocity=%f, acceleration=%f\n", position, relative,minVelocity, maxVelocity, acceleration);// Set the target positionif (relative) {sprintf(pC_->outString_, "%d MR %d", axisIndex_, NINT(position));} else {sprintf(pC_->outString_, "%d MV %d", axisIndex_, NINT(position));}status = pC_->writeReadController();// 如果控制器有一个"go"命令,在这里发送return status;
}/** 当请求一个home时,asynMotor设备支持调用home()。* 注意:forwards是由设备支持设置,不是由motor记录。** motor记录字段中的参数:* minVelocity (steps/s) = VBAS / abs(MRES)* maxVelocity (step/s) = HVEL / abs(MRES)* acceleration (step/s/s) = (maxVelocity - minVelocity) / ACCL* forwards = 1 if HOMF was pressed, 0 if HOMR was pressed* 如果HOMF被按下,forwords=1,如果HOMR被按下,forwards=0*/
/*
asynStatus VirtualMotorAxis::home(double minVelocity, double maxVelocity, double acceleration, int forwards)
{// static const char *functionName = "VirtualMotorAxis::home";// 当前没有实现Homingreturn asynSuccess;
}
*//** 当请求jog时,asynMotor调用moveVelocity* 如果控制器没有一个jog命令,这个jog在此处被模拟。* Arguments in terms of motor record fields:* minVelocity (steps/s) = VBAS / abs(MRES)* maxVelocity (step/s) = (jog_direction == forward) ? JVEL * DIR / MRES : -1 * JVEL * DIR / MRES* acceleration (step/s/s) = JAR / abs(EGU)*/
asynStatus VirtualMotorAxis::moveVelocity(double minVelocity, double maxVelocity, double acceleration)
{asynStatus status;//static const char *functionName = "VirtualMotorAxis::moveVelocity";// 调用这个设置最大当前和加速度。status = sendAccelAndVelocity(acceleration, maxVelocity, minVelocity);sprintf(pC_->outString_, "%d JOG %f", axisIndex_, maxVelocity);status = pC_->writeReadController();return status;
}/** 当用户按下stop按钮时,stop()被asynMotor设备支持调用。当jog按钮被释放时,它也被调用。**/
asynStatus VirtualMotorAxis::stop(double acceleration)
{asynStatus status;//static const char *functionName = "VirtualMotorAxis::stop";sprintf(pC_->outString_, "%d AB", axisIndex_);status = pC_->writeReadController();return status;
}/** 当一个位置被重新定义时,asynMotor设备支持调用setPosition().* It is also required for autosave to restore a position to the controller at iocInit.* position (steps) = DVAL / MRES = RVAL*/
asynStatus VirtualMotorAxis::setPosition(double position)
{asynStatus status;//static const char *functionName = "VirtualMotorAxis::setPosition";sprintf(pC_->outString_, "%d POS %d", axisIndex_, NINT(position));status = pC_->writeReadController();return status;
}/** 当一个用户启用或者禁用torque,asynMotor设备支持调用setClosedLoop(),通常从motorx_all.adl,* 但只用于设置以下参数为1的驱动。* pC->motorStatusGainSupport_* pC->motorStatusHasEncoder_* 在此实现实际实现什么根据控制器特点而不同。** 记录字段中参数:* closedLoop = CNEN*/
/*
asynStatus VirtualMotorAxis::setClosedLoop(bool closedLoop)
{asynStatus status;//static const char *functionName = "VirtualMotorAxis::setClosedLoop";if (closedLoop){// 构建"Enable"命令sprintf(pC_->outString_, "%d EN", axisIndex_);}else{// 构建"Disable" 命令sprintf(pC_->outString_, "%d DI", axisIndex_);}// 发送命令status = pC_->writeController();return status;
}
*//** 查询这个轴。* 这个函数读取电机位置,limit状态,home状态,移动状态以及驱动上电状态。* 为它轮询的每项调用setIntegerParam() 和 setDoubleParam(),并且接着在末尾调用callParamCallbacks()。** 参数[out] moving : 一个标记,设置它来表明这个轴正在移动(true)或结束(false)。*/
asynStatus VirtualMotorAxis::poll(bool *moving)
{int position;int status;int done;int direction;int limit;asynStatus comStatus;// 读取当前电机位置sprintf(pC_->outString_, "%d POS?", axisIndex_);comStatus = pC_->writeReadController();if (comStatus)goto skip;// 响应字符串格式为"0.00000"position = atof((const char *) &pC_->inString_);setDoubleParam(pC_->motorPosition_, position);// 读取这个电机的移动状态sprintf(pC_->outString_, "%d ST?", axisIndex_);comStatus = pC_->writeReadController();if (comStatus)goto skip;// 响应字符串格式是 "1"status = atoi((const char *) &pC_->inString_);/*状态位方向: 0x1结束移动: 0x2移动中: 0x4高限制: 0x8低限位: 0x10寻home: 0x20home限位: 0x40已经找到home: 0x80错误: 0x100*/// 读取方向direction = (status & 0x1) ? 1 : 0;setIntegerParam(pC_->motorStatusDirection_, direction);// 读取移动状态done = (status & 0x2) ? 1 : 0;setIntegerParam(pC_->motorStatusDone_, done);setIntegerParam(pC_->motorStatusMoving_, !done);*moving = done ? false:true;// 读取限位状态limit = (status & 0x8) ? 1 : 0;setIntegerParam(pC_->motorStatusHighLimit_, limit);limit = (status & 0x10) ? 1 : 0;setIntegerParam(pC_->motorStatusLowLimit_, limit);// 读取home状态// TODO: 实现homing// Read the drive power on status 对状态读取驱动电源//driveOn = (status & 0x100) ? 0 : 1;//setIntegerParam(pC_->motorStatusPowerOn_, driveOn);skip:setIntegerParam(pC_->motorStatusProblem_, comStatus ? 1:0);callParamCallbacks();return comStatus ? asynError : asynSuccess;
}/** 注册ioc */
static const iocshArg VirtualMotorCreateControllerArg0 = {"Port name", iocshArgString};
static const iocshArg VirtualMotorCreateControllerArg1 = {"VMC port name", iocshArgString};
static const iocshArg VirtualMotorCreateControllerArg2 = {"Number of axes", iocshArgInt};
static const iocshArg VirtualMotorCreateControllerArg3 = {"Moving poll period (ms)", iocshArgInt};
static const iocshArg VirtualMotorCreateControllerArg4 = {"Idle poll period (ms)", iocshArgInt};
static const iocshArg * const VirtualMotorCreateControllerArgs[] = {&VirtualMotorCreateControllerArg0,&VirtualMotorCreateControllerArg1,&VirtualMotorCreateControllerArg2,&VirtualMotorCreateControllerArg3,&VirtualMotorCreateControllerArg4};
static const iocshFuncDef VirtualMotorCreateControllerDef = {"VirtualMotorCreateController", 5, VirtualMotorCreateControllerArgs};
static void VirtualMotorCreateContollerCallFunc(const iocshArgBuf *args)
{VirtualMotorCreateController(args[0].sval, args[1].sval, args[2].ival, args[3].ival, args[4].ival);
}/* VirtualMotorCreateAxis */
/*
static const iocshArg VirtualMotorCreateAxisArg0 = {"Controller port name", iocshArgString};
static const iocshArg VirtualMotorCreateAxisArg1 = {"Axis number", iocshArgInt};
static const iocshArg VirtualMotorCreateAxisArg2 = {"stepsPerUnit", iocshArgString};
static const iocshArg * const VirtualMotorCreateAxisArgs[] = {&VirtualMotorCreateAxisArg0,&VirtualMotorCreateAxisArg1,&VirtualMotorCreateAxisArg2};
static const iocshFuncDef VirtualMotorCreateAxisDef = {"VirtualMotorCreateAxis", 3, VirtualMotorCreateAxisArgs};
static void VirtualMotorCreateAxisCallFunc(const iocshArgBuf *args)
{VirtualMotorCreateAxis(args[0].sval, args[1].ival, args[2].sval);
}
*/static void VirtualMotorRegister(void)
{iocshRegister(&VirtualMotorCreateControllerDef, VirtualMotorCreateContollerCallFunc);//iocshRegister(&VirtualMotorCreateAxisDef, VirtualMotorCreateAxisCallFunc);
}extern "C" {
epicsExportRegistrar(VirtualMotorRegister);
}
注册文件vm.db:
registrar(VirtualMotorRegister)
Makefile文件:
...
# motorvm.dbd will be made up from these files:
motorvm_DBD += base.dbd
motorvm_DBD += asyn.dbd
motorvm_DBD += drvAsynIPPort.dbd
motorvm_DBD += motorSupport.dbd
motorvm_DBD += asSupport.dbd
motorvm_DBD += vm.dbd# Include dbd files from all support applications:
#motorvm_DBD += xxx.dbd# Add all the support libraries needed by this IOC
motorvm_LIBS += asyn
motorvm_LIBS += motor
motorvm_LIBS += autosave# motorvm_registerRecordDeviceDriver.cpp derives from motorvm.dbd
motorvm_SRCS += vm.cpp
...
motor记录的模板文件vmc.substitutions:
file "$(MOTOR)/db/asyn_motor.db"
{
pattern
{N, M, DTYP, PORT, ADDR, DESC, EGU, DIR, VELO, VBAS, ACCL, BDST, BVEL, BACC, MRES, PREC, DHLM, DLLM, INIT}
{1, "m$(N)", "asynMotor", VMC1, 0, "motor $(N)", mm, Pos, 1, .1, .2, 0, 1, .2, 0.0025, 4, 100, -100, ""}
{2, "m$(N)", "asynMotor", VMC1, 1, "motor $(N)", mm, Pos, 1, .1, .2, 0, 1, .2, 0.0025, 4, 100, -100, ""}
{3, "m$(N)", "asynMotor", VMC1, 2, "motor $(N)", mm, Pos, 1, .1, .2, 0, 1, .2, 0.0025, 4, 100, -100, ""}
{4, "m$(N)", "asynMotor", VMC1, 3, "motor $(N)", deg, Pos, 1, .1, .2, 0, 1, .2, 0.01, 4, 100, -100, ""}
{5, "m$(N)", "asynMotor", VMC1, 4, "motor $(N)", deg, Pos, 1, .1, .2, 0, 1, .2, 0.01, 4, 100, -100, ""}
{6, "m$(N)", "asynMotor", VMC1, 5, "motor $(N)", deg, Pos, 1, .1, .2, 0, 1, .2, 0.01, 4, 100, -100, ""}
{7, "m$(N)", "asynMotor", VMC1, 6, "motor $(N)", deg, Pos, 1, .1, .2, 0, 1, .2, 0.01, 4, 100, -100, ""}
{8, "m$(N)", "asynMotor", VMC1, 7, "motor $(N)", deg, Pos, 1, .1, .2, 0, 1, .2, 0.01, 4, 100, -100, ""}
}
启动脚本:
#!../../bin/linux-aarch64/motorvm#- You may have to change motorvm to something else
#- everywhere it appears in this file< envPathscd "${TOP}"## Register all support components
dbLoadDatabase "dbd/motorvm.dbd"
motorvm_registerRecordDeviceDriver pdbbase# 定义IOC前缀:
epicsEnvSet("PREFIX", "MotorVM:")drvAsynIPPortConfigure("VMC_ETH","192.168.50.234:6666", 0, 0, 0)# 显示通信
#!asynSetTraceMask("VMC_ETH", 0, 3)
# 只显示错误
asynSetTraceMask("VMC_ETH", 0, 1)
# 保留选择ascii,使得用单次点击开启跟踪
asynSetTraceIOMask("VMC_ETH", 0, 1)# 设置字符串终止符
asynOctetSetInputEos("VMC_ETH",0,"\r\n")
asynOctetSetOutputEos("VMC_ETH",0,"\r")# 1秒种空闲轮询
VirtualMotorCreateController("VMC1", "VMC_ETH", 8, 250, 1000)cd "${TOP}/iocBoot/${IOC}"
## 装载记录实例
dbLoadTemplate("vmc.substitutions", "P=$(PREFIX)")iocInit
编译以上程序,并且运行启动脚本:
root@orangepi5:/usr/local/EPICS/program/motorvm/iocBoot/iocmotorvm# ../../bin/linux-aarch64/motorvm st.cmd
#!../../bin/linux-aarch64/motorvm
< envPaths
epicsEnvSet("IOC","iocmotorvm")
epicsEnvSet("TOP","/usr/local/EPICS/program/motorvm")
epicsEnvSet("SUPPORT","/usr/local/EPICS/synApps/support")
epicsEnvSet("ASYN","/usr/local/EPICS/synApps/support/asyn")
epicsEnvSet("MOTOR","/usr/local/EPICS/synApps/support/motor")
epicsEnvSet("AUTOSAVE","/usr/local/EPICS/synApps/support/autosave")
epicsEnvSet("EPICS_BASE","/usr/local/EPICS/base")
cd "/usr/local/EPICS/program/motorvm"
## Register all support components
dbLoadDatabase "dbd/motorvm.dbd"
motorvm_registerRecordDeviceDriver pdbbase
# 定义IOC前缀:
epicsEnvSet("PREFIX", "MotorVM:")
drvAsynIPPortConfigure("VMC_ETH","192.168.50.234:6666", 0, 0, 0)
# Show communication
#!asynSetTraceMask("VMC_ETH", 0, 3)
# Only show errors
asynSetTraceMask("VMC_ETH", 0, 1)
# Leave ascii selected so traces can be turned on with a single click
asynSetTraceIOMask("VMC_ETH", 0, 1)
# Set end-of-string terminators
asynOctetSetInputEos("VMC_ETH",0,"\r\n")
asynOctetSetOutputEos("VMC_ETH",0,"\r")
# 1-second idle polling
VirtualMotorCreateController("VMC1", "VMC_ETH", 8, 250, 1000)
cd "/usr/local/EPICS/program/motorvm/iocBoot/iocmotorvm"
## Load record instances
dbLoadTemplate("vmc.substitutions", "P=MotorVM:")
iocInit
Starting iocInit
############################################################################
## EPICS R7.0.7
## Rev. 2023-05-26T09:07+0000
## Rev. Date build date/time:
############################################################################
iocRun: All initialization complete
## Start any sequence programs
#seq sncxxx,"user=orangepi"
epics>
使用dbl查看加载的记录实例,可见加载了八个电机轴:
epics> dbl
...
MotorVM:m1
MotorVM:m2
MotorVM:m3
MotorVM:m4
MotorVM:m5
MotorVM:m6
MotorVM:m7
MotorVM:m8
使用通道访问命令设置轴的位置,并且实时监控其所在位置:
[blctrl@main-machine adls]$ caput MotorVM:m1 15;camonitor MotorVM:m1.RBV
Old : MotorVM:m1 10
New : MotorVM:m1 15
MotorVM:m1.RBV 2023-09-15 03:55:16.445524 10
MotorVM:m1.RBV 2023-09-15 03:55:16.708532 10.1725
MotorVM:m1.RBV 2023-09-15 03:55:16.977737 10.4425
MotorVM:m1.RBV 2023-09-15 03:55:17.240218 10.705
MotorVM:m1.RBV 2023-09-15 03:55:17.503565 10.97
MotorVM:m1.RBV 2023-09-15 03:55:17.769194 11.2325
MotorVM:m1.RBV 2023-09-15 03:55:18.078248 11.5425
MotorVM:m1.RBV 2023-09-15 03:55:18.339768 11.805
MotorVM:m1.RBV 2023-09-15 03:55:18.600618 12.065
MotorVM:m1.RBV 2023-09-15 03:55:18.862169 12.3275
MotorVM:m1.RBV 2023-09-15 03:55:19.123034 12.5875
MotorVM:m1.RBV 2023-09-15 03:55:19.383936 12.85
MotorVM:m1.RBV 2023-09-15 03:55:19.644173 13.11
MotorVM:m1.RBV 2023-09-15 03:55:19.904203 13.37
MotorVM:m1.RBV 2023-09-15 03:55:20.168548 13.63
MotorVM:m1.RBV 2023-09-15 03:55:20.455850 13.9175
MotorVM:m1.RBV 2023-09-15 03:55:20.763345 14.2275
MotorVM:m1.RBV 2023-09-15 03:55:21.024398 14.49
MotorVM:m1.RBV 2023-09-15 03:55:21.285069 14.56
MotorVM:m1.RBV 2023-09-15 03:55:21.546239 14.685
MotorVM:m1.RBV 2023-09-15 03:55:21.807113 14.8775
MotorVM:m1.RBV 2023-09-15 03:55:22.067684 15
使用medm连接其中的一个电机轴,进行图形显示:
[blctrl@main-machine adls]$ medm -x -macro "P=MotorVM:,M=m1" motorx_all.adl &
通过更改MoveAbs可以改变虚拟轴的位置:
这篇关于EPICS motor驱动程序实例的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!