asynMotorAxis类

25 篇文章 24 订阅

轴对象的基类,具体的轴类是派生自这个类,控制器类是其友元类。

派生类根据需要实现以下方法:

asynMotorAxis.h 头文件:

/* asynMotorAxis.h 
** 这个文件为一个asynMotorAxis定义了一个基类。
** 真实电机从这个类派生
*/
#ifndef asynMotorAxis_H
#define asynMotorAxis_H
 
#include <epicsEvent.h>
#include <epicsTypes.h>

#ifdef __cplusplus
#include <asynPortDriver.h>

#include "asynMotorController.h"

class epicsShareFunc asynMotorAxis {

 public:
/*  这是这个类的构造器:控制器对象的指针以及这个轴编号 */
asynMotorAxis(class asynMotorController *pController, int axisNumber);

// 根据索引设置参数库中的整数变量
virtual asynStatus setIntegerParam(int index, int value);
// 根据索引设置参数库中的双精度浮点变量
virtual asynStatus setDoubleParam(int index, double value);
virtual void report(FILE *fp, int details);
virtual asynStatus callParamCallbacks();

// 移动:要移动的位置,相对或绝对,最低速度,最高速度,加速度
// 要移动的位置以step为单位
virtual asynStatus move(double position, int relative, double minVelocity, double maxVelocity, double acceleration);

//以一个指定速度移动
virtual asynStatus moveVelocity(double minVelocity, double maxVelocity, double acceleration);
//归零:最低速度,最高速度,加速度以及方向
virtual asynStatus home(double minVelocity, double maxVelocity, double acceleration, int forwards);
//轴停止
virtual asynStatus stop(double acceleration);
//轴轮询
virtual asynStatus poll(bool *moving);
//设置轴位置
virtual asynStatus setPosition(double position);
//设置编码器位置
virtual asynStatus setEncoderPosition(double position);
//设置上限位
virtual asynStatus setHighLimit(double highLimit);
//设置下限位
virtual asynStatus setLowLimit(double lowLimit);
//设置比例增益
00040   virtual asynStatus setPGain(double pGain);
//设置积分增益
virtual asynStatus setIGain(double iGain);
//设置微分增益
00042   virtual asynStatus setDGain(double dGain);
//设置是否闭环
virtual asynStatus setClosedLoop(bool closedLoop);
//设置编码器比率
virtual asynStatus setEncoderRatio(double ratio);
virtual asynStatus doMoveToHome();

virtual asynStatus initializeProfile(size_t maxPoints);
virtual asynStatus defineProfile(double *positions, size_t numPoints);
virtual asynStatus buildProfile();
virtual asynStatus executeProfile();
virtual asynStatus abortProfile();
virtual asynStatus readbackProfile();

void setReferencingModeMove(int distance);
int getReferencingModeMove();

protected:
class asynMotorController *pC_;    //所属控制器对象
int axisNo_;          //轴编号                           
asynUser *pasynUser_; //这个轴的使用者           
double *profilePositions_;         
double *profileReadbacks_;         
double *profileFollowingErrors_;   
int referencingMode_;

private:
/*
*      typedef struct MotorStatus {
*          double position;           //命令电机位置
*          double encoderPosition;    //实际编码器位置
*          double velocity;           //实际速度
*          epicsUInt32 status;        //包含状态位(运动结束,限位等)的字
*        } MotorStatus;
*/
MotorStatus status_;   
int statusChanged_;
int referencingModeMove_;
  
friend class asynMotorController;
};
#endif /* _cplusplus */
#endif /* asynMotorAxis_H */

asynMotorAxis.cpp 实现:

/* asynMotorAxis.cpp
** 这个文件为asynMotorAxis定义了基类。真实电机轴从这个类派生
**
*/
#include <stdlib.h>
#include <string.h>

#include <epicsThread.h>

#include <asynPortDriver.h>
#define epicsExportSharedSymbols
#include <shareLib.h>
#include "asynMotorAxis.h"
#include "asynMotorController.h"

