打印
[复制链接]
2710|5
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
coolwyc|  楼主 | 2007-8-22 21:17 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

PRJ2:智能小车V0.1
作者:Sam山野人,coolwyc@21cn.com(coolwyc@21cn.com)
 http://www.roboticfan.com/blog/UploadFiles/2007-8/221435205355.jpghttp://www.roboticfan.com/blog/UploadFiles/2007-8/221435770766.jpg
硬件:
1.       车体
2.       S3C2410A开发板
3.       红外测距传感器
4.       伺服器(舵机)
5.       直流电机
6.       电机驱动板
7.       电源
 
软件:
1.       Linux2.6.14内核,包括:Nand Flash、USB、NET、PWM、ADC等驱动;Yaffs等文件系统。
2.       VIVI
3.       Busybox1.6
 
主要目标:
使车体能自主地在平地行驶,能躲避一定高度和大小的障碍物。
下一目标:
优化行走算法、行走路线预测、自选行走路线等。
加入编码轮,实现PID。
 
开发简述:
1.       在前几个月已完成了PRJ1:智能小车的开发,PRJ2硬件跟PRJ1相同,实现功能也基本相同,最大不同的是PRJ1采用UCOSII操作系统,PRJ2采用Linux,由于工作比较忙,PRJ1的介绍稍后撰写发布。
2.       开发板是一年多前买的,自带的linux是2.4的版本,现在很多开发板都已经用上2.6了,我当然也想用2.6做平台了,于是开始了linux2.6.14的移植,用了大概花了3个星期左右,其中也尝试了2.6.18和2.6.22,编译后运行时老是出现visual address什么什么的错误,再网上也没查到原因,于是放弃了。linux2.6.14的移植也算比较顺利,Nand Flash、USB、NET、Yaffs等都很快弄好了。我是在业余时间做的,平时要上班,花了三个星期自己感觉也不算慢了。
3.       内核移植完了下一步当然是文件系统了,首先是移植Busybox1.6,然后建立目录结构、编写好linuxrc还有hosts、passwd等配置文件,在mtd上划出一个分区建立yaffs,把目录结构、Busybox等都copy过去,启动时用这个yaffs分区做根目录。具体的网上也有很多**参考,这里就从简了。
4.       要使车体工作需要控制三个硬件:
a.       红外测距传感器---车体的唯一一个传感器,最大探测距离80cm,负责探测车体周围的障碍物,车体上没有其他接触开关等传感器,所以车体的安全保障就靠它了。
b.       伺服器---负责带动红外测距传感器旋转,使它能探测到不同角度的距离,这里设计是前方140度范围旋转,也就是说能探测前方140度范围的障碍物的距离。
c.       直流电机---负责车体移动。通过了PWM信号驱动电机驱动板来调节车体的运行速度,前方障碍物距离远时运行速度可以快些,当离障碍物距离近时运行速度可以慢些或者停车。
5.       红外测距传感器输出的是模拟电压信号(当障碍物距离远输出电压低,当障碍物距离近输出电压高),所以要用到ADC,需要编写S3C2410_adc驱动。
6.       伺服器和直流电机都需要用到PWM信号,PWM信号是由定时器产生的,S3C2410有五路定时器,linux占用了一个,查看linux内核源码,确定是占用了timer4,其余的4个就可以选用了,选用timer0驱动伺服器,timer1驱动直流电机,分配好了立刻动手编写S3C2410_pwm驱动;车体运行除了要控制速度还需要控制方向(前进、后退、左转、右转等),需要通过I/O对电机驱动板进行控制,本来应该另外编写驱动程序来完成这些的,但考虑到控制对象是一样的(电机),而且控制方向和控制速度关系比较密切,所以把控制I/O的代码也写到S3C2410_pwm里面去了,用起来也方便。
7.       到此,内核和驱动都已经准备好了,下一步要实现的就是应用程序了,包括小车的行走模式、行走算法、障碍物探测等,使用了两个线程来完成这些任务:
a.       MeasureThread()---探测线程:主要实现伺服器在140度区间来回转动,带动红外测距传感器也随之转动;每转过一定角度就测量障碍物距离;根据测量结果通知MotionThread()做相应的动作,例如:前方障碍物距离在安全范围,通知MotionThread()前进;左前方有障碍物,通知MotionThread()往右转;前方障碍物距离比较近,通知MotionThread()减速,前方障碍物距离比较远,通知MotionThread()加速。通过全局变量Motion_status实现通信。
b.       MotionThread()---运动控制线程:根据MeasureThread()设置的状态控制车体运动。当有障碍物时车体需要左转或右转以避开障碍物,当障碍物刚好在安全距离阀值附近时,会出现抖动(有障碍-à左转à无障碍à停à有障碍-à左转),这里采取了每次转动要至少保持一定时间(例如:200ms),在这段时间内禁止改变车体运动状态,通过信号量mutex_turning来实现这种同步。
 
 [url=http://www.roboticfan.com/blog/UploadFiles/2007-8/221417629139.png]http://www.roboticfan.com/blog/UploadFiles/2007-8/221417629139.png[/url]
 
 
 
 

 
8.       代码:car.c
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define ADC_DEV "/dev/s3c2410_adc" 
#define PWM_DEV "/dev/s3c2410_pwm" 
 
#define PWMIOCTL_PRESALE0 0
#define PWMIOCTL_PRESALE1 1
#define PWMIOCTL_MUX0 2
#define PWMIOCTL_MUX1 3
#define PWMIOCTL_MUX2 4
#define PWMIOCTL_MUX3 5
#define PWMIOCTL_MUX4 6
#define PWMIOCTL_AUTORELOAD0 7
#define PWMIOCTL_AUTORELOAD1 8
#define PWMIOCTL_AUTORELOAD2 9
#define PWMIOCTL_AUTORELOAD3 10
#define PWMIOCTL_INVERTER0 12
#define PWMIOCTL_INVERTER1 13
#define PWMIOCTL_INVERTER2 14
#define PWMIOCTL_INVERTER3 15
#define PWMIOCTL_INVERTER4 16
#define PWMIOCTL_UPDATE0 17
#define PWMIOCTL_UPDATE1 18
#define PWMIOCTL_UPDATE2 19
#define PWMIOCTL_UPDATE3 20
#define PWMIOCTL_UPDATE4 21
#define PWMIOCTL_START0 22
#define PWMIOCTL_START1 23
#define PWMIOCTL_START2 24
#define PWMIOCTL_START3 25
#define PWMIOCTL_START4 26
#define PWMIOCTL_TCNTB0 27
#define PWMIOCTL_TCNTB1 28
#define PWMIOCTL_TCNTB2 29
#define PWMIOCTL_TCNTB3 30
#define PWMIOCTL_TCNTB4 31
#define PWMIOCTL_TCMPB0 32
#define PWMIOCTL_TCMPB1 33
#define PWMIOCTL_TCMPB2 34
#define PWMIOCTL_TCMPB3 35
#define PWMIOCTL_TCMPB4 36
 
#define MOTOIOCTL_GPCDAT 200
 
#define MOTION_FORWARD             1
#define MOTION_STOP             2
#define MOTION_LEFTTURN            3
#define MOTION_RIGHTTURN  4
#define MOTION_BACKTURN           5
#define MOTION_BACKWARD           6
 
#define SERVO_STEP          2
#define SERVO_LEFT_MAX        7
#define SERVO_RIGHT_MAX            21
#define SERVO_MIDDLE            14
#define SERVO_DIRECT_LEFT   0
#define SERVO_DIRECT_RIGHT 1
 
#define SAVE_           0x140     //障碍物安全距离值
#define SAVE_1         0x70
#define SAVE_2         0x50
 
unsigned char Motion_Status = MOTION_STOP ;
unsigned short GP2D12_[30] ;
unsigned char Servo_val[30] = {51,57,63,69,75,81,87,93,99,105,111,117,123,129,135,141,147,153,159,165,171,177,183,189,195,201,207,213,219,225} ;
unsigned char Direct_val[8] = {0x0, 0x48, 0x0, 0x28, 0x42, 0x42, 0x22, 0x0} ;
unsigned char Speed_val[8] = {0x15, 0x20, 0x30, 0x46, 0x50, 0x5a, 0x60, 0x63} ;
 
unsigned char curSpeed = 0 ;
unsigned char curDegree = 0 ;
unsigned char curDegree_d = 0 ;
 
unsigned short turn_count = 0 ;
unsigned short lrturn_count = 0 ;
pthread_mutex_t mutex_turning;
 
int adc_fd,pwm_fd; 
 
void InitServo() ;
void InitMoto() ;
void SetServoDegree(unsigned char degree) ;
void SetMotoSpeed(unsigned char speed) ;
void SetMotoDirect(unsigned char direct) ;
int GetAdc() ;
void MeasureThread() ;
void MotionThread() ;
 
void InitServo() {
       int i = 0 ;
       i=0x20 ;
       ioctl(pwm_fd,PWMIOCTL_PRESALE0,&i); 
       i=0x3 ;
       ioctl(pwm_fd,PWMIOCTL_MUX0,&i); 
       i=1953 ; //i=1800 ;
       ioctl(pwm_fd,PWMIOCTL_TCNTB0,&i); 
       SetServoDegree(14) ;
}
 
void InitMoto() {
       SetMotoDirect(MOTION_STOP) ;
       SetMotoSpeed(curSpeed) ;
}
 
void SetServoDegree(unsigned char degree) {
       int i = 0 ;
       i=Servo_val[degree] ;
       ioctl(pwm_fd,PWMIOCTL_TCMPB0,&i); 
}
 
void SetMotoSpeed(unsigned char speed) {
       int i = 0 ;
       i=Speed_val[speed] ;
       ioctl(pwm_fd,PWMIOCTL_TCMPB1,&i);
}
 
void SetMotoDirect(unsigned char direct) {
       int i = 0 ;
       i=Direct_val[direct] ;
       ioctl(pwm_fd,MOTOIOCTL_GPCDAT,&i); 
}
 
int GetAdc() {
       int i = 0, ret = 0, tmp = 0 ;
       for(i=0;i<5;i++) {
              read(adc_fd,&tmp,sizeof(unsigned long));
              if(i>0) ret += tmp ;
       }
       return ret/4 ;
}
 
void MeasureThread()
{
        unsigned short adcData0 = 0 ;
       unsigned char save_count = 0 ;
       unsigned char save_count1 = 0 ;
       unsigned char save_count2 = 0 ;
        
//     Motion_Status = MOTION_STOP ;
        printf("MeasureThread,start ");
       
        while(1)
        {
 
         switch (Motion_Status) {
           case MOTION_LEFTTURN:
           case MOTION_RIGHTTURN:
              usleep(20000);
              pthread_mutex_lock(&mutex_turning); //等待转动一定角度后才开始检测
              pthread_mutex_unlock(&mutex_turning);
              while(1) {
                adcData0 = GetAdc() ;
                if(adcData0<=SAVE_) {
                  SetMotoDirect(MOTION_STOP) ;
                  Motion_Status = MOTION_STOP ;
                  break ;
                }
                if(Motion_Status != MOTION_LEFTTURN && Motion_Status != MOTION_RIGHTTURN)
                  break ;
              }
              break ;
              
           case MOTION_BACKWARD:
           case MOTION_BACKTURN:
              break ;
           
            default:
 
               if(curDegree
                 curDegree = SERVO_LEFT_MAX ;
                 curDegree_d = SERVO_DIRECT_RIGHT ;
               }
               if(curDegree>SERVO_RIGHT_MAX) {
                 curDegree = SERVO_RIGHT_MAX ;
                 curDegree_d = SERVO_DIRECT_LEFT ;
               }
 
              while(1) {
                adcData0 = GetAdc() ;
                if(adcData0>=SAVE_) {
                    //stop and sleep to do.
                    //
                         lrturn_count++ ;
                     if(curDegree>SERVO_MIDDLE) {
                           Motion_Status = MOTION_LEFTTURN ;
                           curDegree_d=SERVO_DIRECT_RIGHT ;
                           
                         } else {
                           Motion_Status = MOTION_RIGHTTURN ;
                           curDegree_d=SERVO_DIRECT_LEFT ;
                         }
                         save_count = 0 ;
                    save_count1 = 0 ;
                    save_count2 = 0 ;
                    curSpeed = 0 ;
                      SetMotoDirect(MOTION_STOP) ;
                    SetMotoSpeed(curSpeed) ;
                         break ;
                  
                } else if(adcData0
                    save_count2++ ;
                    save_count1++ ;
                         save_count++ ;
                    if(save_count2>8) {
                      curSpeed = 2 ;
                      save_count2 = 8 ;
                     }
                } else if(adcData0
                    save_count2 = 0 ;
                    save_count1++ ;
                         save_count++ ;
                    if(curSpeed == 2) curSpeed = 1 ;
                    if(save_count1>8) {
                      curSpeed = 1 ;
                      save_count1 = 8 ;
                     }
                } else if(adcData0
                    save_count1 = 0 ;
                    save_count2 = 0 ;
                         save_count++ ;
                    curSpeed = 0 ;
                }
                if(save_count>15) {
                    Motion_Status = MOTION_FORWARD ;
                    lrturn_count = 0 ;
                    save_count = 15 ;
                }
                SetMotoSpeed(curSpeed) ;
                
                if(curDegree_d==SERVO_DIRECT_LEFT) {  //控制伺服器旋转
                  curDegree -= SERVO_STEP ;
                  if(curDegree
                         curDegree=SERVO_LEFT_MAX ;
                         curDegree_d=SERVO_DIRECT_RIGHT ;
                  }
                } else {
                  curDegree += SERVO_STEP ;
                  if(curDegree>SERVO_RIGHT_MAX) {
                         curDegree=SERVO_RIGHT_MAX ;
                         curDegree_d=SERVO_DIRECT_LEFT ;
                  }
                }
                SetServoDegree(curDegree) ;
                
                usleep(40000);
                
                }
                break ;
              
          }
 
        }
}
 
void MotionThread()
{
 
        printf("MotionThread start.  ");
        while(1)
        {
 
         switch (Motion_Status) {
           case MOTION_FORWARD:
               while(Motion_Status==MOTION_FORWARD) {
                      SetMotoDirect(MOTION_FORWARD) ;
                      usleep(5000) ;
               }
               SetMotoDirect(MOTION_STOP) ;
              break ;
           case MOTION_STOP:
               usleep(5000) ;
                  break ;
           case MOTION_LEFTTURN:
                SetMotoDirect(MOTION_LEFTTURN) ;
              pthread_mutex_lock(&mutex_turning); //每次转动要保持转动一定时间
                if(lrturn_count>10) {
                  lrturn_count = 0 ;
                  usleep(1000000) ;
                } else {
                  usleep(200000) ;
                }
              pthread_mutex_unlock(&mutex_turning);
               while(Motion_Status==MOTION_LEFTTURN) {
                      SetMotoDirect(MOTION_LEFTTURN) ;
                      usleep(20000) ;
               }
               
               SetMotoDirect(MOTION_STOP) ;
               usleep(100000) ;
                  break ;
           case MOTION_RIGHTTURN:
                SetMotoDirect(MOTION_RIGHTTURN) ;
              pthread_mutex_lock(&mutex_turning);
                if(lrturn_count>10) {
                  lrturn_count = 0 ;
                  usleep(1000000) ;
                } else {
                  usleep(200000) ;
                }
              pthread_mutex_unlock(&mutex_turning);
               while(Motion_Status==MOTION_RIGHTTURN) {
                      SetMotoDirect(MOTION_RIGHTTURN) ;
                      usleep(20000) ;
               }
               SetMotoDirect(MOTION_STOP) ;
               usleep(100000) ;
                  break ;
            default:
               SetMotoDirect(MOTION_STOP) ;
              Motion_Status = MOTION_STOP ;
               usleep(5000) ;
                  break ;
         }
         
         
        }
        printf("MotionThread end.  ");
}
 
int main(void) 

       int ret; 
       pthread_t thread_id;
       unsigned long tmp; 
 
       adc_fd=open(ADC_DEV,O_RDWR); 
       pwm_fd=open(PWM_DEV,O_RDWR); 
       if(adc_fd < 0) 
       { 
         printf("Error opening %s adc device ", ADC_DEV); 
         return -1; 
       }
       if(pwm_fd < 0) 
       { 
         printf("Error opening %s adc device ", ADC_DEV); 
         return -1; 
       } 
       else 
         printf("device id is %d ",adc_fd) ; 
 
       
       InitServo();
       InitMoto() ;
       
       pthread_mutex_init (&mutex_turning,NULL);
       ret=pthread_create(&thread_id,NULL,(void *)MeasureThread,NULL);
       if(ret!=0){
              printf ("Create pthread error! ");
              return -1;
       }
       
       MotionThread() ;
       
       pthread_join(thread_id,NULL);
       
       close(adc_fd); 
       close(pwm_fd); 
       return 0; 
}
 
图片+视频+代码下载
相关链接:http://www.mcublog.com/blog/blog2007/coolwyc/archives/2007/24607.html

相关帖子

沙发
kingor_888| | 2007-8-24 11:00 | 只看该作者

congradulations!

使用特权

评论回复
板凳
lz13| | 2007-8-31 19:01 | 只看该作者

这个小车,用什么控制转向呀?

使用特权

评论回复
地板
zook0k| | 2007-9-10 14:20 | 只看该作者

太强啦

太酷了
小车

使用特权

评论回复
5
vikingrex| | 2007-9-12 00:08 | 只看该作者

牛X


强!!!!!!!!!!!!
强!!!!!!!!!!!!强!!!!!!!!!!!!强!!!!!!!!!!!!强!!!!!!!!!!!!
强!!!!!!!!!!!!强!!!!!!!!!!!!
强!!!!!!!!!!!!强!!!!!!!!!!!!

使用特权

评论回复
6
chenguozho| | 2007-9-12 15:35 | 只看该作者

感谢

代表人民给你深深鞠一躬!!!!

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

2

主题

7

帖子

0

粉丝