极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 3268|回复: 0

全地形爆破赛小车的制作

[复制链接]
发表于 2022-12-2 14:53:51 | 显示全部楼层 |阅读模式
1. 比赛场地
       场地中设定四种五个不同特点、不同难度的障碍物,每种障碍物均有一定的分值,参赛队根据比赛规则自主设计制作全地形小车,完成穿越各个障碍物的比赛。
       障碍物分别为三种颜色的气球、楼梯、管道、窄桥,各障碍物由黑色引导线连接,形成完整的比赛赛道,并设置比赛起点和终点,比赛场地由组委会统一布置。
       全地形小车启动后自动行驶并跨越其他三种障碍物(管道,窄桥,楼梯)后,需识别颜色板上随机色卡的颜色并扎破对应颜色气球。

       场地地面为 408cm×175cm(尺寸误差±3cm) 的宝丽布,四周有高度为 18cm 的围栏。场地地面设有起点线和终止线,距离边缘 90cm。部分障碍前后20cm 设有标志线,供参赛队伍参考使用。距离长边 60cm 的两条红线为装饰线。5 个 障碍物按位置安放,并以双面胶固定在场地地面上,不可移动。黑线用 3.8cm 宽低反光绝缘胶带铺设。

场地尺寸图片详见https://www.robotway.com/h-col-120.html

关于气球说明:
气球颜色为:深红、深绿、深蓝
气球大小(宽):22cm和26cm之间,测量宽度方向以下图黑线示意为参考(横向最宽距离);

气球安装角度:气球横放,气嘴朝向终点线反方向,气球底面中部与场地布紧贴,气球 与场地布通过粘度较高的双面胶固定(以侧向拍打不掉落为准),气球固定位置距离气球底面中点误差±5cm;

关于扎气球的装置说明:扎气球装置末端可采用细小尖锐物体,如曲别针、图钉、牙签等,机器人上场前将对扎气球装置进行检验;
关于挡板布置,如下图蓝色外框(其中尺寸标注误差±10mm)

场地尺寸图片详见https://www.robotway.com/h-col-120.html

2. 示例样机
       本文采用的示例样机是基于月球车样机改造的。在此样机的基础上,在四个前后轮上缠绕了履带片以增大轮径,提高越障的性能。另外,在车身上增加了一个舵机驱动的摆杆,摆杆的顶部可以安装针甚至排针,用来刺破气球。

3. 示例程序
电子模块:Arduino UNO(Basra控制板×1,Bigfish扩展板)×1,灰度传感器×3,IIC颜色识别传感器)×1
编程环境:Arduino1.8.19
函数库:ServoTimer2、Adafruit_GFX、Adafruit_NeoPixel、MH_TCS34725

程序源代码如下:
Hit_Ballon_Car_yeyeyeye.ino
/*
*=====================================================================================================*
*实验接线:                                                                                            |
*=====================================================================================================*
*                       车头
*   灰度传感器:     A2   A3   A4
*                *----------------*
*                |                |
*                |                |
*                |                |
*                |                | 右侧
*         motor   |                | 车轮
*          9,10   |                | 5,6
*                |                |
*                |                |
*                |                |
*                |                |
*                |                |
*                *----------------*
*                       车尾
* 舵机接线:
*         气球舵机:3
*
*/

#include<ServoTimer2.h>        //调用舵机库函数
ServoTimer2 myServo;           //声明舵机
#define Forward_Left_Speed 125   //小车前进时左轮速度
#define Forward_Right_Speed 90//小车前进时右轮速度
#define Back_Left_Speed 160    //小车后退时左轮速度
#define Back_Right_Speed 110   //小车后退时右轮速度
#define Left_Left_Speed 235    //小车左转时左轮速度
#define Left_Right_Speed 240   //小车左转时右轮速度
#define Right_Left_Speed 235   //小车右转时左轮速度
#define Right_Right_Speed 240   //小车右转时右轮速度
#define Car_speed_stop 255     //小车刹车制动的速度
#define TrackingSensorNum 3    //小车寻迹时使用的灰度传感器数量

#define DEBUG                //程序进入调试模式
#define Debug_Color_Card     //检测色卡颜色
//#define Debug_Color_Balloon   //检测气球颜色
//#define Debug_Gray_Sensor    //检测灰度传感器
//#define Debug_Car_Forward    //检测小车走直线

int servo_num = 1;//定义舵机数量
int servo_port = 8;//定义舵机引脚
float value_init = 5;//定义舵机初始角度
int Car_DC_Motor_Pin[4] = {9,10,5,6};//直流电机引脚
int Gray_SensorPin[3]={A4,A3,A2};//寻迹、检测路口传感器
int f = 60; //定义舵机每个状态间转动的次数,以此来确定每个舵机每次转动的角度
int motor_num = sizeof(Car_DC_Motor_Pin) / sizeof(Car_DC_Motor_Pin[0]);//定义电机数量
int Car_Head_Gray_SensorPin_Num = sizeof(Gray_SensorPin)/sizeof(Gray_SensorPin[0]);//定义gray数量

