浙江省第五届大学生机器人竞赛比赛心得与部分实现方案

  比赛终于结束了,终于可以好好睡一觉了。比赛从四月份延到了七月份,但这丝毫没有影响我把这比赛硬生生打成电赛,前前后后制作的时间加起来可能也就只有完完整整一星期吧,还能拿到省三我已经很满足了。就开个贴给今后要参加比赛的同学们讲讲这段经历,讲讲我觉得比较重要的几点。

队友

  有没有好队友非常的关键,有两个好队友就成功了一半。我做的是超市购物组,相对来说比较好的搭配是一个机械的一个信电的一个计算的。不管是从车的结构还是底层驱动还是图像识别上都能够考虑到。由于我们组没有学机械的同学,对于一些车的结构来说虽然我们可以想到,但是要是做出来非常困难,AutoCAD这些画图建模软件也都不会用,丧失了一些竞争力。现场看到的一些车的结构真的是令人感到震撼。

  队友的关系也要好,最好是自己比较熟的,交流起来也比较方便。这次比赛过去心态崩了两天,队友硬是给我心态整回来了,这点非常感谢我的队友。总之,队友最好不要是那种带来划水的,没啥时间观念的,否则真的会很累,除非是大佬,轻松一带二。

训练场地

  可以说这次是吃了场地的大亏了,学校里的场地出发区并没有涂成红色的,而实际的比赛场地变成了红色的。赛场上调试的时候,巡线传感器直接懵逼了,连出发区都走不出去,心态直接爆炸了一点点。抓取货物的时候,发现学校里测试的场地和实际比赛的场地高度还是有个2~3cm的差别,直接导致了机械臂根本抓不到东西,心态又炸了一次。场地还是得严格按照规则来搭,否则真的到了场上心态要崩。要么机械臂程序的容错率要够高,才能避免场地制作带来的误差。

赛前准备

  说实话这个比赛的制作准备时间还是非常充裕的,千万不要像我一样把这个比赛做成电赛,连续肝几天几夜,一天只睡两三个小时。一定不要拖到最后几天才做。早做早调试早发现问题早解决。要用到的模块一定要多准备一些,至少完完全全的准备额外的一套。能带多少去就带多少!!!!不然场上坏了想换都换不了。我们的破机器人可以说是从头换到了尾,第二天舵机坏了,找隔壁组借了一个,连夜换了调试,舵机驱动板烧了一块,比赛开始前半小时,降压模块还莫名其妙地烧掉了,电压表还找不到借了一个,赶紧换了一个模块。多带一套还是非常有必要的。

硬件

  说真的,硬件真的是一分钱一分货,还是得买性能好的,该花的钱还是得花,不然赛场上就会出现各种模块爆炸的情况。我们一开始电机驱动用的是那种最便宜的L298N,起初重量没上去还是比较正常的,但是搭完车,电机的电流就开始增加了,小车旋转30s驱动就滚烫。后来换了一块70+的驱动,承载电流大了很多,也不是很烫了。隔壁做运输对抗的他们用两百一块的驱动,峰值电流还可以到200A,这驱动想烧了都难。

  再说说机械臂,由于我们并没有什么机械制作的基础,也就只能想到用机械臂了。大家买的时候一定要买那种结构比较稳定的!!!!!我们从上上届的车上拆了一条机械臂,动的时候晃的不行,每抓一次都捏一把汗。舵机也得全新的,本来还想着废物利用,后来全换成新的了。扭矩一定要够大!!!!https://item.taobao.com/item.htm?spm=a1z09.2.0.0.299e2e8dl9HVl5&id=578661255198&_u=d2jd14b827f9这家店应该是淘宝上比较便宜的了,质量也还行,但是我调的时候可能堵转太久了,还是烧了一个。

  机械臂的调试一直是非常麻烦的事情,本来想直接用arduino写程序调,但是后来觉得实在是太麻烦了,搞了一块舵机调试板子,还有上位机,拖拖拽拽就能调,还是比较方便的。尽管如此,机械臂的调试还是非常花时间,如果有什么东西可以把机械臂用手调好的状态记录下来那就太好了!(我在想peach)

  巡线传感器我看到很多人用的16路传感器,网上一搜价格劝退,但是前面用单个单个拼在一起又感觉太容易松动了,而且间距不太好控制。前期准备的时候我索性自己做了一个六路和单路的传感器,前面还有灯,再也不怕光线影响了,夜车都能开嘿嘿。但是这个电位器好像没啥用,调节不了灵敏度,在红色上还是认为是白的。可能这个地方大家需要自己再改进改进。这两个传感器我也都开源了网址附上:

