ti移动机器人设计报告

一、基本功能描述:

1、基本循迹功能。对于直道、S弯道和钝角弯道,小车可沿黑线轨迹自动进行调整使黑线在小车正中间。如若出现小车全脱离黑线,小车进行逆时针旋转直至再次检测到黑线进行循迹。

2、特殊赛道循迹功能。对于直角、锐角赛道,小车进行较大幅度转向不偏离轨道。对于十字路口赛道,即小车检测模块全压在黑线,小车直行跨越黑线。

3、防碰撞功能:在碰撞障碍时可以识别障碍的存在并进行避障。(本次课程未实现)

 

二、硬件结构:

2.1:小车整体分为5大模块:

1)控制模块:搭载单片机MSP432Launch Pad主板

2)驱动模块:电池组、N20直流电机

3)循迹模块:红外LED传感器

4)防撞模块:防撞开关

5)运动模块:底盘和车轮等

模块作用:

1)控制模块即使用单片机编程,实现代码控制小车按一定路线行进

2)驱动模块即是提供能源动力的部分

3)循迹模块是使用红外传感器,通过反射的不同来识别路面,以获得轨道信息

4)防撞模块是通过防撞开关进行传感,以使小车识别障碍,进而实现避障功能

5)运动模块是小车主体部分,是进行运动的主体

 

2.2:这里主要介绍本次课程重点的3个模块

1)控制模块:MSP432P401R Launch Pad包含48MHz ARM CortexM4F内核80μA/MHz工作功耗和660nA RTC操作,141Msps差动SAR ADCAES256加速器。

处理器特性:低功耗、高性能的MSP432P401R MCU

带浮点单元和DSP加速功能的48MHz 32ARM CortexM4F

功耗:80μA/MHz工作功耗和660nA RTC待机操作功耗

模拟:24通道141Msps差动SAR ADC两个比较器

数字:高级加密标准(AES256)加速器、CRCDMA32位硬件乘法器

存储器:256KB闪存、64KB RAM

计时器:416位、232

通信:多达4I2C8SPI4UART

40引脚BoosterPack连接器,支持20引脚BoosterPack采用EnergyTrace+技术的板载XDS-110ET仿真器 2个按钮和2LCD,便于用户交互反向通道UART通过USB连接到PC

MSP432处理器可以使用CCSIARKeil μVision IDE来开发。

整块电路板的框图如下:

ti移动机器人设计报告_第1张图片

ti移动机器人设计报告_第2张图片

以电路板上虚线为分界,上半部分是XDS-110ET仿真器,S101开关来选择板载XDS-110ET仿真器还是用外部仿真器

MSP432P401RXDS-110ET的连接可以断开,MSP432P401RXDS-110ET除仿真信号外没有其他通讯连接,仿真信号包括XDS-110ET串行调试信号、应用UART信号和3.3V5V电源

2)驱动模块:两节3.7V可充电锂电池

N20直流减速电机:

产品型号: GM12-N20VA

主要用途:标签打印机、标签剥离机、条码打印机、机器人、电子门锁、打印机、电子监控器、美容仪器、展示架、柜台、自动售货机等

电压:3V 4.5V 6V 12V

转速:3rpm--1000rpm

力矩: 最大 7kg.cm

外形尺寸:12*10*25mm

出轴外径: 3mm, (出轴长短可根据客户的要求设计)

输出轴可以加工成M3螺纹, M4螺纹

12*10mm微型精密减速器.

减速比:1/31/51/101/301/501/631/1001/1501/2101/2501/2981/3701/3801/1000

ti移动机器人设计报告_第3张图片

ti移动机器人设计报告_第4张图片

3)循迹模块:红外传感器原理:利用8路红外传感器感知地面颜色信息,控制机器人沿白线行进。不同的材料表面对红外线的反射能力不同,红外接收器电压变化也就不同,如下图:

ti移动机器人设计报告_第5张图片