bool finish=true;
int Gray_Three = 0; //记录三个灰度传感器同时触发的次数(即记录小车经过特殊路口的次数)
bool finish_all = true;//判断小车是否结束比赛(true表示没有结束比赛,false表示结束比赛)
int color_detection_card = 0; //记录颜色传感器识别到色卡的数值(红色为1,蓝色为2,绿色为3)
int color_detection_ballon = 0; //记录颜色传感器识别到气球的数值(红色为1,蓝色为2,绿色为3)
enum{Forward=1,Back,Left,Right,Stop,ForwardSpeedDown,BackSpeedDown,ForwardRoad,Tracking_automatic};//小车各种模式状态


void setup() {
  delay(1500);Serial.begin(9600);//打开串口并启用9600波特率
  Motor_Sensor_Init();//电机及传感器引脚初始化
  Servo_Init(); //舵机引脚初始化
  Color_Init();delay(1000);//颜色引脚初始化
  #ifdef DEBUG //判断小车是否要进入调试模式
    Car_Debug_Test();
  #endif
}

void loop() {

  Automatic_Tracking_analogRead();

}

Color_detection.ino
/*********************接线方式
TCS3473x   Arduino_Uno
  SDA         A4
  SCL         A5
  VIN         5V
  GND         GND
*************************/
#include <Wire.h>        //调用IIC库函数
#include "MH_TCS34725.h" //调用颜色识别传感器库函数

//颜色传感器不同通道值设置
MH_TCS34725 tcs = MH_TCS34725(TCS34725_INTEGRATIONTIME_50MS, TCS34725_GAIN_4X); //设置颜色传感器采样周期50毫秒

void Color_Init()
{
  if (tcs.begin()) {                 //如果检测到颜色传感器模块
    Serial.println("Found sensor");   //串口打印 Found sensor
  } else {                           //如果没有检测到颜色传感器模块
    Serial.println("No TCS34725 found ... check your connections");//串口打印:没有找到颜色识别传感器模块
    while (1); // halt! //程序陷入死循环
  }
}

/*
* color_judge[0]   red green
* color_judge[0]   green red
*/
void return_color_ballon()
{
  int numbers_count = 0;
  int color_judge[12]={0,0,0,0,0,0,0,0,0,0,0,0};
  int red_summer,green_summer,blue_summer;
  Serial.println("---------------Start---------------");
  unsigned long time_now = millis();
  while( (millis() - time_now ) < 2000)
  {
     numbers_count ++;
     uint16_t clear, red, green, blue;
     tcs.getRGBC(&red, &green, &blue, &clear);
     if(red>=blue){color_judge[0] = color_judge[0] +1;}   else{color_judge[1] = color_judge[1] +1;}
     if(red>=green){color_judge[2] = color_judge[2] +1;} else{color_judge[3] = color_judge[3] +1;}

     if(blue>=red){color_judge[4] = color_judge[4] +1;}   else{color_judge[5] = color_judge[5] +1;}
     if(blue>=green){color_judge[6] = color_judge[6] +1;} else{color_judge[7] = color_judge[7] +1;}

     if(green>=red){color_judge[8] = color_judge[8] +1;}   else{color_judge[9] = color_judge[9] +1;}
     if(green>=blue){color_judge[10] = color_judge[10] +1;} else{color_judge[11] = color_judge[11] +1;}     
  }
  Serial.println();
  if( (color_judge[0] > color_judge[1])   && ((color_judge[2] > color_judge[3])) )
  {
#ifdef DEBUG
    Serial.println("The color is red");
#endif
    color_detection_ballon = 1;
  }

  else if( (color_judge[4] > color_judge[5])   && ((color_judge[6] > color_judge[7]))   )
  {
#ifdef DEBUG
    Serial.println("The color is blue");
#endif
    color_detection_ballon = 2;
  }

  else if( (color_judge[8] > color_judge[9])   && ((color_judge[10] > color_judge[11])) )
  {
#ifdef DEBUG
    Serial.println("The color is green");
#endif
    color_detection_ballon = 3;   
  }
  else
  {
#ifdef DEBUG
    Serial.println("None color");
#endif   
  }
}


void return_color_card()
{
  int numbers_count = 0;
  int color_judge[12]={0,0,0,0,0,0,0,0,0,0,0,0};
  int red_summer,green_summer,blue_summer;
  Serial.println("---------------Start---------------");
  unsigned long time_now = millis();
  while( (millis() - time_now ) < 2000)
  {
     numbers_count ++;
     uint16_t clear, red, green, blue;
     tcs.getRGBC(&red, &green, &blue, &clear);
     if(red>=blue){color_judge[0] = color_judge[0] +1;}   else{color_judge[1] = color_judge[1] +1;}
     if(red>=green){color_judge[2] = color_judge[2] +1;} else{color_judge[3] = color_judge[3] +1;}

     if(blue>=red){color_judge[4] = color_judge[4] +1;}   else{color_judge[5] = color_judge[5] +1;}
     if(blue>=green){color_judge[6] = color_judge[6] +1;} else{color_judge[7] = color_judge[7] +1;}

     if(green>=red){color_judge[8] = color_judge[8] +1;}   else{color_judge[9] = color_judge[9] +1;}
     if(green>=blue){color_judge[10] = color_judge[10] +1;} else{color_judge[11] = color_judge[11] +1;}     
  }
  Serial.println();
  if( (color_judge[0] > color_judge[1])   && ((color_judge[2] > color_judge[3])) )
  {
#ifdef DEBUG
    Serial.println("The color is red");
#endif
    color_detection_card = 1;  
  }

  else if( (color_judge[4] > color_judge[5])   && ((color_judge[6] > color_judge[7]))   )
  {
#ifdef DEBUG
    Serial.println("The color is blue");   
#endif
    color_detection_card = 2;
  }
  else if( (color_judge[8] > color_judge[9])   && ((color_judge[10] > color_judge[11])) )
  {
#ifdef DEBUG
    Serial.println("The color is green");
#endif
    color_detection_card = 3;   
  }  
  else
  {
#ifdef DEBUG
    Serial.println("None color");
#endif   
  }
}