static const char *driverName = "asynMotorAxis";


/** 创建一个asynMotorAxis对象.
  * 参数[in] pC :指向这个轴所属的asynMotorController的指针。
  * 参数[in] axisNo:这个轴的编号,范围从0到pC->numAxes_-1.
  * 
  * 检查pC不为空,并且axisNo在有效范围内。
  * 在pC->pAxes[axisNo_]中设置一个指针指向自身
  * 连接pasynUser_到这个asyn端口和asynNo
  */
asynMotorAxis::asynMotorAxis(class asynMotorController *pC, int axisNo)
  : pC_(pC), axisNo_(axisNo), statusChanged_(1)
{
  static const char *functionName = "asynMotorAxis";

  if (!pC) {// 检查传入pC不为空
    printf("%s:%s: Error, controller is NULL\n",driverName, functionName);
    return;
  }
  // 检查axisNo在有效范围内
  if ((axisNo < 0) || (axisNo >= pC->numAxes_)) {
    printf("%s:%s: Error, axis=%d is not in range 0 to %d\n",
    driverName, functionName, axisNo, pC->numAxes_-1);
    return;
  }
  
  //pC->pAxes_的第axisNo索引指向自身
  pC->pAxes_[axisNo] = this;
  //初始状态置位0
  status_.status = 0;
  profilePositions_       = NULL;
  profileReadbacks_       = NULL;
  profileFollowingErrors_ = NULL;

  /* 用于在驱动程序中跟踪参考模式 */
  referencingMode_ = 0;
  /* 用于启用/禁用移动到零位,并且告诉驱动程序要移动多远 */
  referencingModeMove_ = 0;

  wasMovingFlag_ = 0;
  disableFlag_ = 0;
  lastEndOfMoveTime_ = 0;

  // 创建一个asynUser, 连接到这个轴
  /* 创建一个asynUser. 调用者指定两个回调process和timeout。
  这些回调仅由queueRequest的结果被调用。timeout是可选的。
  位errorMesage分配errorMessageSize个字符。存储量不能被更改。
  如果这个方法不能分配存储区,它不返回。
  */
  pasynUser_ = pasynManager->createAsynUser(NULL, NULL);
/* 连接这个asynUser结构体到由portName,addr指定的一个设备。
这个端口号与在registerPort中指定的端口名相同。如果这个asynUser已经连接了一个设备,
这个调用将出错。如果端口不支持多设备,则忽略addr。connectDevice仅位portName,addr连接这个asynUser到端口驱动。端口驱动可能连接了实际设备,也可能没有连接。因而,connectDevice和
asynCommon:connect完全不同。
*/
  pasynManager->connectDevice(pasynUser_, pC->portName, axisNo);
}

asynMotorAxis::~asynMotorAxis()
{
}

/** 移动单机到一个绝对位置或者一个相对量。
  * 参数[in] position:如果relavtive=0,移动到绝对位置,relavtive=1移动一个相对距离  Units=steps.
  * 参数[in] relative:指明相对移动(1)或者绝对移动(0)的标记
  * 参数[in] minVelocity:初始速度,通常称为基速度,Units=steps/sec.
  * 参数[in] maxVelocity:最大速度,通常称为回转速度Units=steps/sec.
  * 参数[in] acceleration 加速度值. Units=steps/sec/sec. 
*/
asynStatus asynMotorAxis::move(double position, int relative, double minVelocity, double maxVelocity, double acceleration)
{
  return asynSuccess;
}


/** 在告诉停止前,以固定速度移动电机。
  * 参数[in] minVelocity:初始速度,通常称为基速度,Units=steps/sec.Units=steps/sec.
  * 参数[in] maxVelocity: 最大速度,通常称为回转速度Units=steps/sec.
  * 参数[in] acceleration: 加速度值. Units=steps/sec/sec.
 */
asynStatus asynMotorAxis::moveVelocity(double minVelocity, double maxVelocity, double acceleration)
{
  return asynSuccess;
}