https://lceda.cn/wywy/tcrt5000

https://lceda.cn/wywy/tcrt5000-6-lu

   降压模块也要多准备一些,主要还是要看电流的大小,给舵机、电机用电流一定得大,太小了一下子就很烫烧掉了,接线的时候一定要看清楚正负!!!!上次再实验室头昏了,接反了,一通电,一路火花带闪电,30块没了,实验室的小伙伴人都傻了,这也是我这么久来炸掉的第一个电容,人生圆满了。。。。附上降压模块遗照一张。

  最后我也不得不说一句,蓝牙模块拿来调车是真的好用,各种数据打回手机就行了,根本不用连电脑串口看数据,方便的很,和板子的TX、RX一连,手机app一开数据都有,爽得很。HC-04 HC-08都可以,强推蓝牙模块调车。

软件实现

  由于我只是做的底层控制,所以只能说说底层的软件怎么实现的。用的是比较简单的arduino mega2560,IO口也比较充足,串口也很多,完全足够连接各种模块。我也简单讲讲我都实现思路。下图是一开始没有考虑到出发区的红色,现场马上改了一下。

  修改之后是这样

  只走了外面的一大圈,但是拿奖还是够了,如果想冲省一,中间还是要拿的。

  附上我小车所有底盘代码:

#define jidianqi 13
#define wheel_left_en 44  
#define wheel_right_en 45 
#define left_wheel_in1 46 
#define left_wheel_in2 47 
#define right_wheel_in3 48 
#define right_wheel_in4 49 
#define qti_left 53  //黑色返回1
#define qti_right 52
#define f_qti1 38
#define f_qti2 39
#define f_qti3 40
#define f_qti4 41
#define f_qti5 42
#define f_qti6 43
#define b_qti1 32
#define b_qti2 33
#define b_qti3 34
#define b_qti4 35
#define b_qti5 36
#define b_qti6 37

unsigned char action0[5] = {0xFF, 0x09, 0x00, 0x00, 0x00};
unsigned char action1[5] = {0xFF, 0x09, 0x00, 0x01, 0x00};
unsigned char action2[5] = {0xFF, 0x09, 0x00, 0x02, 0x00};
unsigned char action3[5] = {0xFF, 0x09, 0x00, 0x03, 0x00};
unsigned char action4[5] = {0xFF, 0x09, 0x00, 0x04, 0x00};
unsigned char action5[5] = {0xFF, 0x09, 0x00, 0x05, 0x00};
unsigned char action6[5] = {0xFF, 0x09, 0x00, 0x06, 0x00};

unsigned char f_QTIS = 0xff;
unsigned char b_QTIS = 0xff;
unsigned char s_QTIS = 0xff;

int crossing_counts = 0;
byte stop_flag = 0;     //路口停止位,stop为1表示车停止,stop为0表示车未停止

int incomingByte = 0; // for incoming serial data
int result[7] = {};
int count = 0;

