Reference

Wall Follower : https://goo.gl/6bTBz6
Recursive Algorithm : https://goo.gl/5l44Eh
Arduino MEGA 2560 : https://goo.gl/8Oi7Jv
Arduino  UNO : https://goo.gl/jtYgEb
Bluetooth HC-05 : https://goo.gl/vmX4iM
Pixy CMUcam5 : https://goo.gl/Z9gpf9
Adafruit Motor Shield : https://goo.gl/3hnqFt
OpenCM9.04-C : https://goo.gl/e4OYSn
Dynamixel XL-320 : https://goo.gl/Uc3e7D


Our Team Photo


สมาชิกที่ทำ Robo Maze




















Programming Implementation

           ในส่วนต่อไปคือโปรแกรมในการเคลื่อนที่นั้นนอกจากจะใช้ encoder ในการวัดระยะในการเคลื่อนที่แล้ว  ยังสามารถนำมาควบคุมความเร็วในการเคลื่อนที่ได้อีกด้วย  โดยจะใช้หลักการนับสัญญาณพัลส์ได้กี่พัลส์ใน 100 มิลลิเซค  (ms)




ยกตัวอย่าง  ::  ถ้ามอเตอร์หมุนและส่งสัญญาณพัลส์ได้ 10 พัลส์ต่อ 100 มิลลิเซค  ถ้ารับสัญญาณพัลส์ได้ น้อยกว่า 10 พัลส์จะทำการเพิ่มความเร็วมอเตอร์  แต่ถ้ารับสัญญาณพัลส์ได้มากกว่า 10 จะลดความเร็วมอเตอร์





ถ้าในระหว่างการสำรวจเส้นทางถ้าหุ่นยนต์เกิดการเอียงจะใช้ Ultrasonic ในการช่วยตรวจสอบและปรับความเร็วมอเตอร์ได้ โดยการที่เราแบ่งช่วงเซ็นเซอร์ของ Ultrasonic เป็นระยะใกล้  กลาง  ไกล  จะเทียบกับกำแพง ถ้าวัดได้ระยะใกล้จะทำการเพิ่มความเร็วมอเตอร์ข้างซ้าย
                 ถ้าวัดได้ระยะกลางจะทำการปรับความเร็วมอเตอร์ทั้ง 2 ข้างเท่ากัน
                 ถ้าวัดได้ระยะไกลจะทำการเพิ่มความเร็วมอเตอร์ข้างขวา

การติดต่อสื่อสารระหว่างหุ่นยนต์กับคอมพิวเตอร์


 การสื่อสารระหว่างหุ่นยนต์และคอมพิวเตอร์ จะอาศัย การสื่อสารแบบไร้สายระยะใกล้ คือ การใช้ 
บลูทูท (Bluetooth) ส่งข้อความหรือ ตัวเลขเพื่อสื่อสารกัน 

1. การส่งข้อมูลของคอมพิวเตอร์ถึง หุ่นยนต์

ใน หุ่นยนต์ สามารถเคลื่อนที่ได้ 4 ลักษณะ คือ การเดินไปข้างหน้า การหันไปทางซ้าย การหันไปทางขวา และการหันกลับหลัง

ดังนั้นเมื่อถึงเวลาที่ต้องสำรวจ (Exploration) จะต้องส่งคำสั่งให้กับหุ่น รหัสการสั่งมีดังนี้
รหัสเลข 0 จะเป็นคำสั่งให้หุ่นเคลื่อนไปข้างหน้า
รหัสเลข 1 จะเป็นคำสั่งให้หุ่นเคลื่อนถอยหลัง
รหัสเลข 2 เป็นคำสั่งให้เลี้ยวซ้าย
รหัสเลข 3 เป็นคำสั่งให้เลี้ยวขวา
รหัสเลข 4 เป็นคำสั่งให้หันกลับหลัง

รหัส 0 1 2 3 4 นั้นมีประโยชน์ต่อการโปรแกรม ในภาษา ซี อันเนื่องจาก คุณสมบัติของ enumeration ซึ่งสามารถใช้ตัวเลข เพื่อเรียก ข้อความที่อยู่ในฟังก์ชัน enum ทำให้สะดวกต่อการเรียกใช้และประมวลผลของโปรแกรมจากคอมพิวเตอร์