/** 移动电机到归零位置。
  * 参数[in]  minVelocity :初始速度,通常称为基速度,Units=steps/sec.
  * 参数[in]  maxVelocity :最大速度,通常称为回转速度Units=steps/sec.
  * 参数[in]  acceleration: 加速度值. Units=steps/sec/sec.
  * 参数[in]  forwards : 指明电机在正向(1)或反向(0)移动电机的标志
  * 某些电机需要告诉方向,另外知道哪个方向上归零。
*/
asynStatus asynMotorAxis::home(double minVelocity, double maxVelocity, double acceleration, int forwards)
{
  return asynSuccess;
}


/** 停止电机
  *参数[in] acceleration :加速度值. Units=steps/sec/sec. */
asynStatus asynMotorAxis::stop(double acceleration)
{
  return asynSuccess;
}


/** Poll the axis.查询这个轴。 这个函数应该读取控制器位置,编码器位置和硬件支持一样多的*motorStatus标记。它应该位它查询的每个项调用setIntegerParam() 和 setDoubleParam(),并且
*最后调用callParamCallbacks()。
* 参数[out] moving:函数必须设定这个标记,表明轴是移动(1)或者结束(0)。
*/
asynStatus asynMotorAxis::poll(bool *moving)
{
  return asynSuccess;
}


/** 设置电机的当前位置。
* 参数[in] position:应该设置到硬件中的新绝对电机位置。  Units=steps.
*/
asynStatus asynMotorAxis::setPosition(double position)
{
  return asynSuccess;
}


/** 设置电机的当前编码器位置
* 参数[in] position:应该设置到硬件中的新绝对编码器位置  Units=steps.
*/
asynStatus asynMotorAxis::setEncoderPosition(double position)
{
  return asynSuccess;
}


/** 设置电机的上限位位置
* 参数in] highLimit:应该设定到硬件中新的上限位置.Units=steps.
*/
asynStatus asynMotorAxis::setHighLimit(double highLimit)
{
  return asynSuccess;
}


/** 设置电机的下限位位置
* 参数[in] lowLimit:应该设定到硬件中新的下限位置.Units=steps.
*/
asynStatus asynMotorAxis::setLowLimit(double lowLimit)
{
  return asynSuccess;
}


/** 设置电机比例增益
  *参数[in] pGain :新的比例增益
 */
asynStatus asynMotorAxis::setPGain(double pGain)
{
  return asynSuccess;
}


/** 设置电机积分增益
  * 参数[in] iGain 新的积分增益.
 */
asynStatus asynMotorAxis::setIGain(double iGain)
{
  return asynSuccess;
}


/** 设置电机微分增益
  * 参数[in] dGain 新的微分增益
*/
asynStatus asynMotorAxis::setDGain(double dGain)
{
  return asynSuccess;
}


/** 设置电机闭环状态
  *  参数[in]  closedLoop true = 闭环, false = 开环 */
asynStatus asynMotorAxis::setClosedLoop(bool closedLoop)
{
  return asynSuccess;
}


/** 设置电机编码器比率
  * 参数[in] ratio 新的编码器比率 */
asynStatus asynMotorAxis::setEncoderRatio(double ratio)
{
  return asynSuccess;
}

void asynMotorAxis::report(FILE *fp, int details)
{
}


/**
 * doMoveToHome的默认实现,派生类需要实现这个函数实际执行这个轴移动到归零位置
 */
asynStatus asynMotorAxis::doMoveToHome()
{
  static const char *functionName="doMoveToHome";

  asynPrint(pasynUser_, ASYN_TRACE_ERROR,
    "%s:%s: Axis=%d no implementation\n",
    driverName, functionName, pC_->moveToHomeAxis_);
  return asynSuccess;
}


/**
 * referencingModeMove_的设置方法
 */
void  asynMotorAxis::setReferencingModeMove(int distance)
{
  referencingModeMove_ = distance;
}


/**
 * referencingModeMove_的获取方法
 */