void setup() {
  delay(13000);
  car_init();
  motor_motion(80,80);
  delay(2000);
  stop_car();
  start_car();
}
void loop(){
  while(!stop_flag)
    Robot_hunting_judge_crossing();
  if((crossing_counts == 1)||(crossing_counts==2))
  {
    turn_left();
    start_car();
    motor_motion(255,255);
    delay(300);
  }
  else if(crossing_counts==3)
  {
    turn_right();
    start_car();
    motor_motion(255,255);
    delay(300);
  }
  else if((crossing_counts==12)||(crossing_counts==10)||(crossing_counts==11)||(crossing_counts==21)||(crossing_counts==19)||(crossing_counts==20)||(crossing_counts==30)||(crossing_counts==28)||(crossing_counts==29))
  {
    start_car();
    motor_motion(255,255);
    delay(300);
  }
  else if(((crossing_counts>=4)&&(crossing_counts<=8))||((crossing_counts>=13)&&(crossing_counts<=17))||((crossing_counts>=22)&&(crossing_counts<=26))||((crossing_counts>=31)&&(crossing_counts<=35)))
  {
    send_recieve_smd();
    how_carry_things();
    start_car();
    motor_motion(255,255);
    delay(300);
  }
  else if((crossing_counts==9)||(crossing_counts==18)||(crossing_counts==27)||(crossing_counts==36))
  {
    send_recieve_smd();
    how_carry_things();
    turn_right();
    start_car();
    motor_motion(255,255);
    delay(300);
  }
  else if(crossing_counts==37)
  {
    park_car();
  }
  stop_flag = 0;
}

void car_init()           //小车所用各个引脚初始化
{
  Serial.begin (115200);
  Serial1.begin (115200);
  Serial3.begin (9600);
  //初始化各IO,模式为OUTPUT 输出模式
  pinMode(jidianqi,OUTPUT);
  digitalWrite(jidianqi,LOW);
  pinMode(wheel_right_en,OUTPUT);
  pinMode(wheel_left_en,OUTPUT);
  pinMode(left_wheel_in1,OUTPUT);
  pinMode(left_wheel_in2,OUTPUT);
  pinMode(right_wheel_in3,OUTPUT);
  pinMode(right_wheel_in4,OUTPUT);
  digitalWrite(wheel_right_en,HIGH); //给高电平
  digitalWrite(wheel_left_en,HIGH); //给高电平
  pinMode(f_qti1,INPUT);
  pinMode(f_qti2,INPUT);
  pinMode(f_qti3,INPUT);
  pinMode(f_qti4,INPUT);
  pinMode(f_qti5,INPUT);
  pinMode(f_qti6,INPUT);
  pinMode(b_qti1,INPUT);
  pinMode(b_qti2,INPUT);
  pinMode(b_qti3,INPUT);
  pinMode(b_qti4,INPUT);
  pinMode(b_qti5,INPUT);
  pinMode(b_qti6,INPUT);
  pinMode(qti_left,INPUT);
  pinMode(qti_right,INPUT);
  digitalWrite(left_wheel_in1,HIGH); //给高电平
  digitalWrite(left_wheel_in2,LOW);  //给低电平
  digitalWrite(right_wheel_in3,HIGH); //给高电平
  digitalWrite(right_wheel_in4,LOW);  //给低电平
  send_arm_action(action0);
}

int f_readqti()       //读取前方QTI的值
{
  int f_qti,f_q1,f_q2,f_q3,f_q4,f_q5,f_q6;
  f_q1=digitalRead(f_qti1);
  f_q2=digitalRead(f_qti2);
  f_q3=digitalRead(f_qti3);
  f_q4=digitalRead(f_qti4);
  f_q5=digitalRead(f_qti5);
  f_q6=digitalRead(f_qti6);
  f_qti=32*f_q1+16*f_q2+8*f_q3+4*f_q4+2*f_q5+f_q6;
  f_qti=f_qti & 0x3f;
  return f_qti;
}

int b_readqti()      //读取后方QTI的值
{
  int b_qti,b_q1,b_q2,b_q3,b_q4,b_q5,b_q6;
  b_q1=digitalRead(b_qti1);
  b_q2=digitalRead(b_qti2);
  b_q3=digitalRead(b_qti3);
  b_q4=digitalRead(b_qti4);
  b_q5=digitalRead(b_qti5);
  b_q6=digitalRead(b_qti6);
  b_qti=32*b_q1+16*b_q2+8*b_q3+4*b_q4+2*b_q5+b_q6;
  b_qti=b_qti & 0x3f;
  return b_qti;
}