可以看出,白色表面比黑色表面下降更快,由此我们记录高电平时间,通过这个时间的长短即可以判断地面是黑色或白色。
控制:对于这种车型,小车的控制当然是差速控制。8路开关,可以把差速分为4个等级,不同等级差速大小不一样,这几个参数影响小车循迹的稳定性,要根据实际情况调整。电机配有编码器,使用定时器输入捕获功能进行正交解码即可得知电机转速信息,这样就能实现电机闭环控制,让小车运行效果更好。

 

三、控制算法及软件实现

主要内容:

3.1 软件平台及安装

CCS,Keil uVision5,pack驱动包

3.2 软件系统总体结构及各模块的功能定义

(1)Keil uVision5用于寻迹小车的代码学习和书写,并将程序下入32单片机对小车进行驱动。

(2)Keil.STM32F4xx_DFP.1.0.8.pack为小车配置编程环境

(3)电机使用例程,对单片机对电机的驱动方式方法有了初步的了解,并实现电机的各种功能。

(4)循迹旧版例程,通过红外传感器对黑线识别来控制小车行走,其中涉及二进制,十六进制,单片机IO口等

3.3 关键算法和软件实现

if((0xFF==flag)||(0xFE==flag)||(0x7F==flag))//十字路口代码
        {

//            if(0==TrackingControlCnt)
//            {
//                TrackingControlCnt=1;
//                return ;
//            }
Timer_A_setCompareValue(TIMER_A0_BASE,
                                    TIMER_A_CAPTURECOMPARE_REGISTER_3,
                                    0);
Timer_A_setCompareValue(TIMER_A0_BASE,
                                    TIMER_A_CAPTURECOMPARE_REGISTER_1,
                                    0);
//            while(!Turn(TurnForward,120,200));
            while(!Turn(TurnForward,90,500));
//            TrackingControlCnt=0;
LEDPreError=0;
LEDLastError=0;
TrackingControlFlag=0;
L_Wheel_Speed=L_Wheel_Init_Speed;
R_Wheel_Speed=R_Wheel_Init_Speed;
L_Wheel_Positive();
R_Wheel_Positive();
Timer_A_setCompareValue(TIMER_A0_BASE,
                                    TIMER_A_CAPTURECOMPARE_REGISTER_1,
L_Wheel_Init_Speed);
Timer_A_setCompareValue(TIMER_A0_BASE,
                                    TIMER_A_CAPTURECOMPARE_REGISTER_3,
R_Wheel_Init_Speed);
return ;
        }

else if((0xB8==flag)||(0x98==flag)||(0x9C==flag)||(0xB0==flag))//左锐角代码
        {
Timer_A_setCompareValue(TIMER_A0_BASE,
                                    TIMER_A_CAPTURECOMPARE_REGISTER_3,
                                    0);
Timer_A_setCompareValue(TIMER_A0_BASE,
                                    TIMER_A_CAPTURECOMPARE_REGISTER_1,
                                    0);
            while(!Turn(TurnForward,100,600));
            while(!Turn(TurnLeft,80,900));
TrackingControlCnt=0;
LEDPreError=0;
LEDLastError=0;
TrackingControlFlag=0;
L_Wheel_Speed=L_Wheel_Init_Speed;
R_Wheel_Speed=R_Wheel_Init_Speed;
L_Wheel_Positive();
R_Wheel_Positive();
Timer_A_setCompareValue(TIMER_A0_BASE,
                                    TIMER_A_CAPTURECOMPARE_REGISTER_1,
L_Wheel_Init_Speed);
Timer_A_setCompareValue(TIMER_A0_BASE,
                                    TIMER_A_CAPTURECOMPARE_REGISTER_3,
R_Wheel_Init_Speed);
return ;
        }

这里给出2个较为关键的识别代码

3.4功能模块的具体实现

//前进后退转弯代码

#include "MOTOR.h"

//在MSP432参考指南找到对应章节有关TimerA的介绍
//定时器A向上计数模式配置结构体

