Trackless.c 11.8 KB
#include "Trackless.h"

#if P_SETUP_NAV_TYPE==2||P_SETUP_NAV_TYPE==3
//获取激光数据slam,此补偿不是将雷达位置补偿到车体中心而是工位坐标特殊补偿,每个工位的补偿值不一样,龙旗项目使用中
void laserDataUpdate() //
{
    CurrentCenterPoint.TarX = agv.Public.Coordinate_X + agv.Command.X_compensation; //X补偿

    CurrentCenterPoint.TarY = agv.Public.Coordinate_Y + agv.Command.Y_compensation; //Y补偿

    CurrentCenterPoint.CurAngle = agv.Public.Coordinate_W + agv.Command.W_compensation; //W补偿
}

int LightArriveFlagL = 0,LightArriveFlagR = 0;
//到达判断
unsigned char ArriveJugement()
{
	static u8 lastStopFlagL = 0,lastStopFlagR = 0;
	if(navi.Public.VerticalDistanceAgvToTARGET < LIGHT_STOP_SIGNAL_DIS)
	{
		if(agv.Command.LightStopSig == 1)//左光电停靠
		{
			if(agv.Public.i_LightStopFlagL == 1&&lastStopFlagL == 0)
			{
				LightArriveFlagL = 1;
			}
			if(LightArriveFlagL == 1)
			{
				Uart_Printf(COM1,"左光电到达  %d\r\n",agv.Command.LightStopSig);
				return 1;
			}
			if(agv.Public.i_LightStopFlagL == 0 && navi.Public.VerticalDistanceAgvToTARGET < REFLECTIVE_RANGE)
			{
				navi.Private.FirstZeroPoint = 1;
			}
			if(navi.Private.FirstZeroPoint && navi.Public.VerticalDistanceAgvToTARGET > REFLECTIVE_RANGE*2)
			{
				Uart_Printf(COM1,"未扫到光电到达  %d\r\n",agv.Command.LightStopSig);
				return 1;
			}
		}
		else if(agv.Command.LightStopSig == 1)//右光电停靠
		{
			if(agv.Public.i_LightStopFlagR == 1&&lastStopFlagR == 0)
			{
				LightArriveFlagR = 1;
			}
			if(LightArriveFlagR == 1)
			{
				Uart_Printf(COM1,"右光电到达  %d\r\n",agv.Command.LightStopSig);
				return 1;
			}
		}
		else
		{
			if ((navi.Public.VerticalDistanceAgvToSTART >= (navi.Public.DistanceSTARTtoTARGET - POSARRIVE_RANGE)) && (navi.Public.VerticalDistanceAgvToTARGET < navi.Public.VerticalDistanceAgvToSTART))
			{
				Uart_Printf(COM1,"正常到达  %d\r\n",agv.Command.LightStopSig);
				return 1;
			}
		}
		lastStopFlagL = agv.Public.i_LightStopFlagL;
	
		lastStopFlagR = agv.Public.i_LightStopFlagR;
	}
	return 0;
}
//更新执行站点
void pathUpdate(u8 *CurrentID)
{
    static int lastTime = 0;
		static float lastAnglediff = 0;
    /*****************到达站点判断以及切换站点**********************/
    if (agv.Command.CurDirection == 1 || agv.Command.CurDirection == 2) //直行判断
    {
        //到达站点判断
        if (ArriveJugement()==1)
        {
					navi.Private.FirstZeroPoint = 0;
            *CurrentID += 1;
/****单机测试***/
#if P_SETUP_SINGLE_PLAYER == 1
            if (*CurrentID >= traffic_land_marks.size)
            {
                *CurrentID = 1;
             }
#elif P_SETUP_SINGLE_PLAYER == 0
            if (*CurrentID >= traffic_land_marks.size)
            {
               if((agv.Command.LightStopSig == 1 && LightArriveFlagL == 1)||(agv.Command.LightStopSig == 2 && LightArriveFlagR == 1))
							 {
								 SetAlarm(0x200); 
							 }
							 else
							 {
								 SetAlarm(0x40);
							 }
							 LightArriveFlagL = 0;
						
							 LightArriveFlagR = 0;
						
							 agv.Public.i_UpdatePathSig = 1;
            }
#endif
            Uart_Printf(COM1, "站点更新,当前站点 = %d 当前方向 = %d Error_Flag = %x\r\n", agv.Command.standSiteID, agv.Command.CurDirection, agv.Public.Error_Flag);
        }
				lastAnglediff = 0;
    }
    else if (agv.Command.CurDirection == 7 || agv.Command.CurDirection == 8 || agv.Command.CurDirection == 9 || agv.Command.CurDirection == 10) //弧线转弯
    {
        //站点更新
        if ((fabs(navi.Public.AngleDifference) <= TURNINGOFF_ANGLE)||(navi.Public.AngleDifference*lastAnglediff<0))
        {
            *CurrentID += 1;
        }
				lastAnglediff = navi.Public.AngleDifference;
    }
    agv.Command.DispatchSpeed = traffic_land_marks.land_marks[*CurrentID - 1].DispatchSpeed; //系统下发速度

    agv.Command.CurDirection = traffic_land_marks.land_marks[*CurrentID - 1].Direction; //当前站点运行方向

    if (*CurrentID < traffic_land_marks.size) //当前站点不是最后站点,保存下一个站点方向和光电停车信号
    {
        agv.Command.LightStopSig = traffic_land_marks.land_marks[*CurrentID].LightStopSig; //目标站点广电信号

        agv.Command.NextDirection = traffic_land_marks.land_marks[*CurrentID].Direction; //下个站点运行方向

        agv.Command.NextDispatchSpeed = traffic_land_marks.land_marks[*CurrentID].DispatchSpeed;
    }
    else //已经是最后一个站点,没有下一个站点清零
    {
        agv.Command.LightStopSig = 0;

        agv.Command.NextDirection = 0;

        agv.Command.NextDispatchSpeed = 0;
    }

    StartPoint.TarX = traffic_land_marks.land_marks[*CurrentID - 1].pose[0]; //当前点(起点)

    StartPoint.TarY = traffic_land_marks.land_marks[*CurrentID - 1].pose[1];

    TargetPoint.TarX = traffic_land_marks.land_marks[*CurrentID].pose[0]; //目标点(终点)

    TargetPoint.TarY = traffic_land_marks.land_marks[*CurrentID].pose[1];

    if (*CurrentID >= 2 && *CurrentID < traffic_land_marks.size - 1) //实现弧线转弯需要有四个点位计算
    {
        PointOne.TarX = traffic_land_marks.land_marks[*CurrentID - 2].pose[0];

        PointOne.TarY = traffic_land_marks.land_marks[*CurrentID - 2].pose[1];

        PointTwo.TarX = traffic_land_marks.land_marks[*CurrentID - 1].pose[0];

        PointTwo.TarY = traffic_land_marks.land_marks[*CurrentID - 1].pose[1];

        PointThree.TarX = traffic_land_marks.land_marks[*CurrentID].pose[0];

        PointThree.TarY = traffic_land_marks.land_marks[*CurrentID].pose[1];

        PointFour.TarX = traffic_land_marks.land_marks[*CurrentID + 1].pose[0];

        PointFour.TarY = traffic_land_marks.land_marks[*CurrentID + 1].pose[1];
    }
}