2. การส่งข้อมูลของหุ่นยนต์ไปยังคอมพิวเตอร์

เนื่องจากว่า สิ่งกีดขวางของหุ่นประกอบไปตามเซ็นเซอร์อัลตราโซนิก ซึ่งติดตั้งในหุ่น ทำให้หุ่นสามารถตรวจจับสิ่งกีดขวาง รวมถึงมี กล้องจับสีภาพ PIXY ช่วยในการจับสีที่กล้องตรวจจับได้

สิ่งกีดขวางที่เป็นไปได้คือ กำแพง ด้านต่างๆ ซึ่งประกอบไปด้วย กำแพงด้านซ้าย ด้านขวา และข้างหน้า
ดังรูปที่ 1  สิ่งกีดขวาง หรือ พื้นที่ว่าง  ดังรูปที่่ 2

รูปที่ 1 รูปแสดงตำแหน่งการติดตั้งของอุปกรณ์ตรวจจับ หรือ เซนเซอร์อัลตราโซนิก



รูปที่ 2 รูปแสดงการตรวจจับสิ่งกีดขวาง ที่อยู่ตรงหน้าของเซนเซอร์


ค่าที่ตรวจจับ หากเป็นกำแพง จะส่งค่าที่เป็น 1 มาทำให้ทราบว่ามีสิ่งกีดขวาง
ค่าที่ถูกตรวจจับ หากเป็นช่องว่าง  จะส่งค่าที่เป็น 0 มาทำให้ทราบว่าบริเวณนั้นเป็นทางที่สามารถเดินได้
ตามตัวอย่าง ดังรูปที่ 3


รูปที่ 3 รูปแสดงสิ่งกีดขวาง และการส่งข้อมูล ไปยังคอมพิวเตอร์


ค่าเหล่านี้ก็จะถูกส่งกลับไปยัง คอมพิวเตอร์เพื่อสร้างแผนที่ที่ สำรวจ

การจับสีภาพของกล้อง pixy นั้นจะสามารถทำได้โดยการกำหนด หาก สีเป็นดังต่อไปนี้
รหัสสี 0 หมายถึง  สีขาว
รหัสสี R หมายถึง  สีแดง
รหัสสี G หมายถึง สีเขียว
รหัสสี B หมายถึง สีน้ำเงิน



รูปที่ 4 รูปแสดง รหัสของการตรวจจับสี โดยกล้อง pixy


Source Code #


#include <AFMotor.h>
float dir = 0.0, error = 0.0, no_wall = 40;
int sl = 0, sr = 0, spd_l = 200, spd_r = 250, sl_c = 0, sr_c = 0;
enum Wallcolor {white, red, green, blue, orange};
enum direct {forw, left, right, retn, right2, left2};
enum command {fow, lef, rgt, rtn, none, rtn2};
enum ck_sen {clr, ct_sen, sd_data, ct_rtn, ct_fw};
int en1 = 21, en2 = 20; //180//180
int n = 0, clr_n = 0, start2 = 0;
char p1 = ' ', p = ' ';
char test[128];
int n_reval = 0, kk = 0;
unsigned de = 0;
unsigned int ti, ti_pre = 0;
int mode1 = 0, mode = 0, mode2 = 0 , mode3 = 0 , n_sf = 0;
char p3;
String data;
String sm[3];
int sen[3], sd[3];
int nn = 0;
int Scut = 0;
ck_sen ck_sn;
direct dirt;
command cmd;
AF_DCMotor m1(1);
AF_DCMotor m2(2);

void setup()
{
  pinMode(en1, INPUT);
  pinMode(en2, INPUT);
  pinMode(32, OUTPUT);
  attachInterrupt(digitalPinToInterrupt(en1), en_l, RISING );
  attachInterrupt(digitalPinToInterrupt(en2), en_r, RISING );

  Serial.begin(9600);
  Serial1.begin(9600); // For uno
  Serial2.begin(9600); //For Bluetooth

  m1.setSpeed(199);
  m2.setSpeed(245);
  mode = 0; clr_en();
  m_stp();
  delay(2000); p1 = ' '; p = ' '; cmd = none; ck_sn = clr;
  digitalWrite(32, HIGH);
  delay(20);
  digitalWrite(32, LOW); //m_for();
  // Serial2.println("R");

}