int  asynMotorAxis::getReferencingModeMove()
{
  return referencingModeMove_;
}

//我们实现setIntegerParam, setDoubleParam, 和 callParamCallbacks,因此我们可以构造
//聚合状态结构体并且对其进行回调。
/*
在参数库中为这个轴的一个整数设置值。
如果这个参数是motorStatus参数 (motorStatusDirection_, motorStatusHomed_等)之一,这个函数采取特殊操作。在这种情况中,它置位或清零其私有MotorStatus.status结构体中相应的位,并且当导演callParamCallbacks()时,如果状态发生变化,设置一个标记对devMotorAsyn进行回调。
参数[in] function :功能(参数)编号
参数[in] value:要设定的值
*/
asynStatus asynMotorAxis::setIntegerParam(int function, int value)
{
  int mask;
  epicsUInt32 status=0;
  // 这假设以上定义的参数与电机基类预计的位相同顺序
  /*
  这些是状态位
  int motorStatusDirection_;
  int motorStatusDone_;
  int motorStatusHighLimit_;
  int motorStatusAtHome_;
  int motorStatusSlip_;
  int motorStatusPowerOn_;
  int motorStatusFollowingError_;
  int motorStatusHome_;
  int motorStatusHasEncoder_;
  int motorStatusProblem_;
  int motorStatusMoving_;
  int motorStatusGainSupport_;
  int motorStatusCommsError_;
  int motorStatusLowLimit_;
  int motorStatusHomed_;
   */
  if (function >= pC_->motorStatusDirection_ &&
      function <= pC_->motorStatusHomed_) {
    status = status_.status; // 获取状态
    mask = 1 << (function - pC_->motorStatusDirection_);
    if (value) status |= mask;
    else       status &= ~mask;
    if (status != status_.status) {//状态发生了变化
      status_.status = status;
      statusChanged_ = 1;
    }
  }
  // 设置新的状态
  pC_->setIntegerParam(axisNo_, pC_->motorStatus_, status);
  return pC_->setIntegerParam(axisNo_, function, value);
}



/** 在参数库中位这个轴的一个double设置值.
  * 如果这个参数是motorPosition_ 或 motorEncoderPosition_采取特殊操作。
  * 在这种情况下,它设置私有MotorStatus结构体中这个值,并且如果这个值发生变化,则
  * 设置置位一个在callParamCallbacks()被调用时对devMotorAsyn进行回调的标记
  * 参数[in] function :功能(参数)编号
  * 参数[in] value : 要设置的值
*/
asynStatus asynMotorAxis::setDoubleParam(int function, double value)
{
  if (function == pC_->motorPosition_) {
    if (value != status_.position) {// 传入的电机位置不能与状态结构体中的电机位置
        statusChanged_ = 1;
        status_.position = value;
    }
  } else if (function == pC_->motorEncoderPosition_) {
    if (value != status_.encoderPosition) {
        statusChanged_ = 1;
        status_.encoderPosition = value;
    }
  }
  // 调用控制类对象,存储这个功能编号对应的值
  return pC_->setDoubleParam(axisNo_, function, value);
}

/**
  * 位参数库中这个轴的一个字符串设置值
  * 参数[in] function: 功能(参数)编号
  * 参数[in] value: 要设定的值
*/
asynStatus asynMotorAxis::setStringParam(int function, const char *value)
{
  // 调用控制类对象的setStringParam
  return pC_->setStringParam(axisNo_, function, value);
}


/** 为在参数库中对应这个轴已经发生变化的任何参数,调用回调函数。
*如果聚合结构体已经发生变化,这个参数采取特殊操作。
*在这种情况,它对asynGenericPointer进行回调,尤其对devMotorAsyn
*/
asynStatus asynMotorAxis::callParamCallbacks()
{
  if (statusChanged_) {
    statusChanged_ = 0;
    pC_->doCallbacksGenericPointer((void *)&status_, pC_->motorStatus_, axisNo_);
  }
  return pC_->callParamCallbacks(axisNo_);
}