//计算偏移量 设置不同运动方式的pid值
void calculateOffsetValue(unsigned char Direction)
{
    if (Direction == 7 || Direction == 8 || Direction == 9 || Direction == 10) //转弯需要计算圆心坐标
    {
        CircleCenterPoint = GetCircleCenterPoint(CurrentCenterPoint,PointThree,PointFour);                      //计算圆心坐标
        navi.Private.SetCalculationRadius = TwoPointDistance(PointTwo, CircleCenterPoint); //入弯点到圆心的距离
    }
		
    switch (Direction)
    {
    case 0:
        break;
		
    case 1:                                                                            //前进
        navi.Private.TarAngle = CalculatingDirectionAngle(StartPoint, TargetPoint); //求出目标方向角度

        navi.Public.AngleDifference = CalculatingCurrentAndTargetAngle(CurrentCenterPoint.CurAngle, navi.Private.TarAngle); //角度偏移

        navi.Public.CenterOffset = -CalCoordinateDis(CurrentCenterPoint, StartPoint, TargetPoint); //车中心横向偏移量
        //根据不同车型和不同方向设置pid参数
        pid = navi.PIDPara[0];
		
        if (navi.Public.VerticalDistanceAgvToTARGET < agv.Parameter.OnlyAnglePos) //小于500MM只纠角度
            pid = navi.PIDPara[3];
        break;
				
    case 2:                                                                            //后退
        navi.Private.TarAngle = CalculatingDirectionAngle(StartPoint, TargetPoint); //求出目标方向角度

        navi.Public.AngleDifference = CalculatingCurrentAndTargetAngle(CurrentCenterPoint.CurAngle + PI, navi.Private.TarAngle); //角度偏移

        navi.Public.CenterOffset = -CalCoordinateDis(CurrentCenterPoint, StartPoint, TargetPoint); //车中心横向偏移量

        pid = navi.PIDPara[1];
        if (navi.Public.VerticalDistanceAgvToTARGET < agv.Parameter.OnlyAnglePos) //小于500MM只纠角度
        {
            pid = navi.PIDPara[3];
            pid.AngleCofficient *= -1;
        }
        break;
				
    case 3:
        break;
		
    case 4:
        break;
		
    case 5:
        break;
		
    case 6:
        break;
		
    case 7:                                                                          //前进左转
        navi.Private.TarAngle = CalculatingDirectionAngle(PointThree, PointFour); //求出目标方向角度

        navi.Public.AngleDifference = CalculatingCurrentAndTargetAngle(CurrentCenterPoint.CurAngle, navi.Private.TarAngle); //角度偏移

        navi.Public.CenterOffset = TwoPointDistance(CurrentCenterPoint, CircleCenterPoint) - navi.Private.SetCalculationRadius; //车中心横向偏移量

        pid = navi.PIDPara[2];
        break;
		
    case 8:                                                                          //前进右转
        navi.Private.TarAngle = CalculatingDirectionAngle(PointThree, PointFour); //求出目标方向角度

        navi.Public.AngleDifference = CalculatingCurrentAndTargetAngle(CurrentCenterPoint.CurAngle, navi.Private.TarAngle); //角度偏移

        navi.Public.CenterOffset = TwoPointDistance(CurrentCenterPoint, CircleCenterPoint) - navi.Private.SetCalculationRadius; //车中心横向偏移量

        pid = navi.PIDPara[2];
        break;
		
    case 9:                                                                          //后退左转
        navi.Private.TarAngle = CalculatingDirectionAngle(PointThree, PointFour); //求出目标方向角度

        navi.Public.AngleDifference = CalculatingCurrentAndTargetAngle(CurrentCenterPoint.CurAngle + PI, navi.Private.TarAngle); //角度偏移

        navi.Public.CenterOffset = TwoPointDistance(CurrentCenterPoint, CircleCenterPoint) - navi.Private.SetCalculationRadius; //车中心横向偏移量

        pid = navi.PIDPara[2];
        break;
		
    case 10:                                                                         //后退右转
        navi.Private.TarAngle = CalculatingDirectionAngle(PointThree, PointFour); //求出目标方向角度

        navi.Public.AngleDifference = CalculatingCurrentAndTargetAngle(CurrentCenterPoint.CurAngle + PI, navi.Private.TarAngle); //角度偏移

        navi.Public.CenterOffset = -TwoPointDistance(CurrentCenterPoint, CircleCenterPoint) - navi.Private.SetCalculationRadius; //车中心横向偏移量

        pid = navi.PIDPara[2];
        break;
		
    default:
        break;
    }
}