void loop()
{
  //Serial.println(test);

  if (sen[0] <= 13 )
  {
    if ((sen[0] > 0 && sen[0] < 8) && (sen[2] < 38 && sen[2] > 16))
    {
      dirt = right;
    }
    else if ((sen[0] > 0 && sen[0] <= 13) && sen[2] > 38)
    {
      dirt = forw;
    }
    else if ((sen[0] > 0 && sen[0] < 8) && sen[2] < 16 && sen[2] > 9)
    {
      dirt = right2;
    }
    else
    {
      dirt = forw;
    }
  }
  else if (sen[0] > 16)
  {
    if ((sen[2] > 0 && sen[2] < 8 ) && (sen[0] < 38 && sen[0] > 16))
    {

      dirt = left;
    }
    else if ((sen[2] > 0 && sen[2] < 8 ) && sen[0] > 38)
    {
      dirt = forw;
    }
    else if ((sen[2] > 0 && sen[2] < 8 ) && sen[0] < 16 && sen[0] > 9)
    {
      dirt = left2;
    }
    else
    {
      dirt = forw;
    }
  }
  ////////////////////////////

  if (ck_sn == ct_sen)
  { if (sd[0] == 1 && sd[1] == 1 && sd[2] == 1)
    {
      digitalWrite(32, HIGH);
      delay(50);
      digitalWrite(32, LOW);
    }
    else
    {
      digitalWrite(32, LOW); delay(50);
    }/*
    Serial.print(sd[0]); Serial.print(","); Serial.print(sd[1]); Serial.print(","); Serial.print(sd[2]);
    Serial.print(","); Serial.println(white);*/
    de++;
    if (de > 28)
    {
      de = 0;
      ck_sn = sd_data;
    }
  }
  else if (ck_sn == sd_data)
  { de++; delay(50);

    if (de > 15)
    { de = 0;
      clr_en();
      if (sen[1] < 14)
      {
        ck_sn = ct_rtn; de = 0;
      }
      else if (sen[1] < 37 && sen[1] > 20)
      {
        ck_sn = ct_fw; de = 0;
      }
      else
      {
        Serial2.print(sd[0]); Serial2.print(","); Serial2.print(sd[1]); Serial2.print(","); Serial2.print(sd[2]);
        Serial2.print(","); Serial2.println(white);
        digitalWrite(32, HIGH);
        delay(50);
        digitalWrite(32, LOW);
        clr_en(); ck_sn = clr;
        de = 0;

      }
    }
  }
  else if (ck_sn == ct_rtn)
  { // Serial2.println(sen[1]);
    m_re(); de = 0;
    if (sl > 12 && sr > 12)
    { Serial.print("yyy  "); Serial.println(ck_sn);
      de = 0;

      m_stp();
      delay(800);
      clr_en(); ck_sn = ct_sen;
    }

  }
  else if (ck_sn == ct_fw)
  {
    m_for();
    de = 0;
    if (sl > 12 && sr > 12)
    { Serial.print("yyy  "); Serial.println(ck_sn);
      de = 0;

      m_stp();
      delay(800);
      clr_en(); ck_sn = ct_sen;
    }
  }


  if (p1 == '0' || cmd == fow )//
  { m_for();  ck_spd(); de++;
    /*  sprintf(test, " S1 =%d  S2=%d   spd_l %d   spd_r %d  %s|", sen[0], sen[2], spd_l, spd_r, dirt);
      Serial2.println(test);*/
    // Serial2.print(test); Serial2.print(" error" ); Serial2.print(error); Serial2.print(" dir "); Serial2.println(dir);

    if (sl > 116 && sr > 116 )
    {
      m_stp();


      clr_en(); p1 = ' '; de = 0;
      cmd = none;
      ck_sn = ct_sen;
    }
    ck_local();
  }
  else if (p1 == '2' || cmd == rgt) //2
  { m_rr();
    if (sl >= 73)
    {
      n = 1;
      m_stp();

      delay(800);
      //   Serial2.println(sl);
      //delay(1200);
      if (sl > 80 && sl <= 100)
      {
        mode2 = 1;
        n_sf = sl - 80;
      }
      else if ( sl <= 75 && sl > 63)
      {
        n_sf = 78 - sl;
        mode2 = 2;
      }
      else
      { mode2 = 0; clr_en();
        m_stp();
        delay(800);
      }

      clr_en();

      if (mode2 != 0)
      {
        while (1)
        {
          if (mode2 == 1)
          {
            m_rr_re();
            if (sl >= n_sf)
            {
              m_stp();
              delay(800);
              break;
            }
          }
          else if (mode2 == 2)
          {
            m_rr();
            if (sl >= n_sf)
            {
              m_stp();
              delay(800);
              break;
            }

          }
        }
        p1 = ' ';
        mode2 = 0;
      }

      if (mode2 == 0)
      {
        cmd = none; p1 = ' '; Serial2.println("R"); Serial.println("R"); digitalWrite(32, HIGH);
        delay(50);
        digitalWrite(32, LOW);
        clr_en();

ck_local();

      }
    }

  }
  else if (p1 == '1' || cmd == lef)
  {
    m_ll();
    if (sr >= 70)
    {
      n = 1;
      m_stp();

      delay(800);
      // Serial2.println(sr);
      if (sr > 82 && sr <= 100)
      {
        mode3 = 1;
        n_sf = sr - 82;
      }
      else if ( sr >= 64 && sr < 70)
      {
        n_sf = 70 - sr;
        mode3 = 2;
      }
      else
      {
        mode3 = 0; clr_en();
        m_stp();
        delay(800);
      }

      clr_en();


      if (mode3 != 0)
      {
        while (1)
        {
          if (mode3 == 1)
          {
            m_ll_re();
            if (sr >= n_sf)
            {
              m_stp();
              delay(800);
              break;
            }
          }
          else if (mode3 == 2)
          {
            m_ll();
            if (sr >= n_sf)
            {
              m_stp();
              delay(800);
              break;
            }

          }
        }
        mode3 = 0; clr_en(); p1 = ' ';
      }
      if (mode3 == 0)
      {
        cmd = none; Serial2.println("R"); Serial.println("R"); digitalWrite(32, HIGH);
        delay(50);
        digitalWrite(32, LOW);
        clr_en(); p1 = ' '; //spd_l = 165; spd_r = 230;
        n_reval = 1;
        ck_local();
      }
    }
  }
  else if (p1 == '3' || cmd == rtn)
  {
    m_r();// return
    if (sl > 68)
    {
      m1.setSpeed(0);
    }
    if (sr > 72)
    {
      m2.setSpeed(0);
    }
    if (sl > 70 && sr > 71)
    {
      m_stp();
      delay(800);


      if (sr > 90)
      { n_sf = sr - 84; clr_en();
        m_ll();
        while (sr < n_sf)
        {
          m_ll();
        } m_stp(); delay(500);
      }
      // Serial2.print(sl); Serial.print(" "); Serial2.println(sr);
      Serial2.println("R"); Serial.println("R"); digitalWrite(32, HIGH);
      delay(50);
      digitalWrite(32, LOW);
      cmd = none; clr_en(); p1 = ' ';
    //  spd_l = 214; spd_r = 230;
      n_reval = 1;ck_local();
    }
  }
  else if ( cmd == rtn2)
  {
    m_l();// return
    if (sl > 68)
    {
      m1.setSpeed(0);
    }
    if (sr > 72)
    {
      m2.setSpeed(0);
    }
    if (sl > 66 && sr > 69)
    {
      m_stp();
      delay(800);


      if (sl > 90)
      { n_sf = sl - 84;
        clr_en();
        while (sl < n_sf)
        { //Serial2.println("ee");
          m_rr();
        } m_stp(); delay(500);
      }
      // Serial2.print(sl); Serial.print(" "); Serial2.println(sr);
      Serial2.println("R"); Serial.println("R"); digitalWrite(32, HIGH);
      delay(50);
      digitalWrite(32, LOW);
      cmd = none; clr_en(); p1 = ' ';
      spd_l = 220; spd_r = 230; n_reval = 1;
    }
  }
  else if (p1 == '5' )
  {
    m_re(); Serial.println(sen[1]);
    if (sl > 15 && sr > 15)
    {
      m_stp();
      delay(800);
      clr_en(); p1 = ' ';
    }
  }




}

