Assignment: Final Project

Plan - A
Final Project : Plan - B Rocking Robot
1. Description
2. Input device
3. Output device
4. 3D designing , 3D printering ,moulding and casting
5. Laser Cutting
6. Bluetooth and App control
7. Balance Vehicle -- Input/Output Device
8. 328P MCU connection and program
9. BOM
10. Final Presentation Slide and Video

Final project -- Rocking Robot

What to do

  • Controlled by mobile through bluetooth
  • Automatically track objects that are previously saved by camera
  • Distance broadcasts and responds to changes in distance
  • Commercial parts

    The final project use two main control boards. One is for integrated arduino board used in the balance vechile, which integrats MPU6050 sensor and power mamagement module. One is 328p, I made myself, which connects with the Pixy camera,Ultrasonic,Servo,Voicespeaker and bluetooth module. Actually, in the Rocking Robot, only the 328p is made myself, other electronic parts are commercial.


    Pixy Camera

    The website of the Pixy Camera is here.

  • Pixy uses a hue-based color filtering algorithm to detect objects. Pixy calculates the hue and saturation of each RGB pixel from the image sensor and uses these as the primary filtering parameters.
  • Pixy remembers up to 7 different color signatures. If you need more than seven, you can use color codes
  • Pixy can find literally hundreds of objects at a time.
  • You can get a complete update of all detected objects’ positions every 20 ms.
  • Ultrasonic

    When the ultrasonic sensor receives the trigger signal, it sends out an ultrasonic wave and starts the timing at the same time, and calculates the distance according to the time interval when the ultrasonic wave is received


    Servo

    The Rocking Robot head has two servos, one for horizontal rotation and the other for vertical rotation control.

    Voice Speaker module

    The website of the Voice Speaker module is here.

    The voice module stores some common sentences in advance, each sentence corresponds to a number, and N pulse signals are sent according to the chip manual, and the voice chip will broadcast N number pronunciation.The principle is shown below, detailed operation, please refer to the following program.


    Servo support frame

    The servo support frame consists of four parts.

  • You can download the bottom frame file here.
  • You can download the left frame file here.
  • You can download the right frame file here.
  • You can download the top frame file here.
  • Robert head cover

    I design the head cover for the Robot, and then cast it.

  • You can download the head 3D file here.

  • Laer Cutting

    I use laser cutter to cut the head piece of 3mm thickness plywood.

  • You can download the laser file here.

  • Bluetooth connection

    The TX pin of the Bluetooth module connects the RX pin of the UNO main board; the RX pin of the Bluetooth module connects the TX pin of the motherboard

    App control

    You can download the App software here.

    The functions of each button on the APP screen are as follows


    Balance Vehicle

    The Balance Vehicle, I purchased from Taobao, it can automatically maintain a balance, The Balance Vehicle is a I/O device to Rocking Robot, Rocking Robot communicates with the Balance Vehicle through the serial port , it sends command to move , rotate and so on.

    The Balance Vehicle get acceleration and gyroscope by MPU 6050, and control balance by PID algorithm, the source file can be downloaded below.


    328p MCU connection

    Since the 328p power supply pin is not enough, I put an external shield to expand the power pin. The specific sensor pin connections are as follows:

    Detailed data pin connections are as follows:

    Program

    												
    
    
    	#include < Voice.h>
    	#include < Servo.h>
    	#include < SPI.h>
    	#include < Pixy.h>
    
    	const byte Rst = A2; //6;
    	const byte Data = A1; //7; 片选
    	const byte Busy = A0; //8; 语音
    
    	const int trigPin = 8;   //超声波trigle引脚
    	const int echoPin = 9;   //超声波echo引脚
    	const int horPin = 6; //水平转动
    	const int verPin = 7; //上下转动
    
    	const int distMin = 10;    //定义响应的范围下限
    	const int distMax = 40;    //定义响应的范围上限
    
    	byte readBuffer[4];
    	unsigned int Command;   //接受按键:红外遥控器和手机app
    
    	Pixy pixy;
    	Voice voice(Rst, Data, Busy);
    	Servo horSer;
    	Servo verSer;
    
    	const int RANGE = 6;
    	const int maxVerAngle = 80;
    	const int minVerAngle = 10;
    	const int verAngleDefault = 40;
    	int dist = 0;
    	int angleHor = 90;
    	int angleVer = verAngleDefault;
    	int preDist = 0;  //用于保存先前的距离状态,用于判断是靠近还是远离
    	int nearOrLeft = 0;  //状态变量:0-靠近  1-远离
    	int StopMove = false;     // 小车运动功能 :false 关闭  true 开启
    	byte followFlag = 0;    //自动跟随 0关闭  1 打开超声波   2 视觉跟随
    	byte broadCastFlag = 0;  // 距离播报 0 关闭  1 距离播报  2 迎宾小人
    	byte ballScanFlag = 0;    // 静止找球 0 关闭  1 打开
    
    	byte followDist = 40;
    	byte followBalance = 15;
    
    	byte FunctionFlag = 0; // A B C D 按键对应的功能打开或关闭
    
    	void setup() {
    
    	  Serial.begin(9600);
    	  pinMode(trigPin, OUTPUT);
    	  pinMode(echoPin, INPUT);
    
    	  horSer.attach(horPin);
    	  verSer.attach(verPin);
    
    	  horSer.write(angleHor);
    	  delay(300);
    	  verSer.write(angleVer);
    	  delay(300);
    
    
    	}
    
    	void loop() {
    	  Command = 0;
    	  getCommand();    //获取按键
    	  Serial.println(Command, HEX);
    
    	  switch (Command) {
    		case 0x4c53 :         //左转
    		  TurnLeft();
    		  break;
    		case 0x5253 :         // 右转
    		  TurnRight();
    		  break;
    		case 0x5553:                 //前进
    		  Forward();
    		  break;
    		case 0x4453:                 //后退
    		  Backward();
    		  break;
    		case 0x4452:                 //停止
    
    		  break;
    		case 0x444c:          //减速
    
    		  break;
    		case 0x554c :           //加速
    
    		  break;
    		case 0x5552 :           //全速
    		  //      speedPWM = maxSpeedPwm;
    		  break;
    		case 0x4141 :        //A   自动跟随
    
    		  if (followFlag == 0) {   //打开超声波跟随
    			voice.VoiceWord(21);
    			voice.VoiceWord(66);
    			voice.VoiceWord(36);
    			followFlag = 1;
    			FunctionFlag = 1; // Function 功能打开
    		  } else  if (followFlag == 1) {   //打开视觉跟随
    			voice.VoiceWord(21);
    			voice.VoiceWord(66);
    			voice.VoiceWord(37);
    			followFlag = 2;
    			FunctionFlag = 1; // Function 功能打开
    		  } else   if (followFlag == 2) {   //打开视觉跟随
    			voice.VoiceWord(22);
    			followFlag = 0;
    			FunctionFlag = 0; // Function 功能打开
    		  }
    		  break;
    		case 0x4242 :         //B
    
    		  if (broadCastFlag == 0) {   //打开距离播报
    			voice.VoiceWord(21);
    			voice.VoiceWord(66);
    			voice.VoiceWord(36);
    			broadCastFlag = 1;
    			FunctionFlag = 1; // Function 功能打开
    		  } else  if (broadCastFlag == 1) {   //打开迎宾小人
    			voice.VoiceWord(21);
    			voice.VoiceWord(66);
    			voice.VoiceWord(37);
    			broadCastFlag = 2;
    			FunctionFlag = 1; // Function 功能打开
    		  } else   if (broadCastFlag == 2) {   //打开视觉跟随
    			voice.VoiceWord(22);
    			broadCastFlag = 0;
    			FunctionFlag = 0; // Function 功能打开
    		  }
    		  break;
    		case 0x4343 :         //C
    
    		  if (ballScanFlag == 0) {   //
    			voice.VoiceWord(21);
    			voice.VoiceWord(66);
    			voice.VoiceWord(37);
    			ballScanFlag = 1;
    			FunctionFlag = 1; // Function 功能打开
    		  } else  if (ballScanFlag == 1) {   //静止找球
    			voice.VoiceWord(21);
    			voice.VoiceWord(66);
    			voice.VoiceWord(37);
    			ballScanFlag = 2;
    			FunctionFlag = 1; // Function 功能打开
    		  } else   if (ballScanFlag == 2) {   //转动找球
    			voice.VoiceWord(22);
    			FunctionFlag = 0; // Function 功能打开
    		  }
    		  break;
    		case 0x4444 :         //D  小车运动功能停止
    		  StopMove = StopMove ? false : true;
    		  if (StopMove)
    			voice.VoiceWord(31);
    		  else
    			voice.VoiceWord(32);
    		  break;
    	  }
    
    	  //    Serial.print('Z');
    	  //  Serial.println('Z');
    
    	}
    
    	void getCommand() {
    	  char flag = 1;
    	  uint8_t num = 0;
    	  while (flag) {
    		if (Serial.available()) {
    		  uint8_t tempBuffer = Serial.read();
    		  readBuffer[num] = tempBuffer;
    		  num++;
    		  if (tempBuffer == 0x0D) {
    			Command = (readBuffer[0] < < 8) | (readBuffer[1]);
    			flag = 0;
    		  }
    		}
    
    		if (followFlag == 1)  // 超声波自动跟随
    		{
    		  followDriveUltraSonic();
    		}
    
    		if (broadCastFlag == 1)  // 距离播报
    		{
    		  followDriveUltraSonic();
    		}
    		if (broadCastFlag == 2)  // 迎宾小人
    		{
    		  welcom();
    		}
    		if (broadCastFlag == 1)  // 静止找球
    		{
    		  Ball_Scan_Stop();
    		}
    		if (broadCastFlag == 2)  // 转动找球
    		{
    		  Ball_Scan_Rotate();
    		}
    
    	  }
    	}
    	//******************************
    	//  功能:头部静止,转动车体找球
    	//  参数:无
    	//  返回值:全局变量dist  距离值cm
    	//*******************************
    	void Ball_Scan_Rotate() {
    	  static int i = 0;
    	  int j;
    	  uint16_t blocks;
    	  char buf[32];
    
    	  // grab blocks!
    	  blocks = pixy.getBlocks();
    
    	  // If there are detect blocks, print them!
    	  if (blocks)
    	  {
    		i++;
    
    		// do this (print) every 50 frames because printing every
    		// frame would bog down the Arduino
    		//    if (i % 2 == 0)    {
    		sprintf(buf, "Detected %d:\n", blocks);
    		Serial.print(buf);
    		for (j = 0; j < 1; j++)  //blocks
    		{
    		  int x = pixy.blocks[j].x;
    		  int y = pixy.blocks[j].y;
    		  int width = pixy.blocks[j].width;
    		  int height = pixy.blocks[j].height;
    		  int angle = 0;
    
    		  if (x < PIXY_MAX_X / 2 - RANGE) {
    		 
    			TurnRight();
    		  }
    		  if (x > PIXY_MAX_X / 2 + RANGE) {
    		   
    			TurnLeft();
    		  }
    		  if (y < PIXY_MAX_Y / 2 - RANGE) {
    			angle = map(y, PIXY_MAX_Y / 2, 0, 0, 5);
    			angleVer += angle;
    			angleVer = (angleVer >= maxVerAngle) ? maxVerAngle : angleVer;
    			verSer.write(angleVer);
    		  }
    		  if (y > PIXY_MAX_Y / 2 + RANGE) {
    			angle = map(y, PIXY_MAX_Y / 2, PIXY_MAX_Y, 0, 5);
    			angleVer -= angle;
    			angleVer = (angleVer <= minVerAngle) ? minVerAngle : angleVer;
    			verSer.write(angleVer);
    		  }
    
    		}
    
    		//    }
    		//    else {
    		//      Serial.println("no found");
    		//    }
    
    	  }
    	}
    	//******************************
    	//  功能:小车静止,头部找球
    	//  参数:无
    	//  返回值:全局变量dist  距离值cm
    	//*******************************
    	void Ball_Scan_Stop() {
    	  static int i = 0;
    	  int j;
    	  uint16_t blocks;
    	  char buf[32];
    
    	  // grab blocks!
    	  blocks = pixy.getBlocks();
    
    	  // If there are detect blocks, print them!
    	  if (blocks)
    	  {
    		i++;
    
    		// do this (print) every 50 frames because printing every
    		// frame would bog down the Arduino
    		//    if (i % 2 == 0)    {
    		sprintf(buf, "Detected %d:\n", blocks);
    		Serial.print(buf);
    		for (j = 0; j < 1; j++)  //blocks
    		{
    		  int x = pixy.blocks[j].x;
    		  int y = pixy.blocks[j].y;
    		  int width = pixy.blocks[j].width;
    		  int height = pixy.blocks[j].height;
    		  int angle = 0;
    
    		  if (x < PIXY_MAX_X / 2 - RANGE) {
    			angle = map(x, PIXY_MAX_X / 2, 0, 0, 9);
    			angleHor -= angle;
    			angleHor = (angleHor <= 0) ? 0 : angleHor;
    			horSer.write(angleHor);
    		  }
    		  if (x > PIXY_MAX_X / 2 + RANGE) {
    			angle = map(x, PIXY_MAX_X / 2, PIXY_MAX_X, 0, 9);
    			angleHor += angle;
    			angleHor = (angleHor >= 180) ? 180 : angleHor;
    			horSer.write(angleHor);
    		  }
    		  if (y < PIXY_MAX_Y / 2 - RANGE) {
    			angle = map(y, PIXY_MAX_Y / 2, 0, 0, 5);
    			angleVer += angle;
    			angleVer = (angleVer >= maxVerAngle) ? maxVerAngle : angleVer;
    			verSer.write(angleVer);
    		  }
    		  if (y > PIXY_MAX_Y / 2 + RANGE) {
    			angle = map(y, PIXY_MAX_Y / 2, PIXY_MAX_Y, 0, 5);
    			angleVer -= angle;
    			angleVer = (angleVer <= minVerAngle) ? minVerAngle : angleVer;
    			verSer.write(angleVer);
    		  }
    
    		}
    
    		//    }
    		//    else {
    		//      Serial.println("no found");
    		//    }
    
    	  }
    	}
    
    	void TurnLeft() {
    	  if (StopMove) {
    		Serial.print('G');
    		delay(200);
    	  }
    	}
    	void TurnRight() {
    	  if (StopMove) {
    		Serial.print('C');
    		delay(200);
    	  }
    	}
    
    
    	void Forward() {
    	  if (StopMove) {
    		Serial.print('A');
    		Serial.print('A');
    		delay(100);
    	  }
    
    	}
    
    	void Backward() {
    	  if (StopMove) {
    		Serial.print('E');
    		delay(200);
    	  }
    
    	}
    
    	void getDistance()     //分别返回左右超声波传感器的距离 当no=0 左侧  n=1 右侧
    	{
    	  digitalWrite(trigPin, LOW);
    	  delayMicroseconds(2);
    	  digitalWrite(trigPin, HIGH);
    	  delayMicroseconds(10);
    	  digitalWrite(trigPin, LOW);
    	  dist = pulseIn(echoPin, HIGH) / 58;
    	}
    
    	//******************************
    	//  功能:播报当前的距离值
    	//  参数:无
    	//  返回值:全局变量dist  距离值cm
    	//*******************************
    	void broadDistance()     //
    	{
    	  getDistance();
    	  Serial.println(dist);
    	  voice.VoiceWord(15);  //播报地址为15的语音,内容为:前方
    	  voice.VoiceNum(dist); //播报距离值distance
    	  voice.VoiceWord(16); //播报地址为15的语音,内容为:厘米
    	  voice.VoiceWord(67); //播报地址为33的语音,内容为:障碍物
    	  //  delay(10);
    	}
    
    	//******************************
    	//  功能:跟随模式
    	//  参数:无
    	//  返回值:dist  距离值cm
    	//*******************************
    	void  followDriveUltraSonic() {
    
    	  getDistance();
    	  if ((dist >= followDist - followBalance) && (dist <= followDist + followBalance)) {
    
    
    		if (dist >= followDist + 5) {
    		  Forward();
    		  delay(80);
    		}
    		if (dist <= followDist - 5) {
    		  Backward();
    		  delay(80);
    		}
    	  }
    	}
    
    	//******************************
    	//  功能:welcom
    	//  参数:无
    	//  返回值:全局变量dist  距离值cm
    	//*******************************
    	void welcom() {
    	  getDistance();  //获取当前超声波返回的距离值
    	  if ((dist <= distMax) && (dist >= distMin)) { // ❷
    		if (preDist < dist) {  // ❸
    		  nearOrLeft = 1;
    		}
    		else {
    		  nearOrLeft = 0;
    		}
    		if ((dist == distMin) && (nearOrLeft == 0)) { // ❹
    		  voice.VoiceWord(21);
    		  voice.VoiceWord(26);
    		  verSer.write(maxVerAngle);
    		  delay(500);
    		  verSer.write(verAngleDefault);
    		}
    		else if ((dist == distMax) && (nearOrLeft == 1)) { // ❺
    		  voice.VoiceWord(59);
    		}
    		preDist = dist;
    	  }
    	}
    
    
    
    

  • You can download the Arduino source file for Rocking Robot here.
  • You can download the library file for Rocking Robot here.
  • You can download the Arduino source file for Balance vehicle here.
  • You can download the library file for Balance vehicle here.

  • Balance vehicle (Commercial)

  • Encoder DC motor x 2
  • Wheel x 2
  • Coupling x2
  • L type motor bracket x 2
  • Arduino UNO x 1
  • DC motor driver TB6612FNG x 1
  • MPU-6050 x 1
  • Battery 3C x 1
  • Rocking Robot

  • 328p x 1
  • shield x 1
  • Pixy camera x 1
  • Ultrasonic sensor x 1
  • Servo(mg90) x 2
  • Bluetooth x 1
  • Voice Speaker module x 1
  • Battery 14500 3.7V x 2
  • Battery box x 1

  • Summary Slide

    Presentation video