搜索
bottom↓
回复: 17

STEP BY STEP,用M16改遥控小车为漫游机器人

[复制链接]

出0入0汤圆

发表于 2006-4-17 10:17:40 | 显示全部楼层 |阅读模式
一直想做个小车,自动控制的。从大一就想做,毕业了还没有实现。

小车应该归为移动机器人类,这东西,想做简单,可以做的相当简单,就像本文中的这个;想做复杂,也可以做的相当复杂,什么模式识别,图像处理,路径规划等等,都可以加入。

在大一时,想做个这样的东西,那时有时间啊,却不知道从哪里开始下手,每天等着本电子线路,啃,却什么也没有实现。

后来,单片机算是入门了,却又开始做项目,被导师逼的急的不行,几年下来,小车这个梦想还是没有实现。

这几天,仍然是有项目,仍然是每天加班,却想把这个东西做出来,于是,花了两晚上做了个小车,用遥控小汽车改的,很幼稚的那种,虽然做出来的效果也不是特别理想,但毕竟是实现了以前的梦想,心里也不由的兴奋!

这是以前买了个遥控的小跑车,支解后的机械部分是这样的:

出0入0汤圆

 楼主| 发表于 2006-4-17 10:19:36 | 显示全部楼层

出0入0汤圆

 楼主| 发表于 2006-4-17 10:40:05 | 显示全部楼层
先分析一下这个小车,它一共用了两个电机,一个用于动力,后轮驱动,一个用于方向,在前面的方向轮上,一加电,电机转到头,这样算是转了向。这样最大的好处是简单,成本极低,当然,付出的代价也不小,电机转不动后,耗电急剧增加,这样,好好的一个小车,成了电老虎,玩不起啊,四节新的南孚电池,一下午就干没了。

再来看看它的电路,接收部分由调谐电路和遥控汽车专用芯片RX2,还有驱动电路组成,天线来的信号通过选频,放大和检波后,送至RX2的14脚进行一,二级反相放大,最后从1脚输出,经外围RC电路滤波后,从3脚进入,进行译码处理,如果接收成功的话,将从6脚(右)、7脚(左)、10脚(后)、11脚(前)输出高电平,从而推动驱动电路使小车执行相关的动作。驱动电路是用三极管做的,很经典的双向驱动电路,如下图所示:





好了,小车基本解剖完毕。下面来想一下我们的方案。

原小车上我们可以用的,我们不用遥控,所以RX2我们可以不用了,前端的接收电路也不用了,唯一有用的是原车的驱动电路,但这个玩具车是个跑车,速度太快,我们如果直接用的话,不好控制,还要随时准备撞墙。但如果只是慢速的话,这个小车的启动又成了大问题,大家物理都学过,静摩擦大于动摩擦。最好,还要能变速,对于M16来讲,要控制它变速,最好的办法就是PWM了,产生的波形通过RC滤波后,变成可以控制的电压信号,再用于控制电机的转速。于是,我们要做的第一步,在驱动的控制三极管的基极上加一个RC滤波,电阻值为10K,电容值为104,是凭感觉选的值,大概能用。

方向是不准备用它的电路了,太耗电了!要能控制转动角度的,用舵机最方便,于是,我就是了舵机,普通的那种,三四十块一个。舵机一般有三根线,一根电源,一根地,一根控制信号线,电源在5V就可以,控制信号线是用脉冲控制的,脉冲的周期是20ms,当脉宽为2ms时,舵机在中间位置,当脉宽为1.5ms时,舵机逆时针转90度,当脉宽为2.5ms时,舵机顺时针转90度。M16不是有四个通道的PWM吗,用一个来控制舵机,是够了。舵机的个头太大了,我把原先放电机的地方上面挖一个洞,才可以把舵机放进去,然后把原先的齿轮卸下来,在舵机的中间插一根钢柱,然后再把齿轮套上去,改装后的舵机如下图所示:





然后把舵机安到车里去,如下图所示:



好了,现在,这个车如果加上电,给控制端放一个固定电平,它应该是可以跑了,但我们当然不会满足于让它走直线啦,下面,我们要给它加控制电路。

三句不离本行,控制还是用单片机做吧。单片机用MEGA16,至于为什么用M16,这个,我也没有认真考虑过,不过,我这刚好有M16做的最小系统PACK板,所以,就用它了。

最小系统的电路图(讲的烂的不能再烂的东西),如下所示:





PCB板图,如下所示



PACK板子,如下所示:





另外,机器人总得有若干传感器吧,否则就是无头苍蝇,到下乱撞。还是用简单点的吧,这里用的是红外反射管,电路如下所示:



