#include "config.h" #include "driversctrl.h" #if (DRIVERS_NUM > 0) #include "stepmotos.h" #include "inout.h" #include "delay.h" #include "shell.h" #include "trigger.h" #include "cpuid.h" #include "driverparas.h" //------------------------------------------------------------------------ #include "drivermotion.h" //------------------------------------------------------------------------ #ifndef MOTO_ECD_PER_CIRCLE #define MOTO_ECD_PER_CIRCLE 4000 #endif //------------------------------------------------------------------------ #define OUT_INFO_NUM 0 typedef struct { s32 cmdPosition; // 指令位置 s32 targetMotoPos; // 目标位置 s32 ecdPosition; // 编码器位置 s32 thisPosErr; // 位置偏差 s32 integral; // 偏差积分 s32 differential; // 位置微分 s32 thisactVel; // 本次检测速度值 s32 pospid; // 位置PID s32 setMotoPos; // 设置位置 s32 effort; // 设置电流 }DrvOutInfo; #ifndef DEF_SPD_FIL #define DEF_SPD_FIL 0 #endif typedef struct { //---------------------- int motoIdx; // 电机索引 void (*InitEncoder)(void); int (*ReadEncoderCounter)(void); //---------------------- DriverPara paras; // 参数 //---------------------- int powerEnFlag; // 使能标志 //---------------------- float stepAngle; // 细分 //---------------------- s32 runspeed; // 运行速度 s32 speedadd; // 内部运行加速度 int runsta; //---------------------- s32 cmdPosition; // 指令位置统计(电角度) s32 ecdPosition; // 编码器位置统计(电角度) s32 runPosition; // 运行位置统计(电角度) s32 lastPosErr; // 上次的偏差(电角度) s32 integral; s32 differential; #if (DEF_SPD_FIL > 1) s32 spdBuff[DEF_SPD_FIL]; s32 spdIdx; s32 spdSum; #endif // s32 lastVel; // s32 lastVErr; // s32 lastDErr; // 上上次的偏差 s32 intev; s32 effort; // 输出电流 //---------------------- s32 lastThetaGap; //---------------------- s32 exCmdCounter; // 外部指令计数 //---------------------- s32 posOffset; //---------------------- int first; s32 oldTheta; // 上次的角度(电角度) s32 oldCounter; // 上次的指令计数 s32 halfCounter; // 开环半流计数器 //---------------------- int errorCode; // 错误代码 //---------------------- #if (OUT_INFO_NUM != 0) int timeCount; int timeGap; int outInfoIdx; int outInfoEn; DrvOutInfo outInfoList[OUT_INFO_NUM+1]; #endif }DriverCtrl; //------------------------------------------------------------------------ DriverCtrl g_driverCtrl[DRIVERS_NUM]; //------------------------------------------------------------------------ void InitCloseCtrl(int driverIdx); int GetThetaValue(int driverIdx); void SetMotoDirectionCtrl(int driverIdx, int dirbit); void SetMotoPulseCtrl(int driverIdx, int dirbit); //------------------------------------------------------------------------ float CalcStepAngle(s32 stepPerCircle, s32 numerator, s32 denominator); int GetThetaFromEcd(int ecdvalue); int LoadCtrlPara(); //------------------------------------------------------------------------ const char * DRV_HLP_STR = "\t""测试电机驱动" "\r\n" "\t" "p1 p2" "\r\n" "\t" "0 x" "显示x驱动参数, 0 全部显示" "\r\n" "\t""x0d n" "设置x驱动参数d的值为n" "\r\n" "\t""x000 m" "开环步进方式运动x电机" "\r\n" "\t\t" "m=0" "失能" "\r\n" "\t\t" "m=1" "使能" "\r\n" "\t\t" "m=2" "正向整步" "\r\n" "\t\t" "m=3" "负向整步" "\r\n" "\t\t" "m=4" "正向微步" "\r\n" "\t\t" "m=5" "负向微步" "\r\n" "\t" "x000d n" "驱动器方式运动x电机,位移为n" "\r\n" ; void TestDriver(char * para1, char * para2); void ShowDriver(char * para1, char * para2); //------------------------------------------------------------------------ #define RD_CALIB_PPC (100) // (4000) //----------------------------------------------------------- #define IDX_RANGE 10 #define PID_RANGE 1024 // PID 参数分母 #define PULSE_COUNTER_RELOAD (S32_MAX-1) // 外部脉冲计数器重装载值 #define LOW_CIRCLE_TIME 2000 // 低电流锁定时间 (2k) #define ADVANCE_ADJ_MAX ((MOTO_PPC)/MOTO_NOPP/5) // 调整偏差 #define MIN_PE_LIMIT ((MOTO_PPC)/MOTO_NOPP/32) // 最小偏差允许 #define MAX_PE_LIMIT (MOTO_PPC/10) // 最大偏差限制 #define MAX_IG_LIMIT (RD_CALIB_PPC*PID_RANGE) // 积分项目饱和限制 #define MAX_IS_LIMIT (MAX_IG_LIMIT*90/100) // 积分分段最大限制 #define MIN_IS_LIMIT (MAX_IG_LIMIT*50/100) // 积分分段最小限制 #define EFF_MAX (MAX_OUT_LEV *1) #define EFF_MIN (MAX_OUT_LEV *-1) #define MIN_OUT_EFF 0 #define DEF_OUT_EFF 50 #define POS_PER_CIRCLE (MOTO_ECD_PER_CIRCLE) //------------------------------------------------------------------------ //------------------------------------------------------------------------ #define MOTO_INIT(id) do \ {\ SetMotoCtrlFuncs(DRIVER##id##_IDX, \ SetMoto##id##CoilAPwm, SetMoto##id##ACPOn, SetMoto##id##ACPOff, SetMoto##id##ACNOn, SetMoto##id##ACNOff, \ SetMoto##id##CoilBPwm, SetMoto##id##BCPOn, SetMoto##id##BCPOff, SetMoto##id##BCNOn, SetMoto##id##BCNOff); \ \ SetMotoCCWDir(DRIVER##id##_IDX, MOTO##id##_CCWDIR); /* 设置方向 */ \ \ SetMoto##id##CoilPwmEnable(); /* 允许PWM输出 */ \ \ g_driverCtrl[id-1].ReadEncoderCounter = ReadMoto##id##EncoderCounter; \ g_driverCtrl[id-1].InitEncoder = InitMoto##id##Encoder; \ }while(0) //------------------------------------------------------------------------ void InitDriversCtrl(void) { int i; // 电机初始化 InitStepMotos(); // 初始化步进电机控制 InitDrvMotions(); // 初始化内置运动控制 // 驱动控制 memset(g_driverCtrl, 0, sizeof(DriverCtrl)*DRIVERS_NUM); #if (DRIVERS_NUM >= 1) MOTO_INIT(1); #endif #if (DRIVERS_NUM >= 2) MOTO_INIT(2); #endif #if (DRIVERS_NUM >= 3) MOTO_INIT(3); #endif #if (DRIVERS_NUM >= 4) MOTO_INIT(4); #endif // 装载默认参数 InitDriverParas(); for (i = 0; i < DRIVERS_NUM; i++) { g_driverCtrl[i].motoIdx = i; // 从参数文件装载参数值 memcpy(&(g_driverCtrl[i].paras), GetDriverParas(i), sizeof(DriverPara)); // 计算细分 g_driverCtrl[i].stepAngle = CalcStepAngle(g_driverCtrl[i].paras.stepPerCircle, g_driverCtrl[i].paras.numerator, g_driverCtrl[i].paras.denominator); printf("moto%d stepAngle=%.2f\r\n", i+1, g_driverCtrl[i].stepAngle); // 重置默认参数 } //----------------------- //----------------------- // 闭环控制初始位置 for (i = 0; i < DRIVERS_NUM; i++) { SetEnableCtrl(i, 0); } DelayMs(10); // 开始时固定在整步位置 for (i = 0; i < DRIVERS_NUM; i++) { if (g_driverCtrl[i].paras.closeCtrlMode != 0) { ResetMotoPos(i, 100); } else { g_driverCtrl[i].halfCounter = LOW_CIRCLE_TIME; } } DelayMs(200); // 初始化编码器计数(根据固定整步位置) for (i = 0; i < DRIVERS_NUM; i++) { g_driverCtrl[i].InitEncoder(); } DelayMs(10); // 使能电机 for (i = 0; i < DRIVERS_NUM; i++) { SetEnableCtrl(i, 1); } DelayMs(100); #if (OUT_INFO_NUM != 0) g_driverCtrl[0].outInfoIdx = 0; g_driverCtrl[0].timeGap = 0; g_driverCtrl[0].outInfoEn = 1; #endif // 打开控制周期,开始控制 if (1) { printf("StartControlCycle\r\n"); StartControlCycle(); } #if (0) AddShellCmd("DRIVER", DRV_HLP_STR, TestDriver); #else AddShellCmd("DRIVER", "", ShowDriver); #endif } //------------------------------------------------------------------------ void InitCloseCtrl(int driverIdx) { s32 rdTheta = 0; DriverCtrl * pCtrl; if (driverIdx < 0 || driverIdx >= DRIVERS_NUM) { return; } pCtrl = &g_driverCtrl[driverIdx]; rdTheta = GetThetaValue(driverIdx); pCtrl->cmdPosition = rdTheta / pCtrl->stepAngle; // 指令位置统计(电角度) pCtrl->ecdPosition = rdTheta; // 编码器位置统计(电角度) pCtrl->runPosition = rdTheta; // 运行位置统计(电角度) pCtrl->lastPosErr = 0; // 上次的偏差 pCtrl->integral = 0; // 积分 // pCtrl->lastDErr = 0; // 上上次的偏差 pCtrl->effort = 0; // 输出电流 printf("\r\n InitCloseCtrl, g_driverCtrl[%d]:\r\n" "\t rdTheta=%d, \r\n" "\t stepAngle=%f, \r\n" "\t cmdPosition=%d, \r\n" "\t ecdPosition=%d, \r\n" "\t runPosition=%d, \r\n", driverIdx, rdTheta, pCtrl->stepAngle, pCtrl->cmdPosition, pCtrl->ecdPosition, pCtrl->runPosition); pCtrl->first = 1; } void SetEnableCtrl(int driverIdx, int enbit) { DriverCtrl * pCtrl; if (driverIdx < 0 || driverIdx >= DRIVERS_NUM) { return; } pCtrl = &g_driverCtrl[driverIdx]; if (enbit != 0) { if (pCtrl->powerEnFlag == 0 && pCtrl->paras.closeCtrlMode != 0) { InitCloseCtrl(driverIdx); SetMotoPosTo(pCtrl->motoIdx, pCtrl->ecdPosition, DEF_OUT_EFF); // 行走到目标位置 } pCtrl->powerEnFlag = 1; printf("set moto%d en on\r\n", pCtrl->motoIdx+1); } else { if (pCtrl->powerEnFlag != 0) { pCtrl->powerEnFlag = 0; DelayUs(200); SetMotoEnable(pCtrl->motoIdx, 0); } printf("set moto%d en off\r\n", pCtrl->motoIdx+1); } } int GetThetaFromEcd(int ecdvalue) { #if (SIN_TAB_SIZE == POS_PER_CIRCLE) // 简化计算, 编码器和正弦表数量相同 ecdvalue *= MOTO_NOPP; #else ecdvalue *= MOTO_PPC; ecdvalue /= POS_PER_CIRCLE; #endif return ecdvalue; } int GetMotoThetaValue(DriverCtrl * pCtrl) { if (pCtrl == NULL) { return 0; } int ecdvalue = pCtrl->ReadEncoderCounter(); ecdvalue += pCtrl->paras.ecdAdjust; return GetThetaFromEcd(ecdvalue); } // int GetThetaValue(int driverIdx) { DriverCtrl * pCtrl; if (driverIdx < 0 || driverIdx >= DRIVERS_NUM) { return 0; } pCtrl = &g_driverCtrl[driverIdx]; return GetMotoThetaValue(pCtrl); } float CalcStepAngle(s32 stepPerCircle, s32 numerator, s32 denominator) { float stepAngle = 1.0f; if (stepPerCircle != 0) { stepAngle = (1.0f*MOTO_PPC/stepPerCircle); } else if (denominator != 0) { stepAngle = (1.0f*MOTO_PPC*numerator/denominator); } return stepAngle; } //------------------------------------------------------------------------ //------------------------------------------------------------------------------------ void MotoCloseCtrlProc(DriverCtrl * pCtrl) { if (pCtrl == NULL) { return; } if (pCtrl->powerEnFlag <= 0) // 非使能状态下 { return; } #if (OUT_INFO_NUM != 0) pCtrl->timeCount++; if (pCtrl->outInfoEn != 0) { if (pCtrl->timeGap <= 0) { pCtrl->timeGap = 1; } if ((pCtrl->timeCount % pCtrl->timeGap) == 0) { pCtrl->outInfoIdx++; if (pCtrl->outInfoIdx >= OUT_INFO_NUM) { pCtrl->outInfoEn = 0; } } } #endif s32 targetMotoPos; // 理论目标位置 s32 setMotoPos; // 本次计算实际目标位置 s32 effort; // 电流 s32 tmps32; s32 thisactVel = 0; // 和上一次比较的电角度差值 // 读取编码器位置 // if (pCtrl->paras.closeCtrlMode != 0) { s32 rdTheta; // 当前电角度 s32 thisThetaGap; // 电角度差值(和上一次比较) rdTheta = GetMotoThetaValue(pCtrl); // 读取编码器, 转换为电角度 if (pCtrl->first == 1) { pCtrl->oldTheta = rdTheta; } thisThetaGap = rdTheta - pCtrl->oldTheta; // 电角度差值 // 转换为-180-180度之间 if (thisThetaGap < -MOTO_PPC/2) // 反转 { thisThetaGap += MOTO_PPC; } else if (thisThetaGap > MOTO_PPC/2) { thisThetaGap -= MOTO_PPC; } #if (DEF_SPD_FIL > 1) pCtrl->spdIdx++; if (pCtrl->spdIdx >= DEF_SPD_FIL) { pCtrl->spdIdx = 0; } pCtrl->spdSum -= pCtrl->spdBuff[pCtrl->spdIdx]; pCtrl->spdBuff[pCtrl->spdIdx] = thisThetaGap; pCtrl->spdSum += thisThetaGap; thisactVel = pCtrl->spdSum/DEF_SPD_FIL; // 速度值 #else thisactVel = thisThetaGap; #endif pCtrl->ecdPosition += thisThetaGap; #if (OUT_INFO_NUM != 0) pCtrl->outInfoList[pCtrl->outInfoIdx].thisactVel = thisactVel; pCtrl->outInfoList[pCtrl->outInfoIdx].ecdPosition = pCtrl->ecdPosition; #endif pCtrl->oldTheta = rdTheta; } // 读取指令位置 { s32 thisCmdGap; // 本次和上次的指令位置偏差 s32 rdCounter; // 目标位置,指令计数 rdCounter = pCtrl->exCmdCounter; if (pCtrl->first == 1) { pCtrl->oldCounter = rdCounter; if (pCtrl->paras.closeCtrlMode != 0) // 闭环模式 { pCtrl->cmdPosition = pCtrl->ecdPosition / pCtrl->stepAngle; } } thisCmdGap = rdCounter - pCtrl->oldCounter; if (thisCmdGap < -1*(s32)(PULSE_COUNTER_RELOAD/2)) // 反转 { thisCmdGap += PULSE_COUNTER_RELOAD; } else if (thisCmdGap > PULSE_COUNTER_RELOAD/2) { thisCmdGap -= PULSE_COUNTER_RELOAD; } pCtrl->oldCounter = rdCounter; // 累计指令位置 pCtrl->cmdPosition += thisCmdGap; #if (OUT_INFO_NUM != 0) pCtrl->outInfoList[pCtrl->outInfoIdx].cmdPosition = pCtrl->cmdPosition; #endif } targetMotoPos = (s32)(pCtrl->cmdPosition * pCtrl->stepAngle); // 计算位置初值为指令位置 #if (OUT_INFO_NUM != 0) pCtrl->outInfoList[pCtrl->outInfoIdx].targetMotoPos = targetMotoPos; #endif if (pCtrl->paras.closeCtrlMode == 0) // 开环模式 { if (targetMotoPos == pCtrl->runPosition) { pCtrl->halfCounter++; } else { pCtrl->halfCounter = 0; // 开环模式下的速度限制, 防止丢步 tmps32 = targetMotoPos - pCtrl->runPosition; if (tmps32 > pCtrl->paras.openMaxOffset) { targetMotoPos = pCtrl->runPosition + pCtrl->paras.openMaxOffset; } else if (tmps32 < -1*pCtrl->paras.openMaxOffset) { targetMotoPos = pCtrl->runPosition - pCtrl->paras.openMaxOffset; } } setMotoPos = targetMotoPos; if (pCtrl->halfCounter > LOW_CIRCLE_TIME) { pCtrl->halfCounter = LOW_CIRCLE_TIME; effort = pCtrl->paras.openLockCircle; // 锁定电流 } else { effort = pCtrl->paras.openRunCircle; // 驱动电流 } } else // 闭环控制 { // 位置闭环 s32 pospid = 0; s32 thisPosErr = 0; // 位置偏差(电角度) { int index = 0; thisPosErr = targetMotoPos - pCtrl->ecdPosition; // 最大偏差36度? if (thisPosErr > MAX_PE_LIMIT) // 限制偏差范围 { thisPosErr = MAX_PE_LIMIT; } else if (thisPosErr < -MAX_PE_LIMIT) { thisPosErr = -MAX_PE_LIMIT; } // 位置PID // 分段积分 if ((thisPosErr >= 0 && pCtrl->lastPosErr <= 0) || (thisPosErr <= 0 && pCtrl->lastPosErr >= 0) ) // 本次与上次运动方向相反 { pCtrl->integral /= 128; // 积分快速下降 } if (abs(thisPosErr + pCtrl->lastPosErr) < 10) // 是否可以理解为接近目标位置或在目标位置附近抖动 { index = IDX_RANGE; pCtrl->integral /= 16; // 2 // 积分快速下降 } else if (abs(thisPosErr) > MAX_IS_LIMIT) { index = 0; } else { if (abs(thisPosErr) < MIN_IS_LIMIT) { index = IDX_RANGE; } else { index = ((MAX_IS_LIMIT) - abs(thisPosErr)) * IDX_RANGE / ((MAX_IS_LIMIT - MIN_IS_LIMIT)); } // 抗积分饱和 if (pCtrl->effort > EFF_MAX) { if (thisPosErr < 0) { pCtrl->integral += thisPosErr; } } else if (pCtrl->effort < EFF_MIN) { if (thisPosErr > 0) { pCtrl->integral += thisPosErr; } } else { pCtrl->integral += thisPosErr; } // 积分项饱和限制 if (pCtrl->integral > MAX_IG_LIMIT) { pCtrl->integral = MAX_IG_LIMIT; } else if (pCtrl->integral < -MAX_IG_LIMIT) { pCtrl->integral = -MAX_IG_LIMIT; } } // 微分项, 微分滤波 tmps32 = (thisPosErr - pCtrl->lastPosErr); pCtrl->differential = (pCtrl->differential * 26 + tmps32 * 230) / 256; pCtrl->lastPosErr = thisPosErr; // 记录上次的误差 // 计算位置PID pospid = ( ( (pCtrl->paras.kp * thisPosErr) + (pCtrl->paras.ki * pCtrl->integral * index / PID_RANGE) + (pCtrl->paras.kd * pCtrl->differential) ) / PID_RANGE); #if (OUT_INFO_NUM != 0) pCtrl->outInfoList[pCtrl->outInfoIdx].thisPosErr = thisPosErr; pCtrl->outInfoList[pCtrl->outInfoIdx].integral = pCtrl->integral; pCtrl->outInfoList[pCtrl->outInfoIdx].differential = pCtrl->differential; pCtrl->outInfoList[pCtrl->outInfoIdx].pospid = pospid; #endif } // 位置前馈 tmps32 = pCtrl->ecdPosition + pCtrl->paras.closeAdjust; // 以编码器位置为基准位置 s32 advance = thisactVel; // 速度作为 前馈角度 s32 basecircle = pCtrl->paras.basecircle; #if (0) // 20240105 临时改进 if (pospid > 200) { advance += (MAX_ADVANCE+MICO_ADVANCE+MIN_ADVANCE); } else if(pospid < -200) { advance -= (MAX_ADVANCE+MICO_ADVANCE+MIN_ADVANCE); } else if (pospid > 100) { advance += (MAX_ADVANCE+MIN_ADVANCE); } else if(pospid < -100) { advance -= (MAX_ADVANCE+MIN_ADVANCE); } else #endif if (pospid > 50) { advance += (MAX_ADVANCE); // 1.8度 } else if(pospid < -50) { advance -= (MAX_ADVANCE); } else if (pospid > 10) { advance += (MICO_ADVANCE); // 0.36度 } else if(pospid < -10) { advance -= (MICO_ADVANCE); } else { #if (0)// 临时测试使用 static int flag = 0; if (abs(advance) < MIN_ADVANCE) { if (flag == 0) { printf("pid=%d,A:%d\r\n", pospid, advance); flag = 1; } basecircle = 0; advance = 0; } else { flag = 0; } #else if (abs(advance) <= MIN_ADVANCE) { basecircle = 0; advance = 0; } #endif } setMotoPos = tmps32 + advance; // 电流 #if (0) // 20240826 effort = abs(pospid); if (effort > 4000) { effort /= 8; } else if (effort > 2000) { effort /= 6; } else if (effort > 800) { effort /= 4; } else if (effort > 200) { effort /= 2; } effort = basecircle + effort * pCtrl->paras.closeCircle / PID_RANGE; #else effort = basecircle + abs(pospid)/8 * pCtrl->paras.closeCircle / PID_RANGE; #endif // 20240109 ljs 电流延迟下降 if (effort < pCtrl->effort) { if (abs(effort - pCtrl->effort) > 10) { effort = pCtrl->effort - 10; } } } // 电流控制 { SetMotoPosTo(pCtrl->motoIdx, setMotoPos, effort); // 行走到目标位置 pCtrl->runPosition = setMotoPos; // 记录电机位置(电角度) pCtrl->effort = effort; #if (OUT_INFO_NUM != 0) pCtrl->outInfoList[pCtrl->outInfoIdx].setMotoPos = setMotoPos; pCtrl->outInfoList[pCtrl->outInfoIdx].effort = effort; #endif } #if (0) if (pCtrl->first == 1) { printf("MotoCloseCtrlProc first run\r\n"); } #endif pCtrl->first = 0; } //------------------------------------------------------------------------ #define CPU_RATE 0 // 测试利用率 u32 g_workGap = 0; float g_cpuRate = 0; void CPURateIntProc(int section) { #if (CPU_RATE != 0) #if (1) if (section == 0) { SetDebugOn(); } else if (section == 1) { SetDebugOff(); } #else static u32 workBeg = 0; static u32 workEnd = 0; static u32 lastEnd = 0; if (section == 0) { SetDebugOn(); workBeg = GetUsSoftTimer(); } else if (section == 1) { workEnd = GetUsSoftTimer(); g_workGap = workEnd - lastEnd; lastEnd = workEnd; if (g_workGap != 0) { g_cpuRate = (workEnd - workBeg) * 100.0 / g_workGap; } SetDebugOff(); } #endif #endif } // 控制中断, 10K void DriversCtrlIntProc(void) { #if (1) // 运动控制计算 DrvMotionCalcProc(); #endif #if (1) // 电机控制 DriverCtrl * pCtrl; for (int i = 0; i < DRIVERS_NUM; i++) { pCtrl = &g_driverCtrl[i]; if (pCtrl->paras.cmdSource == 0) // 内部指令 { pCtrl->exCmdCounter = GetDrvMotionRealPos(i) + pCtrl->posOffset; // 更新运动控制位置到指令位置 } MotoCloseCtrlProc(pCtrl); } #endif } //------------------------------------------------------------------------ u32 GetDrvErrorCode(int driverIdx) { DriverCtrl * pCtrl; if (driverIdx < 0 || driverIdx >= DRIVERS_NUM) { return 0; } pCtrl = &g_driverCtrl[driverIdx]; return pCtrl->errorCode; } void CleanDrvErrorCode(int driverIdx) { DriverCtrl * pCtrl; if (driverIdx < 0 || driverIdx >= DRIVERS_NUM) { return; } pCtrl = &g_driverCtrl[driverIdx]; pCtrl->errorCode = 0; } void SetDrvErrorCode(int driverIdx, int code) { DriverCtrl * pCtrl; if (driverIdx < 0 || driverIdx >= DRIVERS_NUM) { return; } pCtrl = &g_driverCtrl[driverIdx]; pCtrl->errorCode = code; } //-------------------------------------------------------------------------- #ifndef CLOSEMOTO_POSERR_MAXVAL #define CLOSEMOTO_POSERR_MAXVAL (MOTO_PPC*2) #endif void DriverRunTask(void) { s32 poserr = 0; DriverCtrl * pCtrl; for (int i = 0; i < DRIVERS_NUM; i++) { pCtrl = &g_driverCtrl[i]; if (pCtrl->errorCode == 0 && pCtrl->paras.closeCtrlMode == CTRLMODE_CLOSE && 1) { // 检测位置误差过大错误 poserr = abs(pCtrl->cmdPosition*pCtrl->stepAngle - pCtrl->ecdPosition); if (poserr > CLOSEMOTO_POSERR_MAXVAL) { printf("driver %d pos error, cmdPosition=%d, ecdPosition=%d, sub=%d\r\n", i+1, pCtrl->cmdPosition, pCtrl->ecdPosition, poserr); pCtrl->errorCode = DR_ERR_POS; // 出现错误 SetEnableCtrl(i, 0); // 断使能 } } } } //------------------------------------------------------------------------ // 重置驱动器位置 void ResetDriverPos(int driverIdx, s32 pos) { DriverCtrl * pCtrl; if (driverIdx < 0 || driverIdx >= DRIVERS_NUM) { return; } pCtrl = &g_driverCtrl[driverIdx]; printf("reset pos to=%d\r\n", pos); EnterCritical(); s32 cpos = GetDrvMotionRealPos(driverIdx); SetDrvMotionRealPos(driverIdx, pos); s32 ofst = cpos - pos; pCtrl->posOffset += ofst; ExitCritical(); } void SetDriverTargetPos(int driverIdx, s32 tpos) { SetDrvMotionRealPos(driverIdx, tpos); } void SetDriverOffset(int driverIdx, s32 ofst) { s32 cpos = GetDrvMotionRealPos(driverIdx); s32 tpos = cpos + ofst; SetDrvMotionRealPos(driverIdx, tpos); } //------------------------------------------------------------------------------------ void SetOpenRunCircle(int driverIdx, int circle) { DriverCtrl * pCtrl; if (driverIdx < 0 || driverIdx >= DRIVERS_NUM) { return; } pCtrl = &g_driverCtrl[driverIdx]; pCtrl->paras.openRunCircle = circle; } void SetOpenLockCircle(int driverIdx, int circle) { DriverCtrl * pCtrl; if (driverIdx < 0 || driverIdx >= DRIVERS_NUM) { return; } pCtrl = &g_driverCtrl[driverIdx]; pCtrl->paras.openLockCircle = circle; } void SetOpenMaxOffset(int driverIdx, int maxofst) { DriverCtrl * pCtrl; if (driverIdx < 0 || driverIdx >= DRIVERS_NUM) { return; } pCtrl = &g_driverCtrl[driverIdx]; pCtrl->paras.openMaxOffset = maxofst; } s32 GetClosePositionFromEcd(int driverIdx) { DriverCtrl * pCtrl; if (driverIdx < 0 || driverIdx >= DRIVERS_NUM) { return 0; } pCtrl = &g_driverCtrl[driverIdx]; return pCtrl->ecdPosition / pCtrl->stepAngle; } void SetCloseCircle(int driverIdx, int circle) { DriverCtrl * pCtrl; if (driverIdx < 0 || driverIdx >= DRIVERS_NUM) { return; } pCtrl = &g_driverCtrl[driverIdx]; pCtrl->paras.closeCircle = circle; } //------------------------------------------------------------------------------------ #define ANGLE_PER_CIRCLE 36000 // 360 度 s32 CalcAngleByEcdValue(s32 ecd) { s32 angle = -1; float counter; counter = ecd; if (counter < 0) { } counter = (counter * ANGLE_PER_CIRCLE / MOTO_ECD_PER_CIRCLE); // 计算角度 angle = counter + (counter>0?(counter!=0?1:0):-1) * (0.500001f); // 角度值在区间 [0, ANGLE_PER_CIRCLE) while (angle < 0) { angle += ANGLE_PER_CIRCLE; } while (angle >= ANGLE_PER_CIRCLE) { angle -= ANGLE_PER_CIRCLE; } return angle; } //------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------ // 设置电机控制模式, 0开环 1闭环 void SetDriverCtrlMode(int driverIdx, int mode) { if (driverIdx < 0 || driverIdx >= DRIVERS_NUM || (mode != 0 && mode != 1) || 0) { return; } // 设置参数,先去使能 SetEnableCtrl(driverIdx, 0); int ctrlmod = g_driverCtrl[driverIdx].paras.closeCtrlMode; if (mode == 0) { printf("set moto%d ctrlmode to open\r\n", driverIdx+1); } else if (mode == 1) { printf("set moto%d ctrlmode to close\r\n", driverIdx+1); } g_driverCtrl[driverIdx].paras.closeCtrlMode = mode; if (ctrlmod != g_driverCtrl[driverIdx].paras.closeCtrlMode && // 控制模式不同 g_driverCtrl[driverIdx].paras.closeCtrlMode != 0 && // 闭环控制 1) { ResetMotoPos(driverIdx, 100); DelayMs(200); g_driverCtrl[driverIdx].InitEncoder(); DelayMs(10); } DelayMs(1); SetEnableCtrl(driverIdx, 1); } //------------------------------------------------------------------------------------ void DlBlk(u32 dl) { } // DRIVER void TestDriver(char * para1, char * para2) { int p1, p2; p1 = p2 = 0; if (para1 != NULL && strcmp(para1, "") != 0) { p1 = atoi(para1); } if (para2 != NULL && strcmp(para2, "") != 0) { p2 = atoi(para2); } if (p1 == p2) { } //-------------------------------- DriverPara * pParas; if (p1 >= 0 && p1 < 500) { int i; int alllop = 0; int dridx = p1/100; int paidx = p1%100; int lopcount; int didxcount; if (dridx == 0) { if (p2 == 0) { printf("gap=%d, cpu rate=%.2f%%\r\n", g_workGap, g_cpuRate); alllop = DRIVERS_NUM; } } else { dridx -= 1; } lopcount = alllop; didxcount = dridx; do { if (didxcount >= 0 && didxcount < DRIVERS_NUM) { pParas = &(g_driverCtrl[didxcount].paras); if (paidx == 0) { printf("\r\nmoto%d paras:\r\n", didxcount+1); for (i = 0; i < DRV_PARA_NUMS; i++) { const char * parastr = GetDriverParaName(i); if (parastr != NULL && strlen(parastr) != 0) { printf(" %d. %s = %d\r\n", i+1, parastr, *((int*)(((u32)pParas) + i*4))); } } printf("\r\n g_driverCtrl[%d] values:\r\n" "\t cmdPosition=%d, \r\n" "\t ecdPosition=%d, \r\n" "\t runPosition=%d, \r\n", didxcount, g_driverCtrl[didxcount].cmdPosition, g_driverCtrl[didxcount].ecdPosition, g_driverCtrl[didxcount].runPosition); } else { // 设置参数,先去使能 SetEnableCtrl(didxcount, 0); int ctrlmod = g_driverCtrl[dridx].paras.closeCtrlMode; printf("set %s = %d, old = %d\r\n", GetDriverParaName(paidx-1), p2, *((int*)(((u32)pParas) + (paidx-1)*4))); *((int*)(((u32)pParas) + (paidx-1)*4)) = p2; g_driverCtrl[dridx].stepAngle = CalcStepAngle(g_driverCtrl[dridx].paras.stepPerCircle, g_driverCtrl[dridx].paras.numerator, g_driverCtrl[dridx].paras.denominator); if (ctrlmod != g_driverCtrl[dridx].paras.closeCtrlMode && g_driverCtrl[dridx].paras.closeCtrlMode != 0 ) { ResetMotoPos(dridx, 50); DelayMs(200); g_driverCtrl[dridx].InitEncoder(); DelayMs(10); } printf("moto%d stepAngle=%.2f\r\n", dridx+1, g_driverCtrl[dridx].stepAngle); DelayMs(1); #if (OUT_INFO_NUM != 0) g_driverCtrl[dridx].outInfoIdx = 0; g_driverCtrl[dridx].timeGap = 0; g_driverCtrl[dridx].outInfoEn = 1; #endif SetEnableCtrl(didxcount, 1); } } if (lopcount != 0) { lopcount--; didxcount++; DelayMs(100); continue; } else { break; } }while(1); } #if (1) if (p1 >= 1000 && p1 < 5000) {// 测试电机编码器 int dridx = p1/1000 - 1; int paidx = p1%1000; if (dridx < 0 || dridx >= DRIVERS_NUM) { return; } int sel, count; sel = p2%10; count = p2/10; DriverCtrl * pCtrl; pCtrl = &(g_driverCtrl[dridx]); int rslt, arsult; int ang; SetEnableCtrl(dridx, 0); DelayMs(1); do { rslt = pCtrl->ReadEncoderCounter(); ang = CalcAngleByEcdValue(rslt); printf("before run moto%d, rslt=%d(0x%x), ang=%.2f\r\n", dridx+1, rslt, rslt, ang/100.0); if (paidx == 0) { if (sel == 0) { ResetMotoPos(dridx, 0); } else if (sel == 1) { ResetMotoPos(dridx, 50); } else if (sel == 2) { MotoOneFullStep(dridx, 1, 50); } else if (sel == 3) { MotoOneFullStep(dridx, -1, 50); } else if (sel == 4) { MotoOneMicoStep(dridx, 1, 50); } else if (sel == 5) { MotoOneMicoStep(dridx, -1, 50); } else if (sel == 100) { } } DelayMs(50); arsult = pCtrl->ReadEncoderCounter(); ang = CalcAngleByEcdValue(arsult); printf("after run moto%d, rslt=%d(0x%x), ang=%.2f\r\n", dridx+1, arsult, arsult, ang/100.0, arsult-rslt); count--; }while(count > 0); } #endif if (p1 >= 10000 && p1 < 50000) {// 测试电机运动 int dridx = p1/10000 - 1; u32 timer; int rslt, arsult, ang; if (dridx < 0 || dridx >= DRIVERS_NUM) { return; } DriverCtrl * pCtrl; pCtrl = &(g_driverCtrl[dridx]); rslt = pCtrl->ReadEncoderCounter(); ang = CalcAngleByEcdValue(rslt); printf("before run moto%d, rslt=%d(0x%x), ang=%.2f, sub=%d\r\n", dridx+1, rslt, rslt, ang/100.0); printf("test run start, idx=%d, ", dridx); timer = GetMsSoftTimer(); { DrvMotionPara drpara; memset(&drpara, 0, sizeof(DrvMotionPara)); // 输入参数 drpara.movement = p2; // 位移量 drpara.startPPS = pCtrl->paras.startPPS; // 启动速度 drpara.runPPS = pCtrl->paras.runPPS; // 运动速度 drpara.addPPSS = pCtrl->paras.addPPSS; // 启停加速度 drpara.brkPPSS = pCtrl->paras.brkPPSS; // 刹车加速度 drpara.DelayWhenBlock = DlBlk; drpara.blockRunflag = 1; // 阻塞运行标志, =1阻塞运行,同步运动 =0,非阻塞,异步运动 DrvMotionStart(dridx, &drpara); // 启动运动控制 } timer = GetMsSoftTimer() - timer; printf("test run over, time=%dms\r\n", timer); DelayMs(100); arsult = pCtrl->ReadEncoderCounter(); ang = CalcAngleByEcdValue(arsult); printf("after run moto%d, rslt=%d(0x%x), ang=%.2f\r\n", dridx+1, arsult, arsult, ang/100.0, arsult-rslt); } if (p1 >= 100000 && p1 < 200000) { int dridx = 0; // 输入参数 DrvMotionPara drpara; DriverCtrl * pCtrl; for (dridx = 0; dridx < DRIVERS_NUM; dridx++) { printf("test run start, idx=%d, ", dridx); pCtrl = &(g_driverCtrl[dridx]); memset(&drpara, 0, sizeof(DrvMotionPara)); drpara.movement = p2; // 位移量 drpara.startPPS = pCtrl->paras.startPPS; // 启动速度 drpara.runPPS = pCtrl->paras.runPPS; // 运动速度 drpara.addPPSS = pCtrl->paras.addPPSS; // 启停加速度 drpara.brkPPSS = pCtrl->paras.brkPPSS; // 刹车加速度 drpara.funTestTime = 0; // 运行过程中外部函数检测间隔时间计数器 drpara.blockRunflag = 0; // 阻塞运行标志, =1阻塞运行,同步运动 =0,非阻塞,异步运动 DrvMotionStart(dridx, &drpara); // 启动运动控制 } do { printf("gap=%d, cpu rate=%.2f%%\r\n", g_workGap, g_cpuRate); if (IsConsoleCancel() != 0) { break; } DelayMs(10); }while(1); } if (p1 >= 200000 && p1 <= 240000) { #if (OUT_INFO_NUM != 0) int dridx = (p1-200000)/10000; if (dridx < 0 || dridx >= DRIVERS_NUM) { return; } DriverCtrl * pCtrl; pCtrl = &(g_driverCtrl[dridx]); int gap = p1 % 10000; if (p2 < 0) { int i = 0; int num = pCtrl->outInfoIdx; printf("out info num=%d\r\n", num); for (i = 1; i < num; i++) { printf( "%d " "%d " "%d " "%d " "%d " "%d " "%d " "%d " "%d " "%d " "%d " "\r\n" ,i ,pCtrl->outInfoList[i].cmdPosition // 指令位置 ,pCtrl->outInfoList[i].targetMotoPos // 目标位置 ,pCtrl->outInfoList[i].ecdPosition // 编码器位置 ,pCtrl->outInfoList[i].thisPosErr // 位置偏差 ,pCtrl->outInfoList[i].integral // 偏差积分 ,pCtrl->outInfoList[i].differential // 位置微分 ,pCtrl->outInfoList[i].pospid // 位置PID ,pCtrl->outInfoList[i].thisactVel // 本次速度 ,pCtrl->outInfoList[i].setMotoPos // 设置位置 ,pCtrl->outInfoList[i].effort // 设置电流 ); if (IsConsoleCancel() != 0) { break; } DelayMs(10); } } else { pCtrl->outInfoIdx = 0; pCtrl->timeGap = gap; pCtrl->outInfoEn = 1; printf("test out begin, idx=%d\r\n", dridx); // 输入参数 DrvMotionPara drpara; memset(&drpara, 0, sizeof(DrvMotionPara)); drpara.movement = p2; // 位移量 drpara.startPPS = pCtrl->paras.startPPS; // 启动速度 drpara.runPPS = pCtrl->paras.runPPS; // 运动速度 drpara.addPPSS = pCtrl->paras.addPPSS; // 启停加速度 drpara.brkPPSS = pCtrl->paras.brkPPSS; // 刹车加速度 drpara.blockRunflag = 0; // 阻塞运行标志, =1阻塞运行,同步运动 =0,非阻塞,异步运动 DrvMotionStart(dridx, &drpara); // 启动运动控制 do { if (pCtrl->outInfoEn == 0) { break; } if (IsConsoleCancel() != 0) { break; } }while(1); printf("test out end\r\n"); } #endif } } void ShowDriver(char * para1, char * para2) { int p1, p2; p1 = p2 = 0; if (para1 != NULL && strcmp(para1, "") != 0) { p1 = atoi(para1); } if (para2 != NULL && strcmp(para2, "") != 0) { p2 = atoi(para2); } if (p1 == p2) { } if (p1 == 1) { if (p2 > 0 && p2 <= DRIVERS_NUM) { printf("%d.cmdPosition=%d, ecdPosition=%d, runPosition=%d\r\n", p2, g_driverCtrl[p2-1].cmdPosition, g_driverCtrl[p2-1].ecdPosition, g_driverCtrl[p2-1].runPosition); } } } #endif