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 0

class 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 
#include 
#include 
#include 

#include 
#include 

#include 

#include "asynMotorController.h"
#include "asynMotorAxis.h"

#include 
#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文件并且使用户调用VirtualMotorCreateAxis
  for (axis=0; axis0,则将输出每个轴的信息。
  * 在输出控制器专用信息后,它调用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(asynMotorController::getAxis(pasynUser));
}


/**返回一个指向一个VirtualMotorAxis对象的指针。如果在pasynUser中编码的轴编号无效,返回NULL。
  *
  * 参数[in] axisNo Axis索引编码. */
VirtualMotorAxis* VirtualMotorController::getAxis(int axisNo)
{
  return static_cast(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 position
  if (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";

  // 当前没有实现Homing

  return 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:       0x20
     home限位:     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

< envPaths

cd "${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驱动程序实例_第1张图片

你可能感兴趣的:(EPICS教程,Linux,C,EPICS,C语言)