void m_for()
{
  m1.run(FORWARD);
  m2.run(FORWARD);
}
void m_re()
{ m1.setSpeed(199);
  m2.setSpeed(245);
  m1.run(BACKWARD);
  m2.run(BACKWARD);
}
void m_rr()
{
  m1.setSpeed(199);
  m2.setSpeed(245);
  m1.run(FORWARD);
  m2.run(RELEASE);

}
void m_rr_re()
{

  m1.run(BACKWARD);
  m2.run(RELEASE);

}
void m_r()
{
  m1.setSpeed(240);
  m2.setSpeed(255);
  m1.run(FORWARD);
  m2.run(BACKWARD);

}
void m_l()
{
  m1.setSpeed(230);
  m2.setSpeed(255);
  m2.run(FORWARD);
  m1.run(BACKWARD);

}
void m_ll()
{
  m1.setSpeed(199);
  m2.setSpeed(245);
  m2.run(FORWARD);
  m1.run(RELEASE);

}
void m_ll_re()
{

  m2.run(BACKWARD);
  m1.run(RELEASE);

}
void m_stp()
{
  m1.run(RELEASE);
  m2.run(RELEASE);
}
void en_l()
{
  sl++; sl_c++;
}
void en_r()
{ sr++; sr_c++;
}
void clr_en()
{
  sl = 0; sr = 0;
}
void clr_en_spd()
{
  sl_c = 0; sr_c = 0;
}
void ck_local()
{

  if (sen[0] > 0 && sen[0] < 8)
  {
    spd_l = 230; spd_r = 200;
  }
  else if (sen[2] > 0 && sen[2] < 8)
  {
    spd_l = 175; spd_r = 255;
  }
  else
  {
    spd_l = 193; spd_r = 245;
  }
}
void ck_spd()
{
  ti = millis() - ti_pre;
  if (ti >= 100)
  { ti_pre = millis();
    if (dirt == forw)
    { /*
        spd_l = 199;
        spd_r = 245;*/
      //  Serial.print("fowww  ");
      //Serial.println(test);
      //spd_r = 245;
      if (n_reval == 0)
      { spd_r = 245;
        spd_l = 194;
      }
      else if (n_reval >= 3)
      {
        n_reval = 0;
      }
      else
      {
        n_reval++;
      }
      if (sl_c > 12)
      {
        spd_l -= 4;
      }
      else if (sl_c < 10)
      {
        spd_l += 4;
      }
      limit_spd();
    }
    else if (dirt == right)
    { //Serial.print("rigt  ");
      n_reval = 0;
      spd_l += 6;
      spd_r = 210;
      limit_spd();
    }
    else if (dirt == right2)
    {
      n_reval = 0;
      spd_l += 3;
      spd_r = 228;
      limit_spd();
    }
    else if (dirt == left)
    { //Serial.print("left  ");
      n_reval = 0;
      spd_l = 170;
      spd_r += 6;
      limit_spd();
    }
    else if (dirt == left2)
    { //Serial.print("left  ");
      n_reval = 0;
      spd_l = 185;
      spd_r += 3;
      limit_spd();
    }

    m1.setSpeed(spd_l);
    m2.setSpeed(spd_r);
    clr_en_spd();
  }

}
void limit_spd()
{
  if (spd_l > 255)
  {
    spd_l = 255;
  }
  else if (spd_l < 140)
  {
    spd_l = 140;
  }
  if (spd_r > 255)
  {
    spd_r = 255;
  }
  else if (spd_r < 200)
  {
    spd_r = 200;
  }
}
void serialEvent2()
{
  while (Serial2.available())
  {
    p1 = Serial2.read();
  }
  if (p1 == 'S')
  {
    Serial.println("CMP!! ");
    Serial2.print("1,0,1,"); Serial2.println(white);
    p1 = ' ';
  }
  if (p1 == '3')
  {
    p1 = ' ';
    if (sen[0] > sen[2])
    {
      //  Serial2.println("111");
      cmd = rtn;
    }
    else
    { //Serial2.println("222");
      cmd = rtn2;
    }
  }
  digitalWrite(32, HIGH);
  delay(300);
  digitalWrite(32, LOW);

}
void serialEvent1()
{
  while (Serial1.available())
  { p = Serial1.read();

    if (p == ']')
    {
      Scut = 1;
    } else
    {
      data += p;
    }
  }

  if (Scut == 1)
  {

    Strcut();
    Scut = 2;
    con_step();
    Scut = 0; data = "";

  }

}
void Strcut()
{
  while (1)
  { int check = data.indexOf(',');


    if (check != -1)
    {

      sm[nn] = data.substring(0, check);
      data = data.substring(check + 1, data.length());

      nn++;
    }
    else
    {

      sm[nn] = data;
      mode = 1;
      nn = 0;

      break;
    }
  }
}
void con_step()
{

  sen[0] = sm[0].toInt();
  sen[1] = sm[1].toInt();
  sen[2] = sm[2].toInt();
  if (sen[0] > 45)
  {
    sd[0] = 0;
  }
  else
  {
    sd[0] = 1;
  }
  if (sen[1] > 37)
  {
    sd[1] = 0;
  }
  else
  {
    sd[1] = 1;
  }
  if (sen[2] >= 45)
  {
    sd[2] = 0;
  }
  else
  {
    sd[2] = 1;
  }
}
void serialEvent()
{
  while (Serial.available())
  {
    p = Serial.read();
  }
  if (p == '0')
  {
    //p1 = '0';
    p = ' ';
    cmd = fow;
  }
  if (p == '1')
  {
    //p1 = '1';
    p = ' ';
    cmd = lef;
  }
  if (p == '2')
  {
    //p1 = '2';
    p = ' ';
    cmd = rgt;
  }
  if (p == '3')
  {
    //  p1 = '3';
    p = ' ';
    cmd = rtn;
  }
  if (p == '4')
  {
    cmd = rtn2;
  }
  if (p == '5')
  {
    p = ' ';
    p1 = '5';
  }

}
                 
                 
                                 