Timer_A_UpModeConfig upConfig =
{
	TIMER_A_CLOCKSOURCE_SMCLK,              // SMCLK Clock Source
	TIMER_A_CLOCKSOURCE_DIVIDER_48,         // SMCLK/48 = 1MHz
	1000,                                   // 5000 tick period
	TIMER_A_TAIE_INTERRUPT_DISABLE,         // Disable Timer interrupt
	TIMER_A_CCIE_CCR0_INTERRUPT_ENABLE ,    // Enable CCR0 interrupt
	TIMER_A_DO_CLEAR                        // Clear value
};//SMCLK是系统子时钟,MCLK是系统主时钟
//定时标志
volatile uint8_t TimingFlag=0;
//溢出次数LoopCnt,余数TimingVal 溢出次数=定时时间/0xFFFF 余数=定时时间%0xFFFF
volatile uint32_t LoopCnt=0,TimingVal=0;

//电机初始化
void MotorInit(void)
{
    Timer_A_PWMConfig pwm1Config =
    {
        TIMER_A_CLOCKSOURCE_SMCLK,//时钟源选择SMCK
        TIMER_A_CLOCKSOURCE_DIVIDER_1,//1分频
        2000,//周期为2000个SMCK时钟周期
        L_CAPTURECOMPARE_REGISTER,//选择左轮电机PWM
        TIMER_A_OUTPUTMODE_RESET_SET,
        0//初始占空比为0
    };
    Timer_A_PWMConfig pwm2Config =
    {
        TIMER_A_CLOCKSOURCE_SMCLK,//时钟源选择SMCK
        TIMER_A_CLOCKSOURCE_DIVIDER_1,//1分频
        2000,//周期为2000个SMCK时钟周期
        R_CAPTURECOMPARE_REGISTER,//选择右轮电机PWM
        TIMER_A_OUTPUTMODE_RESET_SET,
        0//初始占空比为0
    };
    //GPIO复用配置
    MAP_GPIO_setAsPeripheralModuleFunctionOutputPin(MotorPWMPort,
                                                    L_PWM_Pin|R_PWM_Pin,
                                                    GPIO_PRIMARY_MODULE_FUNCTION);//设置引脚L_PWM_Pin和R_PWM_Pin为复用功能
    MAP_GPIO_setAsOutputPin(MotorDirectionPort,L_Direction_Pin|R_Direction_Pin);//设置引脚L_Direction_Pin和R_Direction_Pin为普通输出
    //PWM配置
    MAP_Timer_A_generatePWM(TIMER_A0_BASE, &pwm1Config);//产生PWM到左轮电机
    MAP_Timer_A_generatePWM(TIMER_A0_BASE, &pwm2Config);//产生PWM到右轮电机
	//转向定时配置器
	MAP_Timer_A_configureUpMode(TIMER_A1_BASE, &upConfig);//配置定时器向上计数模式
    MAP_Interrupt_enableInterrupt(INT_TA1_0);//打开定时器中断
}

//原地转向函数
//direction:方向,可选参数TurnLeft,TurnRight,TurnForward,TurnBackward
//angle:角度 范围:任意度数(前进和后退时此参数为运动时间)
//speed:转向速度,范围:0~2000
uint8_t Turn(uint8_t direction,float angle,uint32_t speed)
{
    uint32_t time;
    if(0==TimingFlag)
    {
        time=angle*TimingPerAngle;
        if(time<=0xFFFF)
        {
            LoopCnt=0;
            TimingVal=time;
        }
        else
        {
            LoopCnt=time/0xFFFF;
            TimingVal=time%0xFFFF;
        }
        upConfig.timerPeriod=TimingVal;
        MAP_Timer_A_configureUpMode(TIMER_A1_BASE, &upConfig);
        //转弯代码--开始转弯
        switch(direction)
        {
            case 1:
                   Timer_A_setCompareValue(TIMER_A0_BASE,
                                           L_CAPTURECOMPARE_REGISTER,
                                           speed);
                   Timer_A_setCompareValue(TIMER_A0_BASE,
                                           R_CAPTURECOMPARE_REGISTER,
                                           speed);
                   L_Wheel_Positive();
                   R_Wheel_Negative();
                   break;//右转
            case 2:
                   Timer_A_setCompareValue(TIMER_A0_BASE,
                                           L_CAPTURECOMPARE_REGISTER,
                                           speed);
                   Timer_A_setCompareValue(TIMER_A0_BASE,
                                           R_CAPTURECOMPARE_REGISTER,
                                           speed);
                   L_Wheel_Negative();
                   R_Wheel_Positive();
                   break;//左转
            case 3:
                   Timer_A_setCompareValue(TIMER_A0_BASE,
                                           L_CAPTURECOMPARE_REGISTER,
                                           speed);
                   Timer_A_setCompareValue(TIMER_A0_BASE,
                                           R_CAPTURECOMPARE_REGISTER,
                                           speed);
                   L_Wheel_Negative();
                   R_Wheel_Negative();
                   break;//后退
            case 4:
                   Timer_A_setCompareValue(TIMER_A0_BASE,
                                           L_CAPTURECOMPARE_REGISTER,
                                           speed+65);
                    //(若左右轮转速不同可增加一个常数调节)
                   Timer_A_setCompareValue(TIMER_A0_BASE,
                                           R_CAPTURECOMPARE_REGISTER,
                                           speed);
                   L_Wheel_Positive();
                   R_Wheel_Positive();
                   break;//前进
            default:break;
        }
        MAP_Timer_A_startCounter(TIMER_A1_BASE,TIMER_A_CONTINUOUS_MODE);
        TimingFlag=1;
    }
    else if(2==TimingFlag)
    {
        TimingFlag=0;
        return 1;
    }
    return 0;
}