/*  这些函数用于轮廓移动 */
asynStatus asynMotorAxis::initializeProfile(size_t maxProfilePoints)
{
   //轮廓移动的目标位置数组
  if (profilePositions_)       free(profilePositions_);
  profilePositions_ =         (double *)calloc(maxProfilePoints, sizeof(double));
  //轮廓移动的回读位置数组
  if (profileReadbacks_)    free(profileReadbacks_);
  profileReadbacks_ =         (double *)calloc(maxProfilePoints, sizeof(double));
  //  以下轮廓移动的误差的数组
  if (profileFollowingErrors_) free(profileFollowingErrors_);
  profileFollowingErrors_ =   (double *)calloc(maxProfilePoints, sizeof(double));
  return asynSuccess;
}



/**  为一个轮廓移动定义电机位置的函数
  *  这个基类函数使用profileMotorOffset_, profileMotorDirection_和profileMotorResolution参数从用户单位转换位置为控制器单位,
  * 参数[in] positions :这个轴以用户单位的轮廓位置的数组A
  * 参数[in] numPoints :数组中位置数目
  */
asynStatus asynMotorAxis::defineProfile(double *positions, size_t numPoints)
{
  size_t i;
  double resolution;
  double offset;
  int direction;
  double scale;
  int status=0;
  static const char *functionName = "defineProfile";

  asynPrint(pasynUser_, ASYN_TRACE_FLOW,
            "%s:%s: axis=%d, numPoints=%d, positions[0]=%f\n",
            driverName, functionName, axisNo_, (int)numPoints, positions[0]);

  if (numPoints > pC_->maxProfilePoints_) return asynError;

  status |= pC_->getDoubleParam(axisNo_, pC_->motorRecResolution_, &resolution);
  status |= pC_->getDoubleParam(axisNo_, pC_->motorRecOffset_, &offset);
  status |= pC_->getIntegerParam(axisNo_, pC_->motorRecDirection_, &direction);
  asynPrint(pasynUser_, ASYN_TRACE_FLOW,
            "%s:%s: axis=%d, status=%d, offset=%f direction=%d, resolution=%f\n",
            driverName, functionName, axisNo_, status, offset, direction, resolution);
  if (status) return asynError;
  if (resolution == 0.0) return asynError;

  // 转换成控制器单位
  scale = 1.0/resolution;
  if (direction != 0) scale = -scale;
  for (i=0; i<numPoints; i++) {
    profilePositions_[i] = (positions[i] - offset)*scale;
  }
  asynPrint(pasynUser_, ASYN_TRACE_FLOW,
            "%s:%s: axis=%d, scale=%f, offset=%f positions[0]=%f, profilePositions_[0]=%f\n",
            driverName, functionName, axisNo_, scale, offset, positions[0], profilePositions_[0]);
  return asynSuccess;
}



/** 构建一个多轴联动移动的函数*/
asynStatus asynMotorAxis::buildProfile()
{
  // static const char *functionName = "buildProfile";

  return asynSuccess;
}



/** 执行一个多轴联动移动的函数. */
asynStatus asynMotorAxis::executeProfile()
{
  // static const char *functionName = "executeProfile";

  return asynSuccess;
}



/** 终止一个轮廓的函数 */
asynStatus asynMotorAxis::abortProfile()
{
  // static const char *functionName = "abortProfile";

  return asynSuccess;
}



/** 从多轴联动移动回读实际电机位置的函数。这个基类函数转从控制器单位换这些回读和以下误差为用户单位,并且对这些数组进行回调。
注意:这个函数原地修改这些回读,因此它必须每个回读操作仅调用一次。
 */