void color()
{
uint16_t clear, red, green, blue;
tcs.getRGBC(&red, &green, &blue, &clear);
Serial.print("red:");Serial.print(red);Serial.print(" | ");
Serial.print("blue:");Serial.print(blue);Serial.print(" | ");
Serial.print("green:");Serial.println(green);
}

Servo_Move_Control.ino
//===================舵机========================舵机=======================舵机=======================舵机===========================舵机==========================舵机==============================舵机==============================舵机
//====舵机===========================舵机======================舵机=======================舵机=========================舵机==========================舵机============================舵机==================================舵机=============
//===================舵机========================舵机=======================舵机=======================舵机===========================舵机==========================舵机==============================舵机==============================舵机
//void Servo_Init()
//{
//   for(int i=0;i<servo_num;i++)
//   {
////    myServo.attach(servo_port);
////    myServo.write(map(value_init,0,180,500,2500));
////    delay(20);
//    myServo.attach(servo_port);
//    myServo.write(map(value_init,0,180,500,2500));
//    delay(20);
//   }
//}

void Servo_Init()
{
  for(int i=0;i<servo_num;i++)
  {
//    myServo.attach(servo_port);
//    myServo.write(map(value_init,0,180,500,2500));
//    delay(20);
    myServo.attach(servo_port);
    myServo.write(map(value_init,0,180,500,2500));
    delay(20);
  }
}

//void ServoStop(int which){//释放舵机
//   myServo[which].detach();
//   digitalWrite(servo_port[which],LOW);
//}

void ServoStop(){//释放舵机
  myServo.detach();
  digitalWrite(servo_port,LOW);
}

//void ServoGo(int which , float where){//打开并给舵机写入相关角度
//   if(where!=200){
//    if(where==201) ServoStop(which);
//    else{
//      myServo[which].write(map(where,0,180,500,2500));
//    }
//   }
//}

void ServoGo(float where){//打开并给舵机写入相关角度
  if(where!=200){
    if(where==201) ServoStop();
    else{
      myServo.write(map(where,0,180,500,2500));
    }
  }
}

void Servo_Move_Single(int Start_angle,int End_angle,unsigned long Servo_move_time)
{
  int servo_flags = 0;
  int delta_servo_angle = abs(Start_angle-End_angle);
  if( (Start_angle - End_angle)<0 )
  {
    servo_flags = 1;
  }
  else{ servo_flags = -1; }
  for(int i=0;i<delta_servo_angle;i++)
  {
    myServo.write(map( Start_angle+(servo_flags*i) ,0,180,500,2500));
    delay(Servo_move_time);
  }
}

//void servo_move(float value0, float value1, float value2,int delaytimes){ //舵机动作函数
//   float value_arguments[] = {value0, value1, value2};
//   float value_delta[servo_num];  
//   for(int i=0;i<servo_num;i++){
//    value_delta = (value_arguments - value_init) / f;
//   }  
//   for(int i=0;i<f;i++){
//    for(int k=0;k<servo_num;k++){
//      value_init[k] = value_delta[k] == 0 ? value_arguments[k] : value_init[k] + value_delta[k];
//    }
//    for(int j=0;j<servo_num;j++){
//      ServoGo(j,value_init[j]);
//    }
//    delay(delaytimes/f);
//   }
//}

void Zha_Qi_Qiu(int Numbers)
{
  for(int i=0;i<Numbers;i++)
  {
//    myServo.write(map( 130 ,0,180,500,2500));delay(350);
    myServo.write(map( 175 ,0,180,500,2500));delay(1000);
    myServo.write(map( 5 ,0,180,500,2500));delay(1000);
//    Servo_Move_Single(130,,2);delay(1000);
//    Servo_Move_Single(30,130,3);delay(1000);
  }
}

4. 资料内容
全地形排爆车样机3D文件
全地形排爆车完整程序
全地形排爆车例程配套函数库
全地形爆破赛-场地制作文件

资料下载链接https://www.robotway.com/h-col-120.html



本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则 需要先绑定手机号

Archiver|联系我们|极客工坊

GMT+8, 2024-4-28 23:13 , Processed in 0.060714 second(s), 18 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2021, Tencent Cloud.

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