int side_readqti()    //读取两边QTI的值
{
  int s_qti,l_q,r_q;
  l_q=digitalRead(qti_left);
  r_q=digitalRead(qti_right);
  s_qti=2*l_q+r_q;
  s_qti=s_qti & 0x03;
  return s_qti;
}

void Robot_hunting()
{
  f_QTIS = f_readqti();
  switch (f_QTIS)
    {
      case 51:motor_motion(150, 150);break;     //1 110011 1,直行
      case 31:motor_motion(0, 255);break;    //011111,大幅左转
      case 15:motor_motion(0, 200);break;    //001111,大幅左转
      case 7:motor_motion(0, 150);break;     //000111,小幅左转
      case 39:motor_motion(0, 100);break;    //100111,小幅左转
      case 35:motor_motion(0, 100);break;    //100011,小幅左转
      case 55:motor_motion(0, 100);break;    //110111,小幅左转
      case 57:motor_motion(100, 0);break;    //111001,小幅右转
      case 49:motor_motion(100, 0);break;    //110001,小幅右转
      case 59:motor_motion(100, 0);break;    //111011,小幅右转
      case 56:motor_motion(150, 0);break;    //111000,小幅右转
      case 60:motor_motion(200, 0);break;    //111100,大幅右转
      case 62:motor_motion(255, 0);break;    //111110,大幅右转
      default:motor_motion(150, 150);break;
    }
   delay(5);
}

void Robot_hunting_judge_crossing()     //小车巡线加判断路口
{
   f_QTIS = f_readqti();
   s_QTIS = side_readqti();
   //Serial.print("f_QTIS=");
   //Serial.println(s_QTIS);
   if(s_QTIS==0){
      stop_car();
      delay(20);
      stop_flag = 1;
      crossing_counts++;
   }
   switch (f_QTIS)
    {
      case 51:motor_motion(80, 80);break;     //1 110011 1,直行
      case 31:motor_motion(0, 255);break;    //011111,大幅左转
      case 15:motor_motion(0, 200);break;    //001111,大幅左转
      case 7:motor_motion(0, 150);break;     //000111,小幅左转
      case 39:motor_motion(0, 100);break;    //100111,小幅左转
      case 35:motor_motion(0, 100);break;    //100011,小幅左转
      case 55:motor_motion(0, 100);break;    //110111,小幅左转
      case 57:motor_motion(100, 0);break;    //111001,小幅右转
      case 49:motor_motion(100, 0);break;    //110001,小幅右转
      case 59:motor_motion(100, 0);break;    //111011,小幅右转
      case 56:motor_motion(150, 0);break;    //111000,小幅右转
      case 60:motor_motion(200, 0);break;    //111100,大幅右转
      case 62:motor_motion(255, 0);break;    //111110,大幅右转
      default:motor_motion(80, 80);break;
    }
   delay(5);
}

void motor_motion(unsigned int left_val, unsigned int right_val)
{
  analogWrite(wheel_right_en,right_val);
  analogWrite(wheel_left_en,left_val);          
}

void turn_right()
{
  digitalWrite(left_wheel_in1,HIGH); //给高电平
  digitalWrite(left_wheel_in2,LOW);  //给低电平
  digitalWrite(right_wheel_in3,LOW);
  digitalWrite(right_wheel_in4,HIGH);
  motor_motion(255, 255);
  delay(600);
  while(1){
    f_QTIS = f_readqti();  
    if((f_QTIS == 51)||(f_QTIS == 49)||(f_QTIS == 35)||(f_QTIS == 57)||(f_QTIS == 39))
    {
      stop_car();
      break;
    }  
  }
}


