EPICS motor驱动程序实例

2023-10-15 07:10

本文主要是介绍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驱动程序实例的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/216149

相关文章

【机器学习】高斯过程的基本概念和应用领域以及在python中的实例

引言 高斯过程(Gaussian Process,简称GP)是一种概率模型,用于描述一组随机变量的联合概率分布,其中任何一个有限维度的子集都具有高斯分布 文章目录 引言一、高斯过程1.1 基本定义1.1.1 随机过程1.1.2 高斯分布 1.2 高斯过程的特性1.2.1 联合高斯性1.2.2 均值函数1.2.3 协方差函数(或核函数) 1.3 核函数1.4 高斯过程回归(Gauss

C++操作符重载实例(独立函数)

C++操作符重载实例,我们把坐标值CVector的加法进行重载,计算c3=c1+c2时,也就是计算x3=x1+x2,y3=y1+y2,今天我们以独立函数的方式重载操作符+(加号),以下是C++代码: c1802.cpp源代码: D:\YcjWork\CppTour>vim c1802.cpp #include <iostream>using namespace std;/*** 以独立函数

实例:如何统计当前主机的连接状态和连接数

统计当前主机的连接状态和连接数 在 Linux 中,可使用 ss 命令来查看主机的网络连接状态。以下是统计当前主机连接状态和连接主机数量的具体操作。 1. 统计当前主机的连接状态 使用 ss 命令结合 grep、cut、sort 和 uniq 命令来统计当前主机的 TCP 连接状态。 ss -nta | grep -v '^State' | cut -d " " -f 1 | sort |

Java Websocket实例【服务端与客户端实现全双工通讯】

Java Websocket实例【服务端与客户端实现全双工通讯】 现很多网站为了实现即时通讯,所用的技术都是轮询(polling)。轮询是在特定的的时间间隔(如每1秒),由浏览器对服务器发 出HTTP request,然后由服务器返回最新的数据给客服端的浏览器。这种传统的HTTP request 的模式带来很明显的缺点 – 浏 览器需要不断的向服务器发出请求,然而HTTP

828华为云征文|华为云Flexus X实例docker部署rancher并构建k8s集群

828华为云征文|华为云Flexus X实例docker部署rancher并构建k8s集群 华为云最近正在举办828 B2B企业节,Flexus X实例的促销力度非常大,特别适合那些对算力性能有高要求的小伙伴。如果你有自建MySQL、Redis、Nginx等服务的需求,一定不要错过这个机会。赶紧去看看吧! 什么是华为云Flexus X实例 华为云Flexus X实例云服务是新一代开箱即用、体

LLVM入门2:如何基于自己的代码生成IR-LLVM IR code generation实例介绍

概述 本节将通过一个简单的例子来介绍如何生成llvm IR,以Kaleidoscope IR中的例子为例,我们基于LLVM接口构建一个简单的编译器,实现简单的语句解析并转化为LLVM IR,生成对应的LLVM IR部分,代码如下,文件名为toy.cpp,先给出代码,后面会详细介绍每一步分代码: #include "llvm/ADT/APFloat.h"#include "llvm/ADT/S

OpenStack离线Train版安装系列—11.5实例使用-Cinder存储服务组件

本系列文章包含从OpenStack离线源制作到完成OpenStack安装的全部过程。 在本系列教程中使用的OpenStack的安装版本为第20个版本Train(简称T版本),2020年5月13日,OpenStack社区发布了第21个版本Ussuri(简称U版本)。 OpenStack部署系列文章 OpenStack Victoria版 安装部署系列教程 OpenStack Ussuri版

OpenStack实例操作选项解释:启动和停止instance实例

关于启动和停止OpenStack实例 如果你想要启动和停止OpenStack实例时,有四种方法可以考虑。 管理员可以暂停、挂起、搁置、停止OpenStack 的计算实例。但是这些方法之间有什么不同之处? 目录 关于启动和停止OpenStack实例1.暂停和取消暂停实例2.挂起和恢复实例3.搁置(废弃)实例和取消废弃实例4.停止(删除)实例 1.暂停和取消暂停实例

Cmake之3.0版本重要特性及用法实例(十三)

简介: CSDN博客专家、《Android系统多媒体进阶实战》一书作者 新书发布:《Android系统多媒体进阶实战》🚀 优质专栏: Audio工程师进阶系列【原创干货持续更新中……】🚀 优质专栏: 多媒体系统工程师系列【原创干货持续更新中……】🚀 优质视频课程:AAOS车载系统+AOSP14系统攻城狮入门视频实战课 🚀 人生格言: 人生从来没有捷径,只有行动才是治疗恐惧

实例demo理解面向接口思想

浅显的理解面向接口编程 Android开发的语言是java,至少目前是,所以理解面向接口的思想是有必要的。下面通过一个简单的例子来理解。具体的概括我也不知道怎么说。 例子: 现在我们要开发一个应用,模拟移动存储设备的读写,即计算机与U盘、MP3、移动硬盘等设备进行数据交换。已知要实现U盘、MP3播放器、移动硬盘三种移动存储设备,要求计算机能同这三种设备进行数据交换,并且以后可能会有新的第三方的