然后连线,两个控制端一个放在OC1A,一下放在OC1B,舵机放在OC2上,三个红外接收输出接到ADC0至ADC2上,这样,还可以控制一下灵敏度。最后,我的小车闪亮登场!



下附本小车的程度,我没有做路径规划,只用根据习惯做了一些避障动作,最后做出的效果也只能是凑和,动作不是很连贯,偶尔还会撞墙。以后有时间再做一些路径规划,把动作做的连贯些。另外,在这里提出一点建议,把ADC放在一个定时器中断里,采样再加滤波,得出的障碍情况处理时分时处理,这样,可以在一个障碍没处理完时又碰到另一个障碍,马上转去处理另一个障碍,从而避免在处理障碍时对其它障碍不理的问题。大家可以改进改进,哥们我实在是不行了,现在都早上一点多了。程序是用GCC编的。

/*

* FileName:       Robocarmain.c

* Author:         yuanding  Version: 1.0  Date: 2006-4-16

* Description:    a roboticcar controled by m16

* Version:        

* Function List:  

*                 1.

* History:        

*     <author>   <time>    <version >   <desc>

*/



#include <avr/io.h>

#include <avr/interrupt.h>

#include <avr/signal.h>

#include <inttypes.h>

#include <string.h>

#include <avr/eeprom.h>

#include <stdlib.h>

#include <math.h>



//设置的PWM值,用以控制车速

#define LOWSPEED         195

#define MIDSPEED         230

#define HIGHSPEED         250



//定义控制舵机的PWM值

#define FULL                144

#define STRIGHT                10

#define LEFT                6

#define RIGHT                14



//定义红外传感器的引脚

#define DEAHEAD                0x04

#define DELEFT                0x01

#define DERIGHT                0x02



void SetPWM(uint16_t PWMValue0);

void delay_1ms(void);

void delay_nms(unsigned int n) ;

void Forward(uint16_t Speed);

void Backward(uint16_t Speed);

void SetPosition(uint8_t Position);

void Init(void);

void Stop(void);

void Detect(void);

void StartGo(void);

void StartBack(void);

uint8_t Read_Adc(uint8_t Channel);

uint8_t Get_Evt(void);



uint8_t Pulse_With=0;

uint8_t PeriodCount=0;





/*

* Function:       SetPWM

* Description:    try OC1 PWM function

* Calls:          NONE

* Called By:      NONE

* Table Accessed:

* Table Updated:  

* Input:          the PWM value

* Output:         none

* Return:         none

* Others:         

*/

void SetPWM(uint16_t PWMValue0)

{

        TCCR1A=(1<<COM1A1)|(1<<COM1B1)|(1<<WGM11);

        TCCR1B=(1<<WGM13)|(1<<WGM12)|(1<<CS10);

        ICR1=0X7FF;



        if(PWMValue0<2048&&PWMValue0>0)

                {

                OCR1A=PWMValue0;

                OCR1B=PWMValue0;

                }

}



void delay_1ms(void)                 //1ms延时函数

  {

   unsigned int i;

   for (i=0;i<30000;i++);

  }

  

void delay_nms(unsigned int n)       //N ms延时函数

  {

   unsigned int i=0;

   for (i=0;i<n;i++)

   delay_1ms();

  }



/*

* Function:       Forward

* Description:    to control car go ahead

* Calls:          none

* Called By:      StartGo,Detect,etc

* Table Accessed:

* Table Updated:  

* Input:          the speed value

* Output:         none

* Return:         none

* Others:         none

*/

void Forward(uint16_t Speed)

{

        TCCR1A=(1<<COM1A1)|(1<<WGM11);

        TCCR1B=(1<<WGM13)|(1<<WGM12)|(1<<CS10);

        ICR1=0XFF;



        if(Speed<2048&&Speed>0)

                {

                OCR1A=Speed;

                }

}





/*

* Function:       Backward

* Description:    control the car move back

* Calls:          none

* Called By:      StartBack,Detect,etc

* Table Accessed:

* Table Updated:  

* Input:          speed value

* Output:         none

* Return:         

* Others:         

*/

void Backward(uint16_t Speed)

{

        TCCR1A=(1<<COM1B1)|(1<<WGM11);

        TCCR1B=(1<<WGM13)|(1<<WGM12)|(1<<CS10);

        ICR1=0XFF;



        if(Speed<2048&&Speed>0)

                {

                OCR1B=Speed;

                }

}





/*

* Function:       stop

* Description:    stop the car

* Calls:         

* Called By:      

* Table Accessed:

* Table Updated:  

* Input:          none

* Output:         none

* Return:         

* Others:         

*/