asynStatus asynMotorAxis::readbackProfile()
{
  int i;
  double resolution;
  double offset;
  int direction;
  int numReadbacks;
  int status=0;
  //static const char *functionName = "readbackProfile";

  status |= pC_->getDoubleParam(axisNo_, pC_->motorRecResolution_, &resolution);
  status |= pC_->getDoubleParam(axisNo_, pC_->motorRecOffset_, &offset);
  status |= pC_->getIntegerParam(axisNo_, pC_->motorRecDirection_, &direction);
  status |= pC_->getIntegerParam(0, pC_->profileNumReadbacks_, &numReadbacks);
  if (status) return asynError;

  // 转换成用户单位
  if (direction != 0) resolution = -resolution;
  for (i=0; i<numReadbacks; i++) {
    profileReadbacks_[i] = profileReadbacks_[i] * resolution + offset;
    profileFollowingErrors_[i] = profileFollowingErrors_[i] * resolution;
  }
  status  = pC_->doCallbacksFloat64Array(profileReadbacks_,       numReadbacks, pC_->profileReadbacks_, axisNo_);
  status |= pC_->doCallbacksFloat64Array(profileFollowingErrors_, numReadbacks, pC_->profileFollowingErrors_, axisNo_);
  return asynSuccess;
}

/****************************************************************************/
/* 
    以下函数是由自动化驱动电源控制在asynMotorControler中基类poller中使用。
*/

/**
* 读取指示上次poll是否正在运行的标记
*/
int asynMotorAxis::getWasMovingFlag(void)
{
  return wasMovingFlag_;
}

/**
* 如果之前查询表明移动状态,设置为1
 */
void asynMotorAxis::setWasMovingFlag(int wasMovingFlag)
{
  wasMovingFlag_ = wasMovingFlag;
}

/**
 * 表明驱动是否应该自定被禁用的标记
 */
int asynMotorAxis::getDisableFlag(void)
{
  return disableFlag_;
}

/**
 * 如果驱动应该自动被禁用,设置此为1
 */
void asynMotorAxis::setDisableFlag(int disableFlag)
{
  disableFlag_ = disableFlag;
}

/**
 * 读取上次移动结束的时间(以秒为单位)
 */
double asynMotorAxis::getLastEndOfMoveTime(void)
{
  return lastEndOfMoveTime_;
}

/**
 * Set this to the current time at the end of a move.
 * 将这个设置到移动结束时的当前时间
 */
void asynMotorAxis::setLastEndOfMoveTime(double time)
{
  lastEndOfMoveTime_ = time;
}

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
图像识别技术在病虫害检测中的应用是一个快速发展的领域,它结合了计算机视觉和机器学习算法来自动识别和分植物上的病虫害。以下是这一技术的一些关键步骤和组成部分: 1. **数据收集**:首先需要收集大量的植物图像数据,这些数据包括健康植物的图像以及受不同病虫害影响的植物图像。 2. **图像预处理**:对收集到的图像进行处理,以提高后续分析的准确性。这可能包括调整亮度、对比度、去噪、裁剪、缩放等。 3. **特征提取**:从图像中提取有助于识别病虫害的特征。这些特征可能包括颜色、纹理、形状、边缘等。 4. **模型训练**:使用机器学习算法(如支持向量机、随机森林、卷积神经网络等)来训练模型。训练过程中,算法会学习如何根据提取的特征来识别不同的病虫害。 5. **模型验证和测试**:在独立的测试集上验证模型的性能,以确保其准确性和泛化能力。 6. **部署和应用**:将训练好的模型部署到实际的病虫害检测系统中,可以是移动应用、网页服务或集成到智能农业设备中。 7. **实时监测**:在实际应用中,系统可以实时接收植物图像,并快速给出病虫害的检测结果。 8. **持续学习**:随着时间的推移,系统可以不断学习新的病虫害样本,以提高其识别能力。 9. **用户界面**:为了方便用户使用,通常会有一个用户友好的界面,显示检测结果,并提供进一步的指导或建议。 这项技术的优势在于它可以快速、准确地识别出病虫害,甚至在早期阶段就能发现问题,从而及时采取措施。此外,它还可以减少对化学农药的依赖,支持可持续农业发展。随着技术的不断进步,图像识别在病虫害检测中的应用将越来越广泛。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值