void TA1_0_IRQHandler(void)
{
    MAP_Timer_A_clearCaptureCompareInterrupt(TIMER_A1_BASE,
                                             TIMER_A_CAPTURECOMPARE_REGISTER_0);
    if(0==LoopCnt)
    {
        Timer_A_stopTimer(TIMER_A1_BASE);
        //转弯代码--停止转弯
        Timer_A_setCompareValue(TIMER_A0_BASE,
                                L_CAPTURECOMPARE_REGISTER,
                                0);
        Timer_A_setCompareValue(TIMER_A0_BASE,
                                R_CAPTURECOMPARE_REGISTER,
                                0);
        MAP_GPIO_toggleOutputOnPin(GPIO_PORT_P1, GPIO_PIN0);
        TimingFlag=2;
    }
    else
    {
        LoopCnt--;
        upConfig.timerPeriod=0xFFFF;
        MAP_Timer_A_configureUpMode(TIMER_A1_BASE, &upConfig);
        MAP_Timer_A_startCounter(TIMER_A1_BASE,TIMER_A_CONTINUOUS_MODE);
    }
}
//红外传感模块代码

#include "ReflectSensor.h"

//void ReflectSensorInit(void)
//{
//}

uint8_t ReadReflectSensor(void)
{
	uint8_t val=0;
	//对管端口设置为输出方式
	MAP_GPIO_setAsOutputPin(ReflectSensorPort,ReflectSensor_Pin0);
	MAP_GPIO_setAsOutputPin(ReflectSensorPort,ReflectSensor_Pin1);
	MAP_GPIO_setAsOutputPin(ReflectSensorPort,ReflectSensor_Pin2);
	MAP_GPIO_setAsOutputPin(ReflectSensorPort,ReflectSensor_Pin3);
	MAP_GPIO_setAsOutputPin(ReflectSensorPort,ReflectSensor_Pin4);
	MAP_GPIO_setAsOutputPin(ReflectSensorPort,ReflectSensor_Pin5);
	MAP_GPIO_setAsOutputPin(ReflectSensorPort,ReflectSensor_Pin6);
	MAP_GPIO_setAsOutputPin(ReflectSensorPort,ReflectSensor_Pin7);
	//对管LED设置为输出方式
	MAP_GPIO_setAsOutputPin(ReflectSensorLED_Port,ReflectSensorLED_Pin);
	//对管端口输出为高电平
	MAP_GPIO_setOutputHighOnPin(ReflectSensorPort,ReflectSensor_Pin0);
	MAP_GPIO_setOutputHighOnPin(ReflectSensorPort,ReflectSensor_Pin1);
	MAP_GPIO_setOutputHighOnPin(ReflectSensorPort,ReflectSensor_Pin2);
	MAP_GPIO_setOutputHighOnPin(ReflectSensorPort,ReflectSensor_Pin3);
	MAP_GPIO_setOutputHighOnPin(ReflectSensorPort,ReflectSensor_Pin4);
	MAP_GPIO_setOutputHighOnPin(ReflectSensorPort,ReflectSensor_Pin5);
	MAP_GPIO_setOutputHighOnPin(ReflectSensorPort,ReflectSensor_Pin6);
	MAP_GPIO_setOutputHighOnPin(ReflectSensorPort,ReflectSensor_Pin7);
	//打开LED,对电容充电
	MAP_GPIO_setOutputHighOnPin(ReflectSensorLED_Port,ReflectSensorLED_Pin);
	//延迟10us
	DelayUs(10);
	//设置对管端口为输入方式
	MAP_GPIO_setAsInputPin(ReflectSensorPort,ReflectSensor_Pin0);
	MAP_GPIO_setAsInputPin(ReflectSensorPort,ReflectSensor_Pin1);
	MAP_GPIO_setAsInputPin(ReflectSensorPort,ReflectSensor_Pin2);
	MAP_GPIO_setAsInputPin(ReflectSensorPort,ReflectSensor_Pin3);
	MAP_GPIO_setAsInputPin(ReflectSensorPort,ReflectSensor_Pin4);
	MAP_GPIO_setAsInputPin(ReflectSensorPort,ReflectSensor_Pin5);
	MAP_GPIO_setAsInputPin(ReflectSensorPort,ReflectSensor_Pin6);
	MAP_GPIO_setAsInputPin(ReflectSensorPort,ReflectSensor_Pin7);
	//延时1.7ms(建议在1~2之间,可用来调节对轨道识别灵敏度)
	DelayUs(1700);
	//读对管引脚
	val|=(MAP_GPIO_getInputPinValue(ReflectSensorPort,ReflectSensor_Pin0)<<7);
	val|=(MAP_GPIO_getInputPinValue(ReflectSensorPort,ReflectSensor_Pin1)<<6);
	val|=(MAP_GPIO_getInputPinValue(ReflectSensorPort,ReflectSensor_Pin2)<<5);
	val|=(MAP_GPIO_getInputPinValue(ReflectSensorPort,ReflectSensor_Pin3)<<4);
	val|=(MAP_GPIO_getInputPinValue(ReflectSensorPort,ReflectSensor_Pin4)<<3);
	val|=(MAP_GPIO_getInputPinValue(ReflectSensorPort,ReflectSensor_Pin5)<<2);
	val|=(MAP_GPIO_getInputPinValue(ReflectSensorPort,ReflectSensor_Pin6)<<1);
	val|=(MAP_GPIO_getInputPinValue(ReflectSensorPort,ReflectSensor_Pin7)<<0);
	//关闭管LED
	MAP_GPIO_setOutputLowOnPin(ReflectSensorLED_Port,ReflectSensorLED_Pin);
	//返回测量值
	return val;
}
//避障模块代码

