optical/NxFuncs/closedriver/driversctrl.c
2025-09-04 09:45:08 +08:00

1519 lines
32 KiB
C

#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