/* * * Smart Robot Car V3 * - HC-06(Bluetooth Control) * - L293D IC * - Ultrasonic sensor(optional) */ #include /////////////////////// // // TX <-----> RX // RX <-----> TX /////////////////////// SoftwareSerial btSerial(10, 11); // RX, TX(UNO) /////////////////////////////////////////////////////////////// // Note: ENA and ENB must be connected to PWD supported pins // #define ENA 3 // PWD #define EN1 2 #define EN2 4 #define EN3 5 #define EN4 7 #define ENB 6 // PWD //////////////////////////////////////// // Ultrasonic sensor //////////////////////////////////////// int TRIG_pin = 12; // 센서 Trig 핀, D12 int ECHO_pin = 13; // 센서 Echo 핀, D13 #define blinkLED 8 // for crash warning /////////////////////// // Car direction // #define CAR_DIR_FW 0 // forward #define CAR_DIR_BK 1 // backward #define CAR_DIR_LT 2 // left turn #define CAR_DIR_RT 3 // right turn #define CAR_DIR_ST 4 // stop /////////////////////////////////// // Default direction and speed // int g_carDirection = CAR_DIR_ST; int g_carSpeed = 230; // 60% of max speed for testing //////////////////////////////////////////////// // Note : confirm HIGH/LOW for correct movement // void car_forward() { digitalWrite(EN1, LOW); digitalWrite(EN2, HIGH); analogWrite(ENA, g_carSpeed); digitalWrite(EN3, LOW); digitalWrite(EN4, HIGH); analogWrite(ENB, g_carSpeed); } void car_backward() { digitalWrite(EN1, HIGH); digitalWrite(EN2, LOW); analogWrite(ENA, g_carSpeed); digitalWrite(EN3, HIGH); digitalWrite(EN4, LOW); analogWrite(ENB, g_carSpeed); } void car_left() { digitalWrite(EN1, HIGH); digitalWrite(EN2, LOW); analogWrite(ENA, g_carSpeed); digitalWrite(EN3, LOW); digitalWrite(EN4, HIGH); analogWrite(ENB, g_carSpeed); } void car_right() { digitalWrite(EN1, LOW); digitalWrite(EN2, HIGH); analogWrite(ENA, g_carSpeed); digitalWrite(EN3, HIGH); digitalWrite(EN4, LOW); analogWrite(ENB, g_carSpeed); } void car_stop() { analogWrite(ENA, 0); analogWrite(ENB, 0); } //////////////////////////// // Execute car moving // void update_Car() { switch ( g_carDirection ) { case CAR_DIR_FW: car_forward(); break; case CAR_DIR_BK: car_backward(); break; case CAR_DIR_LT: car_left(); break; case CAR_DIR_RT: car_right(); break; case CAR_DIR_ST: car_stop(); break; default : ; } return; } /////////////////////////////////// // Class - Serial Protocol // class _CommProtocol { private: unsigned char protocolPool[28]; int bufPoint; public: _CommProtocol() { } void addPool(unsigned char cByte) { if (bufPoint < 28) { if (bufPoint == 0 and cByte != 0x0c) return; // invalid code protocolPool[bufPoint++]=cByte; //Serial.print("bufPoint -> "); //Serial.println(bufPoint); } } void clearPool() { bufPoint = 0; memset(protocolPool, 0x00, 28); Serial.println("clearPool"); } bool isValidPool() { if (bufPoint >= 28) { //Serial.print("protocol length : "); if (protocolPool[0] == 0x0c && protocolPool[14] == 0x0c) { //Serial.println(protocolPool.length()); return true; } else { clearPool(); Serial.println("isValidPool 28 OVER"); } } return false; } unsigned char getMotorLValue() { unsigned char szProto[14]; memcpy(szProto, protocolPool, 14); if (szProto[0] == 0x0C && szProto[1] == 0x00 && szProto[2] == 0x80 && szProto[3] == 0x04 && szProto[4] == 0x02) { unsigned char l = szProto[5];// -0x32; return l; } return 0x00; } unsigned char getMotorRValue() { unsigned char szProto[14]; memcpy(szProto, &protocolPool[14], 14); if (szProto[0] == 0x0C && szProto[1] == 0x00 && szProto[2] == 0x80 && szProto[3] == 0x04 && szProto[4] == 0x01) { unsigned char l = szProto[5];// -0x32; return l; } return 0x00; } }; // class(_CommProtocol) //////////////////////////////////////////////// // Create an instance of class(_CommProtocol) // _CommProtocol SerialCommData; //////////////////////////////////////////////////////////// // Parse the serial input value and convert to MOVE command // void process_SerialCommModule() { if (SerialCommData.isValidPool()) { char motorLR[2]; motorLR[0] = (char)SerialCommData.getMotorLValue(); motorLR[1] = (char)SerialCommData.getMotorRValue(); SerialCommData.clearPool(); // Serial.print("Left ["); Serial.print(motorLR[0],DEC); Serial.print("] Right ["); Serial.print(motorLR[1],DEC); Serial.println("]"); // char szCmdValue = '5'; // set MOVE commands if (motorLR[0] == 0 && motorLR[1] == 0) { // (0,0) stop szCmdValue = '5'; } else { int nSpeed; nSpeed = max(abs(motorLR[0]), abs(motorLR[1])); // Set direction if (motorLR[0] > 0 && motorLR[1] > 0) // (+,+) forward { szCmdValue = '2'; g_carSpeed = 255.0f * ((float)nSpeed / 100.0f); } else if (motorLR[0] < 0 && motorLR[1] < 0) // (-,-) backward { szCmdValue = '8'; g_carSpeed = 255.0f * ((float)nSpeed / 100.0f); } else if (motorLR[0] < 0 && motorLR[1] > 0) // (-,+) left turn { szCmdValue = '4'; g_carSpeed = 255.0f * ((float)((float)nSpeed*1.66f) / 100.0f); } else if (motorLR[0] > 0 && motorLR[1] < 0) // (+,-) right turn { szCmdValue = '6'; g_carSpeed = 255.0f * ((float)((float)nSpeed*1.66f) / 100.0f); } } // Serial.print("speed "); Serial.print(g_carSpeed); Serial.print(" "); Serial.println(szCmdValue); // // Set the direction and speed with command controlByCommand(szCmdValue); } } ////////////////////////////////////////////////// // Hint : Command codes come from keypad numbers // void controlByCommand(char doCommand) { switch ( doCommand ) { case '+' : // speed up g_carSpeed += 20; g_carSpeed = min(g_carSpeed, 255); break; case '-' : // speed down g_carSpeed -= 20; g_carSpeed = max(g_carSpeed, 75); break; case '2' : // forward g_carDirection = CAR_DIR_FW; break; case '5' : // stop g_carDirection = CAR_DIR_ST; break; case '8' : // backward g_carDirection = CAR_DIR_BK; break; case '4' : // left g_carDirection = CAR_DIR_LT; break; case '6' : // right g_carDirection = CAR_DIR_RT; break; default : ; } return; } void setup() { Serial.begin(9600); // PC serial monitor debugging btSerial.begin(9600); // bluetooth serial connection //init car control board pinMode(ENA, OUTPUT); pinMode(EN1, OUTPUT); pinMode(EN2, OUTPUT); pinMode(ENB, OUTPUT); pinMode(EN3, OUTPUT); pinMode(EN4, OUTPUT); pinMode(blinkLED, OUTPUT); // for crash check pinMode(TRIG_pin, OUTPUT); pinMode(ECHO_pin, INPUT); // Serial.print("direction value "); Serial.println(g_carDirection); Serial.print("speed pwm value "); Serial.print(g_carSpeed); Serial.println(""); // } void loop() { //alert_Bump(); // blink LED if (btSerial.available()) { unsigned char cByte; cByte = btSerial.read(); SerialCommData.addPool(cByte); // store the serial input to Buffer process_SerialCommModule(); // parse and change the input value to MOVE command update_Car(); // execute car MOVE } } //////////////////////////////////////////// // Ultrasonic sensor : calculate distance // Blink LED if distance < 20 // bool alert_Bump() { long duration, cm; digitalWrite(TRIG_pin, HIGH); // 센서에 Trig 신호 입력 delayMicroseconds(10); // 10us 정도 유지 digitalWrite(TRIG_pin,LOW); // Trig 신호 off duration = pulseIn(ECHO_pin,HIGH); // Echo pin: HIGH->Low 간격을 측정 cm = microsecondsToCentimeters(duration); // 거리(cm)로 변환 if (cm < 20) { Serial.print("cm -> "); Serial.println(cm); digitalWrite(blinkLED, HIGH); return true; } else digitalWrite(blinkLED, LOW); return false; } long microsecondsToCentimeters(long microseconds) { return microseconds/29/2; }