#include "CrashSensor.h"
#include "Motor.h"
#include "Delay.h"

volatile uint8_t DetectionVal=0;
uint8_t AvoidFlag=0;
extern uint8_t TimingFlag;

const uint8_t SensorAngleTab[]={Sensor1Angle,Sensor2Angle,Sensor3Angle,\
                                Sensor4Angle,Sensor5Angle,Sensor6Angle};
    
void CrashSensorInit(void)
{
    MAP_GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P6,
                                             GPIO_PIN0|GPIO_PIN1|\
                                             GPIO_PIN2|GPIO_PIN3|\
                                             GPIO_PIN4|GPIO_PIN5);
    MAP_GPIO_interruptEdgeSelect(GPIO_PORT_P6,
                                 GPIO_PIN0|GPIO_PIN1|\
                                 GPIO_PIN2|GPIO_PIN3|\
                                 GPIO_PIN4|GPIO_PIN5,
                                 GPIO_HIGH_TO_LOW_TRANSITION);
    MAP_Interrupt_setPriority(INT_PORT6,0xE8);
    MAP_GPIO_clearInterruptFlag(GPIO_PORT_P6, 
                                GPIO_PIN0|GPIO_PIN1|\
                                GPIO_PIN2|GPIO_PIN3|\
                                GPIO_PIN4|GPIO_PIN5);
    MAP_GPIO_enableInterrupt(GPIO_PORT_P6,
                             GPIO_PIN0|GPIO_PIN1|\
                             GPIO_PIN2|GPIO_PIN3|\
                             GPIO_PIN4|GPIO_PIN5);
    MAP_Interrupt_enableInterrupt(INT_PORT6);

}