//根据P值,I值,D值,位置偏差权重,角度偏差权重,输出偏移值
void offsetCompensationOutput(navigationPID *Pid)
{
    static int i = 0;
    static float LastCenterOffset = 0, LastAngleOffset = 0;
    static float Error = 0, DcalError = 0, LastError = 0, SumError = 0;
    //当位置和角度偏差变化重新计算
    if (LastCenterOffset != navi.Public.CenterOffset || LastAngleOffset != navi.Public.AngleDifference)
    {
        LastCenterOffset = navi.Public.CenterOffset;

        LastAngleOffset = navi.Public.AngleDifference;
        //取角度和位置偏差做为偏差补偿量
        Error = navi.Public.CenterOffset * Pid->PosCofficient + navi.Public.AngleDifference * 180 / PI * Pid->AngleCofficient;

        DcalError = Error - LastError; //误差变化量

        LastError = Error; //记录上次偏差
    }
		
    navi.Private.OutputOffset = Error * Pid->Kp + SumError * Pid->Ki + DcalError * Pid->Kd;

    if (navi.Private.OutputOffset >= Pid->MaxLimit)
        navi.Private.OutputOffset = Pid->MaxLimit;
    else if (navi.Private.OutputOffset <= -Pid->MaxLimit)
        navi.Private.OutputOffset = -Pid->MaxLimit;
		
		#if PRINT_TYPE_SELECT == 1
    if (i++ > PRINT_FREQUENCY)
    {
        i = 0;
        //		Uart_Printf(COM1,"当前方向 = %d,角度偏差 = %.2f,位置偏差 = %.2f,输出补偿值 = %.2f\r\n",
        //		agv.Command.CurDirection,navi.Public.AngleDifference*57.3,navi.Public.CenterOffset,navi.Private.OutputOffset);
        Uart_Printf(COM1, "X = %.2f Y = %.2f 当前方向 = %d,发送速度 = %.2f %.2f 反馈速度 = %.2f %.2f 角度偏差 = %.2f,位置偏差 = %.2f,输出补偿值 = %.2f\r\n", agv.Public.Coordinate_X, agv.Public.Coordinate_Y,
                    agv.Command.CurDirection, DriverMotor1.Command.speed, DriverMotor2.Command.speed, DriverMotor1.Public.encoderSpeed, DriverMotor2.Public.encoderSpeed, navi.Public.AngleDifference * 57.3, navi.Public.CenterOffset, navi.Private.OutputOffset);
    }
		#endif
}

void slamNavigation()
{
    laserDataUpdate(); 										//获取激光数据,以及特殊工位定点补偿**************

    pathUpdate(&agv.Command.standSiteID); //执行路径更新 和站点++判断。

    calculateOffsetValue(agv.Command.CurDirection); //计算偏移量和设置不同运动方式的pid值

    offsetCompensationOutput(&pid); 			//计算处理得到补偿值***********

    CalculateDistance(); 									//计算起始点、目标点、agv之前的距离
}
#endif