optical/NxFuncs/motions/curves.c
2025-09-04 09:45:08 +08:00

514 lines
10 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "curves.h"
//--------------------------------------------------
#include "trigger.h"
#include <math.h>
//--------------------------------------------------
#if (1) // T型速度曲线加减速四点式三段
//--------------------------------------------------
// 计算加减速需要的位移
// 参数: pps1 速度1
// pps2 速度2
// ppss 加速度
// 返回:
// 位移值
u32 TTypeCalcDisplacement(float pps1, float pps2, float ppss)
{
// 公式: d=(v2+v1)*(v2-v1)/(2a)
// v1 = pps1
// v2 = pps2
// a = ppss
float temp;
if (ppss == 0) // 加速度为0匀速直线运动
{
return 0;
}
if (pps1 < pps2)
{
temp = (pps2-pps1);
}
else
{
temp = (pps1-pps2);
}
temp *= (pps1+pps2);
temp /= ppss;
temp /= 2;
return (temp+0.5f);
}
//--------------------------------------------------
// 功能:计算某位移下速度变化需要加速度
// 参数:
// disp 位移
// pps1 速度1
// pps2 速度2
// 返回: 加速度
float TTypeCalcAddPPSS(u32 disp, float pps1, float pps2)
{
float temp;
// 公式: a=(v2+v1)*(v2-v1)/(2*d)
// v1 = pps1
// v2 = pps2
// d = disp
if (disp == 0 || pps1 == pps2)
{
return 0;
}
if (pps1 < pps2)
{
temp = (pps2-pps1);
}
else
{
temp = (pps1-pps2);
}
temp *= (pps1+pps2);
temp /= disp;
temp /= 2;
return (temp);
}
//--------------------------------------------------
// 计算某位移和某加速度下,最终的速度值
// 参数:
// disp 位移
// pps1 速度1
// ppss 加速度
//
// 返回:
// 速度值
float TTypeCalcEndSpd(u32 disp, float pps1, float ppss)
{
float temp;
// 公式: a=(v2+v1)*(v2-v1)/(2*d)
// v1 = pps1
// d = disp
// 最终 pps2 = sqrt(2*disp*ppss + pps1*pps1)
temp = 2.0f*disp;
temp *= ppss;
temp += pps1*pps1;
if (temp > 0)
{
temp = sqrt(temp);
}
else
{
temp = 0;
}
return (temp);
}
//--------------------------------------------------
// 计算运动时间
float TTypeCalcRunTime(u32 disp, u32 startpps, u32 stoppps, u32 runpps, u32 addppss)
{
TTypeCtrl tctrl;
float runtime = 0;
float time = 0;
memset(&tctrl, 0, sizeof(TTypeCtrl));
// 计算中间变量和结果
tctrl.movement = disp;
tctrl.begPPS = startpps; // 本段初始速度
tctrl.endPPS = stoppps; // 本段结束速度
tctrl.runPPS = runpps; // 本段运行速度
tctrl.maxPPSS = addppss; // 最大的加速度
TTypeCalcRunParas(&tctrl); // 计算加减速参数
{
s32 newPPSS1, newPPSS2;
newPPSS1 = tctrl.newAddPPSS;
newPPSS2 = tctrl.newAddPPSS;
if (tctrl.begPPS > tctrl.newRunPPS)
{
newPPSS1 *= -1;
}
if (tctrl.endPPS > tctrl.newRunPPS)
{
newPPSS2 *= -1;
}
runtime = 0;
if (tctrl.mvmtseg[0] != 0 && newPPSS1 != 0)
{
time = (int)tctrl.newRunPPS - (int)tctrl.begPPS;
time /= newPPSS1;
runtime += time;
}
if (tctrl.mvmtseg[1] != 0 && tctrl.newRunPPS != 0)
{
time = tctrl.mvmtseg[1];
time /= (int)tctrl.newRunPPS;
runtime += time;
}
if (tctrl.mvmtseg[2] != 0 && newPPSS2 != 0)
{
time = (int)tctrl.newRunPPS - (int)tctrl.endPPS;
time /= newPPSS2;
runtime += time;
}
// printf("run time = %.6f\r\n", runtime);
}
return runtime;
}
//--------------------------------------------------
// 梯形速度计算
int TTypeCalcRunParas(TTypeCtrl * pTTypeCtrl)
{
#define TCDEBUG_OUT 0 // 输出调试信息
int rslt;
// 已知量
// 条件,当前位移段的运动不能换向(速度在一个区间,不会过零)
// 用到的变量
u32 movement; // 本段位移量
u32 begPPS, endPPS, runPPS;
u32 addPPSS; // 加速度
movement = pTTypeCtrl->movement;
begPPS = pTTypeCtrl->begPPS;
endPPS = pTTypeCtrl->endPPS;
runPPS = pTTypeCtrl->runPPS;
addPPSS = pTTypeCtrl->maxPPSS;
// 保证运行速度大于最低速度
if (runPPS < begPPS || runPPS < endPPS)
{
runPPS = begPPS > endPPS ? begPPS:endPPS;
}
rslt = 0;
// 1. 判断是否达到最大速度,并计算各个段的位移
{
u32 mvmt1, mvmt2, mvmt3;
mvmt1 = TTypeCalcDisplacement(begPPS, runPPS, addPPSS);
mvmt3 = TTypeCalcDisplacement(endPPS, runPPS, addPPSS);
if (mvmt1 + mvmt3 >= movement) // 不能达到运行速度
{
float tmpv;
tmpv = movement * 2;
tmpv = sqrt((tmpv*addPPSS + begPPS*begPPS + endPPS*endPPS)/2.0); // 能够达到的峰值速度
runPPS = (tmpv);
#if (TCDEBUG_OUT == 1)
printf("TTypeCalcRunParas runPPS=%d\r\n", runPPS);
#endif
if (runPPS < begPPS || runPPS < endPPS) // 如果重新计算的速度小于启动停止速度
{
u32 tpmvmt;
tpmvmt = TTypeCalcDisplacement(begPPS, endPPS, addPPSS); // 直接变速最小位移
if (tpmvmt > movement) // 所需要位移太大,不足以完成加减速,规划失败
{
addPPSS = TTypeCalcAddPPSS(movement, begPPS, endPPS); // 重新计算加速度
#if (TCDEBUG_OUT == 1)
printf("TTypeCalcRunParas addPPSS=%d\r\n", addPPSS);
#endif
if (begPPS <= endPPS)
{
mvmt1 = movement;
mvmt2 = 0;
mvmt3 = 0;
}
else
{
mvmt1 = 0;
mvmt2 = 0;
mvmt3 = movement;
}
}
else
{
if (begPPS <= endPPS)
{
mvmt1 = tpmvmt;
mvmt2 = movement - tpmvmt;
mvmt3 = 0;
}
else
{
mvmt1 = 0;
mvmt2 = movement - tpmvmt;
mvmt3 = tpmvmt;
}
}
}
else
{
mvmt1 = TTypeCalcDisplacement(begPPS, runPPS, addPPSS);
mvmt3 = TTypeCalcDisplacement(endPPS, runPPS, addPPSS); // 重新计算位移
if (mvmt1 + mvmt3 > movement)
{
mvmt2 = 0;
mvmt3 = movement - mvmt1;
}
else
{
mvmt2 = movement - mvmt1 - mvmt3;
}
}
}
else // 可以达到运行速度
{
mvmt2 = movement - mvmt1 - mvmt3;
}
pTTypeCtrl->mvmtseg[0] = mvmt1; // 第一段
pTTypeCtrl->mvmtseg[1] = mvmt2; // 第二段
pTTypeCtrl->mvmtseg[2] = mvmt3; // 第三段
pTTypeCtrl->newRunPPS = runPPS;
pTTypeCtrl->newAddPPSS = addPPSS;
}
#if (TCDEBUG_OUT == 1)
printf("TTypeCalcRunParas: seg[0]=%d, seg[2]=%d, seg[1]=%d, newRunPPS[1]=%.1f, newAddPPSS=%.1f\r\n",
pTTypeCtrl->mvmtseg[0], pTTypeCtrl->mvmtseg[2], pTTypeCtrl->mvmtseg[1], pTTypeCtrl->newRunPPS, pTTypeCtrl->newAddPPSS);
#endif
return rslt;
}
//--------------------------------------------
// 计算分频系数表
int TTypeCalcDivTab(u32 fin, TTypeCtrl * pTTypeCtrl, u32 * pFidvTab, u32 * pTablen)
{
#define TDEBUG_OUT 0 // 输出调试信息
#if (TDEBUG_OUT == 1)
u32 time, tptm, lstm;
#endif
int rslt;
int totalclk = 0; // 运行时间单位是1个时间片
u32 movement;
if (fin <= 0 || pTTypeCtrl == NULL || pFidvTab == NULL || pTablen == NULL)
{
return -1;
}
#if (TDEBUG_OUT == 1)
time = GetUsSoftTimer();
lstm = time;
#endif
// 计算运动参数
TTypeCalcRunParas(pTTypeCtrl);
*pTablen = 0;
rslt = 0;
// 计算分频系数,生成每个脉冲的分频系数表
{
u32 i;
float begPPS; // 本段初始速度
float endPPS; // 本段结束速度
float runPPS; // 本段运行速度
float newPPSS1, newPPSS2;
float pps; // 速度值
float add;
float rpps1, rpps2; // 单精度能够显著提高运算速度
int runclk;
int coef;
u32 * pBuf;
movement = pTTypeCtrl->movement;
begPPS = pTTypeCtrl->begPPS;
endPPS = pTTypeCtrl->endPPS;
runPPS = pTTypeCtrl->newRunPPS;
newPPSS1 = pTTypeCtrl->newAddPPSS;
newPPSS2 = pTTypeCtrl->newAddPPSS;
if (begPPS > runPPS)
{
newPPSS1 *= -1;
}
if (endPPS > runPPS)
{
newPPSS2 *= -1;
}
#if (TDEBUG_OUT == 1)
lstm = GetUsSoftTimer();
#endif
pps = begPPS;
rpps1 = pps;
runclk = 0;
add = newPPSS1;
add /= fin;
pBuf = &(pFidvTab[0]);
for (i = 0; i < pTTypeCtrl->mvmtseg[0]; i++) // 第一段
{
if (pps > runPPS)
{
pps = runPPS;
}
if (newPPSS1 < 0 && pps < endPPS)
{
pps = endPPS;
}
coef = fin / pps; // 根据速度值得到系数
*pBuf++ = coef; // 记录分频系数
runclk += coef; // 根据分频系数得到下一个脉冲产生的时间点
pps = begPPS + runclk * add; // 根据速度规划,计算下一个脉冲产生时刻的速度值
}
rpps1 = pps;
totalclk += runclk;
#if (TDEBUG_OUT == 1)
tptm = GetUsSoftTimer();
printf("TCDiv seg1 tm=%uus\r\n", tptm-lstm);
lstm = tptm;
#endif
// 倒序产生第三段
pps = endPPS;
rpps2 = pps;
runclk = 0;
add = newPPSS2;
add /= fin;
pBuf = &(pFidvTab[movement - 1]);
for (i = 0; i < pTTypeCtrl->mvmtseg[2]; i++)
{
if (pps > runPPS)
{
pps = runPPS;
}
if (newPPSS2 < 0 && pps < endPPS)
{
pps = endPPS;
}
coef = fin / pps; // 根据速度值得到系数
*pBuf-- = coef; // 记录分频系数
runclk += coef; // 根据分频系数得到下一个脉冲产生的时间点
pps = endPPS + runclk * add; // 根据速度规划,计算下一个脉冲产生时刻的速度值
}
rpps2 = pps;
totalclk += runclk;
#if (TDEBUG_OUT == 1)
tptm = GetUsSoftTimer();
printf("TCDiv seg3 tm=%uus\r\n", tptm-lstm);
lstm = tptm;
#endif
// 匀速段
pps = (rpps1 + rpps2) / 2;
if (pps > runPPS)
{
pps = runPPS;
}
if (newPPSS2 < 0 && pps < endPPS)
{
pps = endPPS;
}
runclk = 0;
pBuf = &(pFidvTab[pTTypeCtrl->mvmtseg[0]]);
coef = fin / pps; // 根据速度值得到系数
for (i = 0; i < pTTypeCtrl->mvmtseg[1]; i++)
{
*pBuf++ = coef; // 记录分频系数
}
runclk = pTTypeCtrl->mvmtseg[1] * coef;
totalclk += runclk;
#if (TDEBUG_OUT == 1)
tptm = GetUsSoftTimer();
printf("TCDiv seg2 tm=%uus\r\n", tptm-lstm);
lstm = tptm;
#endif
}
if (rslt < 0)
{
rslt++;
}
else
{
*pTablen = movement;
rslt = totalclk;
}
#if (TDEBUG_OUT == 1)
tptm = GetUsSoftTimer();
printf("TCDiv tm=%uus\r\n", tptm-time);
#endif
return rslt;
}
//--------------------------------------------
#endif
//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------
#if (0) // S型速度曲线加减速七段
typedef struct
{
// 输入参数
u32 movement; // 本段位移量
float begPPS; // 本段初始速度
float endPPS; // 本段结束速度
float runPPS; // 本段运行速度v
float maxPPSS; // 最大的加速度a
float maxPPSSS; // 最大的加加速度j
// 计算中间变量和结果
u32 timeseg[7]; // 七段时间长度, 单位为1个时间片
u32 mvmtseg[7]; // 七段位移, 分段的位移量 (如果位移量不为零, 说明存在这个段)
float newRunPPS; // 新的运行速度
}STypeCtrl;
// 计算位移量
u32 STypeCalcDisplacement(float pps1, float pps2, float ppss);
// 计算加速度
float STypeCalcAddPPSS(u32 disp, float pps1, float pps2);
// 计算运动结束的速度
float STypeCalcEndSpd(u32 disp, float pps1, float ppss);
// 计算运动的时间
float STypeCalcRunTime(u32 disp, u32 startpps, u32 stoppps, u32 runpps, u32 addppss);
// 计算运动相关参数
int STypeCalcRunParas(STypeCtrl * pSTypeCtrl);
// 计算生成分频系数表
int STypeCalcDivTab(u32 fin, STypeCtrl * pSTypeCtrl, u32 * pFidvTab, u32 * pTablen);
#endif