Programming Design


การออกแบบโปรแกรมคอมพิวเตอร์ สำหรับควบคุมหุ่นยนต์ จะแบ่งออกเป็น 3 ส่วนหลัก คือ

  1. Explore Maze  ส่วนการรับข้อมูลจากหุ่นยนต์ว่ามีกำแพงที่ด้านซ้าย หน้า ขวา และสีกำแพง
  2. Recursive AI   ส่วนการเลือกเส้นทางที่ใกล้ที่สุดและไม่มีทางตันเพื่อหาทางออก แบบการเรียก Function ตัวเองซ้ำ
  3. Solution Maze  ส่วนการสั่งงานหุ่นยนต์ให้เดินไปตามเส้นทางที่ได้ solve
โดยโปรแกรมสามารถสั่งงานและ Simulation เพื่อจำลองการติดต่อสื่อสารระหว่างหุ่นยนต์กับคอมพิวเตอร์ที่ลงโปรแกรม Solve Maze ไว้ 
  
ดูได้ที่ https://www.youtube.com/watch?v=dkjcQIngzuA


Flowchart ของโปรแกรมควบคุมการทำงานของ  Robo Maze

                             

     โปรแกรมจะมีการสื่อสารกับคอมพิวเตอร์ผ่าน Bluetooth โดย ชุดคำสั่งที่คอมพิวเตอร์
