PPC.c 9.28 KB
#include "PPC.h"

#if P_SETUP_NAV_TYPE==4
//获取激光数据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;

                traffic_land_marks.land_marks[0].Direction = 4;

                traffic_land_marks.land_marks[3].Direction = 3;
            }
#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];
    }
}


//1,获取前视距离,根据剩余距离调整前视距离
float getControlFrontDistance(float *distance)
{
	float valueDis = 0;
	
	if(*distance > 1000)
	{
		valueDis = 1000;
	}
	else
		valueDis = 200;
	
	return valueDis;
}

//2,根据当前点位在路径上的映射,求出前视点位坐标



//计算偏移量 设置不同运动方式的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); //入弯点到圆心的距离
    }

}

//根据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); //执行路径更新 和站点++判断。

	CalculateDistance(); 									//计算起始点、目标点、agv之前的距离
	
	if(agv.Command.CurDirection == 1 || agv.Command.CurDirection == 2)
	{
		Line Lpath;
		
		static float angleDiff = 0,valueDis = 0;
		
		Lpath = getLine2(StartPoint,TargetPoint);
		
		navi.Private.FrontViewDistance = getControlFrontDistance(&navi.Public.DistanceAgvToTARGET);//获取并调节前视距离
		
		FrontViewPoint = getControlTargetPoint(CurrentCenterPoint,Lpath,navi.Private.FrontViewDistance);//求预瞄点
		
		navi.Private.FrontViewAngle = CalculatingDirectionAngle(CurrentCenterPoint,FrontViewPoint);//求当前点与预瞄点角度
		
		angleDiff = CalculatingCurrentAndTargetAngle(CurrentCenterPoint.CurAngle,navi.Private.FrontViewAngle);//求车体与预瞄方向夹角
		
		valueDis = TwoPointDistance(CurrentCenterPoint,FrontViewPoint);
		
		if(angleDiff != 0)
		{
			navi.Private.SetCalculationRadius = valueDis/sin(angleDiff)/2;
		}
		else
			navi.Private.SetCalculationRadius = 0;
		
	}
	else
	{
		//	calculateOffsetValue(agv.Command.CurDirection); //计算偏移量和设置不同运动方式的pid值

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



    
}
#endif