void PORT6_IRQHandler(void)
{
    uint32_t status,cnt,i;
    status = MAP_GPIO_getEnabledInterruptStatus(GPIO_PORT_P6);
    MAP_GPIO_clearInterruptFlag(GPIO_PORT_P6, status);
    if(status & GPIO_PIN0)
    {
        cnt=0;
        for(i=0;iSampleThreshold)
            return ;
        DetectionVal|=0x01;
    }
    if(status & GPIO_PIN1)
    {
        cnt=0;
        for(i=0;iSampleThreshold)
            return ;
        DetectionVal|=0x02;
    }
    if(status & GPIO_PIN2)
    {
        cnt=0;
        for(i=0;iSampleThreshold)
            return ;
        DetectionVal|=0x04;
    }
    if(status & GPIO_PIN3)
    {
        cnt=0;
        for(i=0;iSampleThreshold)
            return ;
        DetectionVal|=0x08;
    }
    if(status & GPIO_PIN4)
    {
        cnt=0;
        for(i=0;iSampleThreshold)
            return ;
        DetectionVal|=0x10;
    }
    if(status & GPIO_PIN5)
    {
        cnt=0;
        for(i=0;iSampleThreshold)
            return ;
        DetectionVal|=0x20;
    }
}





void CrashAvoid(void)
{
    uint8_t i;
    uint32_t sum=0,cnt=0;
    //停止状态
    if(0==AvoidFlag)
    {
        AvoidFlag=1;
    }
    //直线行驶状态
    else if(1==AvoidFlag)
    {
        L_Wheel_Positive();
        R_Wheel_Positive();
        Timer_A_setCompareValue(TIMER_A0_BASE,
                                           TIMER_A_CAPTURECOMPARE_REGISTER_1,
                                           500);
        Timer_A_setCompareValue(TIMER_A0_BASE,
                                TIMER_A_CAPTURECOMPARE_REGISTER_3,
                                500);
        AvoidFlag=2;
    }
    //障碍检测状态
    else if(2==AvoidFlag)
    {
        if(DetectionVal!=0)
        {
            DelayUs(1000);
            //停止前进
            Timer_A_setCompareValue(TIMER_A0_BASE,
                                TIMER_A_CAPTURECOMPARE_REGISTER_3,
                                0);
            Timer_A_setCompareValue(TIMER_A0_BASE,
                                    TIMER_A_CAPTURECOMPARE_REGISTER_1,
                                    0);
            for(i=0;i>i)&0x01)
                {
                    sum+=SensorAngleTab[i];
                    cnt++;
                }
            }
            sum=sum/cnt;
            //后退
            while(!Turn(3,50,1000));
            if(sum>90)
            {
                sum=180-sum;
                //退后几步再右拐
                //补充退后代码
                Turn(1,sum,2000);
            }
            else if(sum<90)
            {
                //退后几步再左拐
                //补充退后代码
                Turn(2,sum,2000);
            }
            else
            {
                //退后几步再左拐
                //补充退后代码
                Turn(2,180,2000);
            }
            AvoidFlag=3;
        }
    }
    //避障完成
    else if(3==AvoidFlag)
    {
        if(2==TimingFlag)
        {
            TimingFlag=0;
            AvoidFlag=0;
            DetectionVal=0;
        }
    }
}
//红外循迹模块代码

#include "Track.h"


float L_Wheel_Speed=L_Wheel_Init_Speed,R_Wheel_Speed=R_Wheel_Init_Speed;
float LEDError=0,LEDLastError=0,LEDPreError=0,PIDVal=0,ErrorSum=0;
float Kp=150,Ki=0.01,Kd=30;
uint16_t TrackingControlFlag=0,TrackingControlCnt=0;