ส่งมามีดังนี้ ถ้าส่ง "S"  Robo Maze  จะส่งค่าเซ็นเซอร์ที่ Ultrasonic อ่านค่ามาได้ไปยังคอมพิวเตอร์
                       ส่ง "0,1,2,3"  เป็นชุดคำสั่งในการควบคุมการเคลื่อนที่ของหุ่นยนต์  เช่น เดินหน้า ถอย
                                             หลัง เลี้ยวซ้าย เลี้ยวขวา แต่ถ้าหุ่ยนต์มีการเคลื่อนที่  เลี้ยวซ้าย เลี้ยวขวา                                                  และถอยหลัง เรียบร้อยแล้วจะส่ง  "R" กลับไปยังคอมพิวเตอร์

Mechanics Implementation

  1. ใช้มอเตอร์ที่มีขนาดเล็กและวางแผงจงจรซ้อนกันในแนวตั้ง
  2. ใช้สองล้อในการขับเคลื่อนตัวหุ่ยนต์
  3. ใช้ Arduino ในการพัฒนาโปรแกรมของหุ่นยนต์
  4. ติด Bluetooth เพื่อสื่อสารกับ PC
  5. ออกแบบ Protocol ในการสื่อสารระหว่างหุ่นยนต์และ PC
  6. ใช้ถ่านชาร์จขนาด AA และ Power Bank เป็นแหล่งจ่ายพลังงานให้หุ่นยนต์
  7. ติด Ultrasonic 3 ตัวเพื่อตรวจจัดระยะของหุ่นยนต์กับ Maze
  8. ติดกล้อง 1 ตัวไว้ด้านหน้าหุ่นยนต์เพื่อตรวจวัดสี