void Stop(void)

{

        TCCR1A=0;

        TCCR1B=0;

}



//

/*

* Function:       SetPosition

* Description:    the control the position motor's degree

* Calls:         

* Called By:      

* Table Accessed:

* Table Updated:  

* Input:          the postion value

* Output:         none

* Return:         

* Others:         

*/

void SetPosition(uint8_t Position)

{

        cli();

        TCCR2=0x0f;



        Pulse_With=Position;



        OCR2=FULL-Pulse_With;



        TIMSK|=(1<<OCIE2);



        sei();

        delay_nms(500);

}





/*

* Function:       interrupt function

* Description:    to generate PWM wave to position motor

* Calls:         

* Called By:      

* Table Accessed:

* Table Updated:  

* Input:         

* Output:         

* Return:         

* Others:         

*/

SIGNAL(SIG_OUTPUT_COMPARE2)

{

        if(OCR2<=30)

                {

                cbi(PORTD,7);



                OCR2=FULL-Pulse_With;

                }

        else

                {

                sbi(PORTD,7);



                OCR2=Pulse_With;

                }

}





void Init(void)

{

        //TIMER2 initialize - prescale:8

        // WGM: Normal

        // desired value: 100uSec

        // actual value: 99.826uSec (0.2%)

//        TCCR2 = 0x00; //stop

//        ASSR  = 0x00; //set async mode

//        TCNT2 = 0xA4; //setup

//        OCR2  = 0x5C;

//        TCCR2 = 0x02; //start



//        TIMSK|=(1<<TOIE2);

//        sei();



        DDRA=0x00;

        PORTA=0x00;



}



//100uSec overflow interrupt service function

//not use

SIGNAL(SIG_OVERFLOW2)

{       

        TCNT2 = 0xA4; //reload counter value

        PeriodCount++;

        if(PeriodCount==FULL)

                {

                sbi(PORTD,7);

                PeriodCount=0;

                }

        if(PeriodCount==Pulse_With)

                {

                cbi(PORTD,7);

                }

}





/*

* Function:       StartGo

* Description:    start in high speed to move the car ahead

* Calls:          forward()

* Called By:      

* Table Accessed:

* Table Updated:  

* Input:          none

* Output:         none

* Return:         

* Others:         

*/

void StartGo(void)

{

        Forward(HIGHSPEED);

        delay_nms(300);

        Forward(LOWSPEED);

}





/*

* Function:       StartBack

* Description:    start in high speed to move the car back

* Calls:          backward()

* Called By:      

* Table Accessed:

* Table Updated:  

* Input:          none

* Output:         none

* Return:         

* Others:         

*/

void StartBack(void)

{

        Backward(MIDSPEED);

        delay_nms(200);

        Backward(LOWSPEED);

}





/*

* Function:       Detect

* Description:    to detect whether there are obstructions

* Calls:         

* Called By:      

* Table Accessed:

* Table Updated:  

* Input:         

* Output:         

* Return:         

* Others:         

*/

void Detect(void)

{

        uint8_t temp=0;

        temp=Get_Evt();//PINA;

        if((temp&DEAHEAD)&&(temp&DELEFT)&&(temp&DERIGHT))

                {

                        Backward(HIGHSPEED);

                        delay_nms(100);

                        SetPosition(STRIGHT);

                        StartBack();

                }

        else if((temp&DEAHEAD)&&(!(temp&DELEFT))&&(!(temp&DERIGHT)))

                {

                        Backward(HIGHSPEED);

                        delay_nms(100);

                        SetPosition(RIGHT);

                        StartBack();

                        delay_nms(600);

                        SetPosition(LEFT);

                        StartGo();

                        delay_nms(600);

                        SetPosition(STRIGHT);

                        Forward(LOWSPEED);

                }

        else if((temp&DEAHEAD)&&(temp&DELEFT)&&(!(temp&DERIGHT)))

                {

                        Backward(HIGHSPEED);

                        delay_nms(100);

                        SetPosition(RIGHT);

                        StartBack();

                        delay_nms(1200);

                        SetPosition(STRIGHT);

                        StartGo();

                }

        else if((temp&DEAHEAD)&&(!(temp&DELEFT))&&(temp&DERIGHT))

                {

                        StartBack();

                        delay_nms(100);

                        SetPosition(LEFT);

                        StartBack();

                        delay_nms(2000);

                        SetPosition(STRIGHT);

                        StartGo();

                }

        else if((!(temp&DEAHEAD))&&(temp&DELEFT)&&(!(temp&DERIGHT)))

                {

                        SetPosition(RIGHT);

                        Forward(LOWSPEED);

                        delay_nms(600);

                        SetPosition(STRIGHT);

                        Forward(LOWSPEED);

                }

        else if((!(temp&DEAHEAD))&&(!(temp&DELEFT))&&(temp&DERIGHT))

                {

                        SetPosition(LEFT);

                        Forward(LOWSPEED);

                        delay_nms(600);

                        SetPosition(STRIGHT);

                        Forward(LOWSPEED);

                }

        else if((!(temp&DEAHEAD))&&(!(temp&DELEFT))&&(!(temp&DERIGHT)))

                {

                        Forward(LOWSPEED);

                }

}