void TrackLine(void)
{
    uint8_t flag=0;
    float temp;
	
	flag=ReadReflectSensor();	
	
	if((0x18==flag)||(0x08==flag)||(0x10==flag))
	{
		LEDError=0;
	}
	        else if((0xFF==flag)||(0xFE==flag)||(0x7F==flag))
        {
            if(TrackingControlFlag0)&&(0==flag))
			LEDError=6;
		else if((LEDError<0)&&(0==flag))
			LEDError=-6;//ÍÑÀëºÚ½º´ø
	} 
	//PID调整量计算
//        PIDVal=Kp*(LEDError-LEDLastError)+Kd*(LEDError-2*LEDLastError+LEDPreError);
//	PIDVal=Kp*(LEDError-LEDLastError)+Ki*LEDError;
    PIDVal=Kp*(LEDError-LEDLastError);
//        PIDVal=Kp*(LEDError-LEDLastError)+Ki*LEDError+Kd*(LEDError-2*LEDLastError+LEDPreError);
	LEDPreError=LEDLastError;
	LEDLastError=LEDError;
	
	//速度调整
	//速度限幅
	temp=R_Wheel_Speed;
	temp+=PIDVal; 
	if(tempPIDHighThreshold)
		R_Wheel_Speed=PIDHighThreshold;
	else
		R_Wheel_Speed=temp;
	
	temp=L_Wheel_Speed;
	temp-=PIDVal;
	if(tempPIDHighThreshold)
		L_Wheel_Speed=PIDHighThreshold;
	else
		L_Wheel_Speed=temp;
	
	USARTSendStr("flag:",5);
	USARTSendNum(flag);
	USARTSendStr(",",1);
	
	USARTSendStr("L_Speed:",8);
	USARTSendNum(L_Wheel_Speed);
	USARTSendStr(",",1);
	
	USARTSendStr("R_Speed:",8);
	USARTSendNum(R_Wheel_Speed);
	USARTSendStr(",   ",4);
	
	L_Wheel_Positive();
	R_Wheel_Positive();
	Timer_A_setCompareValue(TIMER_A0_BASE,
							L_CAPTURECOMPARE_REGISTER,
							L_Wheel_Speed);
	Timer_A_setCompareValue(TIMER_A0_BASE,
							R_CAPTURECOMPARE_REGISTER,
							R_Wheel_Speed);
}

ti移动机器人设计报告_第6张图片

ti移动机器人设计报告_第7张图片

ti移动机器人设计报告_第8张图片

ti移动机器人设计报告_第9张图片

ti移动机器人设计报告_第10张图片

 

四、测试调试

项目一:小车电机驱动装置是否正常,能否进行前进、倒退和左右转弯。

1方法:我们小组将小车组装完成后,导入相应的代码,并多次调整电机速度观察是否出现相应运动。

2调试结果:当我们将左右电机的运转速度调成一致,小车前进时向右偏。左右转时并不能转动设定的角度。调整后能顺利直行,左右转弯。

3结果分析与结论:我们小组认为两个电机转动时速有些许差异,导致直行与转弯不顺。于是,我们将小车右轮速度调高,多次调整后,小车能准确进行直行运动,转弯也没有问题。

 

项目二:小车是否具有基本循迹功能,即黑线进行直行,钝角转弯等。

1方法:我们小组首先将循迹功能导入小车,通过人为按键去扫描小车压在黑线上的数据,在此基础上对程序进行提高。同时驱动小车,观察小车能否按预期进行运动,且保持稳定。

2测试仪器设备、环境:小车,XCOM软件,附有黑线的直道、S型弯道和钝角弯道。

3调试结果:当我们把代码导入小车就马上将小车压在黑线上,并打开XCOM软件进行数据采集,采集结果与预期相对应,小车扫描模块没有问题。于是,我们将小车分别压在S弯道和钝角弯道上,根据代码,小车能顺利行走,但是有些许的摇摆,不能很准确地行走。经过完善后能完成基本循迹功能。