Electronics Design

  • แรงดันไฟฟ้าที่ใช้ใน Robo Maze  6V
  • สามารถวัดระยะทางในการเคลื่อนที่ของ Robo Maze ได้
  • สามารถตรวจสอบสีที่อยู่ตามกำแพงได้
  • สามารถสื่อสารกับ คอมพิวเตอร์ด้วยระบบไร้สาย
  • Robo Maze หลบสิ่งขีดขวาง และตรวจสอบเส้นทางได้
  • แสดงผลการทำงานของ Robo Maze 
  • Robo Maze  สามารถทำงานได้อัตโนมัติ

||| HOME |||


Maze Solving Robot



Objectives

Design

Implementation

Discussions

References

Discussions

ปัญหาที่พบในการทำ Robo Maze

  • กำลังมอเตอร์น้อยเกินไป ทำให้ไม่สามารถใช้ความเร็วรอบมอเตอร์ช่วงต่ำๆ เพราะไม่สามารถทำให้หุ่นยนต์เคลื่อนที่ได้ ถ้าใช้ความเร็วรอบที่สูงเกินไปทำให้ไม่สามารถควบคุมการวัดระยะการเคลื่อนที่ได้ทำให้ช่วงในการปรับเปลี่ยนความเร็วสั้นเกินไป
    • แก้ไขปัญหานี้โดยตั้งค่า อ้างอิงและทำการคำควณหาค่าความคลาดเคลื่อนและให้เคลื่อนกลับไป
  • เมื่อเราใช้ความเร็วรอบที่สูงจะทำให้เกิดการ Slip ของล้อได้ ทำให้การอ่าน Encoder ผิดเพี้ยนไป
    •  ใช้ Ultrasonic วัดระยะห่างของกำแพงและปรับเปลี่ยนความเร็วในการเคลื่อนที
  • พื้นสนามของเขาวงกตมีความลื่นมากเกินไปทำให้  Robo Maze เกิดข้อผิดพลาดในการเคลื่อนที่
    • ปรับแต่งล้อของ Robo Maze ลักษณะล้อให้สามารถเกาะพื้นสนามให้มากขึ้น  หรือเพิ่มแรงเสียดทานให้กับ Robo Maze
  • แหล่งจ่ายไฟไม่เพียงพอให้กับ Robo Maze ทำให้เกิดความคลาดเคลื่อนของเซ็นเซอร์ได้
    • เพิ่มแหล่งไฟให้กับ Robo Maze 

 ข้อเสนอแนะ

  • เลือกใช้มอเตอร์ที่มีกำลังและประสิทธิภาพมากกว่านี้ ควรทดสอบมอเตอร์ขณะที่มีโหลด และมีช่วงการปรับความเร็วกว้างพอสมควร

การต่อ OpenCM9.04-C ควบคุม Dynamixel XL 320
  • แนะนำให้ใช้แหล่งจ่าย 12 V ของเดิมใช้แหล่งจ่าย 6  V ไม่เพียงพอ ทำให้การอ่านค่าเซ็นเซอร์ผิด
  • ควรเลือกล้อที่มีหน้าสัมผัสกับพื้นสนามมากขึ้น  และวัสดุชิ้นงานควรเป็นยาง