/*

* Function:       Read_Adc

* Description:    start a ADC ,and return the value,8 bit

* Calls:         

* Called By:      

* Table Accessed:

* Table Updated:  

* Input:          none

* Output:         the adc result,8 bit

* Return:         

* Others:         

*/

uint8_t Read_Adc(uint8_t Channel)

{

        ADMUX=1<<ADLAR|Channel;

        ADCSRA=1<<ADEN|1<<ADSC|6<<ADPS0;

        loop_until_bit_is_set(ADCSRA,ADIF);

        ADCSRA|=1<<ADIF;

        return ADCH;

}





/*

* Function:       Get_Evt

* Description:    get the environment situation

* Calls:         

* Called By:      

* Table Accessed:

* Table Updated:  

* Input:         

* Output:         0b00000(ahead)(left)(right)

* Return:         

* Others:         

*/

uint8_t Get_Evt(void)

{

        uint8_t temp=0;

        if(Read_Adc(0)>=30)

                temp|=0x01;

        if(Read_Adc(1)>=30)

                temp|=0x02;

        if(Read_Adc(2)>=40)

                temp|=0x04;

        return temp;

}



//enter here

int main(void)

{

        DDRD=0xff;

        Init();

        SetPosition(STRIGHT);

        StartGo();

        while(1)

                {

                        Detect();

                }

        return 0;

}



-----此内容被yuanding31于2006-04-17,10:55:40编辑过



-----此内容被yuanding31于2006-04-17,10:58:42编辑过


-----此内容被yuanding31于2006-04-17,11:01:02编辑过

出0入4汤圆

发表于 2006-4-17 10:40:15 | 显示全部楼层
Wonderful!
头像被屏蔽

出0入0汤圆

发表于 2006-4-17 10:41:11 | 显示全部楼层
cool!



如果图片能清晰点就更好。

出0入0汤圆

发表于 2006-4-17 11:15:03 | 显示全部楼层
酷酷!

出0入0汤圆

发表于 2006-4-17 11:39:31 | 显示全部楼层
佩服!!

不知道何时才能实现小时候的梦想呢?

出0入0汤圆

 楼主| 发表于 2006-4-17 14:48:21 | 显示全部楼层
回阿莫,我是用手机拔号上的网,考虑到网速和流量,我用FireWorks把图片改小了,我想,大家一般都能知道那上面是什么东西,所以,图片质量差了点。呵呵,这是我准备放到我网站上去的东西,在这里也贴了一份。

出0入0汤圆

发表于 2006-4-17 16:20:21 | 显示全部楼层
这个不错啊.

出0入0汤圆

发表于 2010-3-4 21:48:18 | 显示全部楼层
COOL,很好。

出0入0汤圆

发表于 2010-3-6 19:37:06 | 显示全部楼层
好啊,顶

出0入0汤圆

发表于 2010-3-7 17:30:59 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-7-24 21:40:35 | 显示全部楼层
遥控小车,这是小时候最渴望的玩具。呵呵

出0入0汤圆

发表于 2010-9-7 11:32:06 | 显示全部楼层
http://shop59582324.taobao.com/  这里有很好的小车套件,红外寻迹,红外避障模块 哦,精度很高,可以测到40CM,有单路,也有双路哦,老板人也很好,在同等产品中,非常的便宜,大家可以去看看,不懂的地方,并且还有人给回答,是超声波初学者的首选哦

出0入0汤圆

发表于 2010-9-7 11:42:53 | 显示全部楼层
回复【15楼】a253545312
http://shop59582324.taobao.com/  这里有很好的小车套件,红外寻迹,红外避障模块 哦,精度很高,可以测到40cm,有单路,也有双路哦,老板人也很好,在同等产品中,非常的便宜,大家可以去看看,不懂的地方,并且还有人给回答,是超声波初学者的首选哦
-----------------------------------------------------------------------

不知道你是否是老板,很少见黄婆了,呵呵
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-29 23:40

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表