4结果分析与结论:小车扫描模块没有任何问题,小车行走时有些许不稳定,我们判断可能是代码中的对小车偏离轨道的分析调整有些过头,于是我们适当地增加调整了小车对于偏离的调整数据,经过多次的测试,小车终于能够稳定地在黑线上行走。

 

项目三:小车是否具有特殊赛道循迹功能,即直角、锐角和十字路口。

1方法:我们用小车和XCOM软件多次在直角、锐角和十字路口上进行数据扫描,并根据结果对使小车进行相应动作,同时需要多次调整转动角度及电机速度。

2测试仪器设备、环境:小车,XCOM软件,附有黑线的直角、锐角和十字路口。

3调试结果:小车对于直角赛道的判断是较为容易的,只需一边的扫描器压在黑线,另一边压在地板上,仅有几次小车无法顺利判断。而锐角赛道和直角赛道就困难许多。对于锐角赛道,判定条件较多,且扫描速率对小车能否顺利通过有极大的影响,同时小车的转动角度也是一个难点。测试结果不是很理想,我们花费了许多时间去进行调试。而十字路口,起初我们的代码能很顺利的进行判断,并做出相应行动。但是在多次测试后,小车有挺大几率会判断成锐角转弯。

4结果分析与结论:对于直角赛道,我们小组认为是小车对于直角赛道的判断条件少了,通过小车多次扫描,我们认为不能小车一半压在一边一半压在另一边就可,在小车行走过程中,小车些许的晃动会使小车稍微偏离赛道,此时一边就只有35个扫描点,于是,我们增加了小车判断条件,更改后,小车能很顺利地通过直角赛道。对于锐角赛道,在多次的测试及数据分析后,我们总结了多个判断条件,更改代码后小车能顺利判断锐角弯道,在此基础上我们对转弯角度进行多次调试,使小车能够很好的转过锐角赛道。对于十字路口,我们采取小车遇十字路口直行方案。导入代码后,起初几次的判断结果都很好,能够顺利通过,但是多次测试后,对于十字路口的判别经常发生错误,很容易误判为锐角,通过串口记录小车行驶数据分析,由于传感器采样速率较快,在到达黑线边界时,这个值其实是模糊的,类似于锐角的值。所以,当检测到锐角时,让车前进一段时间再采样,越过黑线边界,多次调试后,我们找到了较为精确的前进时间数值使小车能顺利通过。

 

项目四:小车是否能稳定地重复在轨道上跑圈。

1方法:我们将初步成型的代码导入小车中,让小车不加干预的在赛道上跑圈。根据结果对小车具体参数进行更改。

2测试仪器设备、环境:小车,XCOM软件,附有黑线的普通、特殊赛道。

3调试结果:小车第一圈刚开始能够顺利地通过十字路口,在直角赛道有一些偏移,最后锐角也能顺利通过。但是第二圈时,小车通过第一个十字路口后,在第二个十字路口判断成了锐角进行了左转。在后面多次的测试中,小车还出现了无法判断直角赛道的情况,直接直行,锐角也有相应的状况发生,小车很难无失误多次跑圈。

4结果分析与结论:起初我们对于小车为什么出现这种情况真的是很头疼,不知道怎么去更改。但是在小组成员多天的测试后,我们认为轨道旁同学的影子,小车扫描的延迟,直行的稳定性,还有判定条件都是很粗糙的会对小车产生很大的影响。需要进一步去完善。在小车测试时,我们会让旁边的同学稍稍让开点,特别是在锐角这个地方。关于小车扫描的时间,我们发现时间长短会对小车判断锐角和十字路口产生不同的影响,所以,我们进行了多次的测试,终于找到了一个较为合适的时间延迟。使小车能顺利通过锐角,对于十字路口,能采集的确定数据进行直行。同时,对于特殊赛道,我们也完善了判定条件,使在弯道能做出正确的动作。更改代码后,小车能够破除一圈魔咒,进行多次跑圈,为了更完善,我们在接下来的几天再次进行了更多次的数据分析,使小车能够更加稳定。为了能在顺利跑圈的同时增加速度,我们也是不断去磨合了这个速度,使之达到更好的状态。最终小车能在较高速下跑完六七圈的成绩。

你可能感兴趣的:(ti移动机器人设计报告)