Electronic Implementation

  วงจรไฟฟ้าที่ใช้ใน RoboMaze จะใช้ arduino  ทั้งหมด 2 ส่วนสามารถ แบ่งออกได้ดังนี้

          ส่วนของ arduino Master จะทำหน้าที่สื่อสารกันระหว่างคอมพิวเตอร์โดยใช้ Bluetooth  เป็นตัวกลางในการสื่อสาร และจะนำข้อูลเซ็นเซอร์จาก Ultrasonic ได้จาก Arduino Sensor โดยใช้ Uart Rx-Tx จะขับเคลื่อนมอเตอร์ได้ผ่าน Drive Motor boards Shields เพื่อควบคุมมอเตอร์ มี Encoder ในการวัดระยะทางในการเคลื่อนที่ของหุ่นยนต์




Arduino Master 


             ในส่วนต่อไปคือส่วนของ Arduino Sensor ใช้ในการรับข้อมูลต่างๆ ของเซ็นเซอร์เพื่อส่งไปยัง Arduino Master โดยจะตรวจจับ สิ่งกัดขวางที่อยู่ ด้านหน้า ด้านซ้าย ด้านขวา และตรวจจับสี จัดข้อมูลเป็นชุดและส่งไปยัง Arduino Master ผ่าน Uart Rx-Tx


Arduino Sensor

               อุปกรณ์ที่ใช้ในการตรวจจับสีของวัตถุของ Robo Maze นั้นจะใช้ Pixy CMUcam5  ในการตรวจจับสีของวัตถุและส่งข้อมูลไปยังบอรฺด arduino โดยเราสามารถสื่อสารได้หลายวิธีเช่น  UART Serial , SPI , I2C


                                                   ภาพการเชื่อมต่อ Pixy CMUcam5 กับ Arduino


รายละเอียดและข้อมูลของ Pixy CMUcam5 







ข้อมูลของขา Pin ต่างๆ ของ Pixy


วิธีการเชื่อมต่อ Pixy CMUcam5 กับ Arduino

  • ติดตั้วโปรแกรม PixyMon 

  • จากนั้นเชื่อมต่อ Pixy CMUcam5 เข้ากับคอมพิวเตอร์  และเปิดโปรแกรม PixyMonขึ้นมา
  • จากนนั้น เลือก File >> Configure…
    • Data out port (กำหนดพอร์ตสำหรับใช้ในการสื่อสาร) 
      •  output data. 0=SPI, 1=I2C, 2=UART, 3=analog/digital x, 4=analog/digital y
    • I2C address  
    • UART baudrate (ถ้าใช้ UART ตั้งค่าให้เหมือนกัน)
  • ตรวจสอบการเชื่อมต่อผ่าน arduino ได้โดยใช้ Pixy Arduino Library  ใน ตัวอย่างโค๊ตชื่อ Hello World ได้

ออกแบบภาคไฟฟ้าเรียบร้อยแล้ว


ติดตั้ง Bluetooth ใช้สื่อสารกับคอมพิวเตอร์



ติดตั้ง Pixy CMUcam5 



ติดตั้ง drive motor board shields กับ Arduino


ติดตั้ง Ultrasonic sensor



Mechanics Design

  1. หุ่นยนต์มีขนาดที่สามารถวิ่งใน Maze ได้
  2. หุ่นยนต์สามารถกลับตัวอยู่กับที่ได้
  3. หุ่นยนต์สามารถแก้ใขโปรแกรมการทำงานได้ง่าย
  4. หุ่นยนต์สื่อสารไร้สายกับ PC
  5. PC สามารถสั่งให้หุ่นยนต์ทำงาน (เดินหน้า, เลี้ยว, กลับหลัง) แล้วหุ่ยนต์ส่งข้อมูล Maze กลับไปให้ PC
  6. มีแหล่งพลังงานในตัวโดยไม่ต้องลากสายไฟ
  7. ตรวจวัดลักษณะของ Maze ได้
  8. ตรวจวัดสีของ Maze ได้