/*
void turn_left()
{
  digitalWrite(left_wheel_in1,LOW); //给高电平
  digitalWrite(left_wheel_in2,HIGH);  //给低电平
  digitalWrite(right_wheel_in3,HIGH);
  digitalWrite(right_wheel_in4,LOW);
  motor_motion(255, 255);
  delay(1800);
  stop_car();
}

void turn_right()
{
  digitalWrite(left_wheel_in1,HIGH); //给高电平
  digitalWrite(left_wheel_in2,LOW);  //给低电平
  digitalWrite(right_wheel_in3,LOW);
  digitalWrite(right_wheel_in4,HIGH);
  motor_motion(255, 255);
  delay(1800);
  stop_car();
}

*/


void turn_left()
{
  digitalWrite(left_wheel_in1,LOW); //给高电平
  digitalWrite(left_wheel_in2,HIGH);  //给低电平
  digitalWrite(right_wheel_in3,HIGH);
  digitalWrite(right_wheel_in4,LOW);
  motor_motion(255, 255);
  delay(600);
  while(1){
    f_QTIS = f_readqti(); 
    //b_QTIS = b_readqti();
    if((f_QTIS == 51)||(f_QTIS == 49)||(f_QTIS == 35)||(f_QTIS == 57)||(f_QTIS == 39))
    {    
      stop_car();
      break;
    }  
  }
}


void stop_car(){
  digitalWrite(left_wheel_in1,LOW); 
  digitalWrite(left_wheel_in2,LOW); 
  digitalWrite(right_wheel_in3,LOW); 
  digitalWrite(right_wheel_in4,LOW);  
}

void start_car()       
{
  digitalWrite(left_wheel_in1,HIGH); //给高电平
  digitalWrite(left_wheel_in2,LOW);  //给低电平
  digitalWrite(right_wheel_in3,HIGH); //给高电平
  digitalWrite(right_wheel_in4,LOW);  //给低电平 
}

void send_arm_action(unsigned char action[])
{
  for(int i = 0; i < 5; i++)
  {
    Serial3.write(action[i]);
    delay(50);
  }

}

void send_recieve_smd()
{
  delay(1000);
  Serial1.write(49);
  delay(20);
  while(Serial1.read() >= 0){}//清空缓存,避免缓存的串口数据的影响
  while(incomingByte != 55)
  {
    if (Serial1.available() > 0) {
      // read the incoming byte:
      incomingByte = Serial1.read();
      result[count] = incomingByte;
      count++;
      // say what you got:
      //Serial.print("I received: ");
      //Serial.println(incomingByte, DEC);
    }
  }
  incomingByte = 0;
}

void how_carry_things()
{
  if((count == 1)||(count>7))
    ;
  else
  {
    for(int i = 0; i < (count-1); i++)  
    {
      if(result[i] == 49)
      {
        send_arm_action(action1);
        delay(15000);
      }
      else if(result[i] == 50)
      {
        send_arm_action(action2);
        delay(15000);
      }
      else if(result[i] == 51)
      {
        send_arm_action(action3);
        delay(15000);
      }
      else if(result[i] == 52)
      {
        send_arm_action(action4);
        delay(20000);
      }
      else if(result[i] == 53)
      {
        send_arm_action(action5);
        delay(16000);
      }
      else if(result[i] == 54)
      {
        send_arm_action(action6);
        delay(20000);
      }
      else
        ;
    }
  } 
  count = 0;
}

void park_car()
{
    turn_right();
    digitalWrite(jidianqi,HIGH);
}

   代码其实并不多,也就三百行。loop里其实是一直在找路口,然后根据路口的计数来判断应该做什么,还是非常简洁的,和上面的图一起看还是很清楚的。但是就是有一个很大的问题,就是转弯按照我这么写其实很不好,但是由于时间有限,我也没有什么好想法,在一个由于车的重心没有完全在中心点,或多或少都有问题,只能靠前面的巡线传感器巡线把车身摆正。串口三和舵机控制板连,串口一和树莓派连。购物车靠电磁铁拉着。

 暂且就写这么多了,以后想到有什么可以补充再补充。也欢迎大家下面评论区交流,虽然这是我的第一次机器人竞赛,也是我最后一次机器人竞赛了。希望大家在竞赛中都能有好运气好名次。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值