ตอนที่ 2 การเคลื่อนที่ในเขาวงกต
จากตอนที่ 1 การอ่าน Barcode มาสู่ตอนที่ 2 การเคลื่อนที่ในเขาวงกตโดยไม่มีเส้นกำกับ จะต้องมีอุปกรณ์อื่นๆ เข้ามาช่วย โดยในงานนี้ให้ใช้ โมดูลเข็มทิศ HMC5983
โมดูลเข็มทิศ HMC5983
โมดูลเข็มทิศดิจิตอล HMC5983 เป็นตัวตรวจจับสนามแม่เหล็กโลก จึงนำมาประยุกต์เป็นตัวตรวจจับทิศทางเพื่อช่วยกำหนดทิศทางการเคลื่อนที่ของหุ่นยนต์ได้ เหมาะกับพื้นที่สนามที่ไม่มีเส้นกำกับ
การติดตั้งโมดูล
จากรูปโครงสร้างทั้งหมดเป็นพลาสติก ไม่เกิดการรบกวนทำงานของเข็มทิศ และต้องติดตั้งให้สูงเหนือตัวหุ่นยนต์ขึ้นไป
การเชื่อมต่อ
โมดูลเข็มทิศ HMC5983 มีการสื่อสารด้วยระบบบัส I2C ประกอบด้วยขา SDA (ข้อรับส่งข้อมูล) SCL (ขาสัญญาณนาฬิกา) ซึ่งขาทั้งสองมีติดตั้งอยู่ที่บอร์ด IPST-SE เรียบร้อยแล้ว
ชุดคำสั่งสำหรับการติดต่อกับ HMC5983
เมื่อใช้งาน IPST-SE กับซอฟต์แวร์ Arduino เวอร์ชั่นล่าสุด จะสามารถใช้งานคำสั่งติดต่อกับเข็มทิศ HMC5983 ได้ทันที โดยมีคำสั่งที่ต้องใช้งานกับกิจกรรมนี้เพียงคำสั่งเดียวคือ
compass_read()
โดยฟังก์ชั่นนี้จะคืนค่า ทิศในช่วง 0-359 ออกมา
ตัวอย่างการอ่านค่าแสดงผลที่ glcd
setTextSize(2); glcdMode(1); glcd(2, 0, "%d ", compass_read());
การใช้งานเข็มทิศนั้น ก็เพื่อให้หุ่นยนต์เคลื่อนที่ตรงไปยังทิศทางที่ต้องการ และให้หุ่นยนต์หมุนตัวตรงไปยังทิศทางที่ต้องการ ดังนั้นก่อนการใช้งานโปรแกรม จำเป็นต้องสำรวจทิศ ของสนามก่อน โดยกำหนดเป็นตัวแปรขึ้นมาดังนี้
int N=50,E=122,S=168,W=300; โดยค่าเหล่านี้ ระบุทิศทั้ง 4 ที่เราเคลื่อนที่ โดยค่าจะไม่เป็นเชิงเส้นมากนัก และสำหรับค่าที่เกิดขึ้น อาจจะไม่เท่ากันทุกจุดในสนาม จะต้องมีการปรับจูน บวกลบค่าเพิ่มเติมจากค่าเหล่านี้ด้วย จากนั้น สร้างฟังกํชั่นเพื่อทำภารกิจต่างๆ
สำหรับฟังก์ชั่นที่เกี่ยวข้องกับการใช้งานเข็มทิศ ต้องยกเครดิตให้ ครูนัฎฐิกา หลอดแก้ว แห่งโรงเรียนบางปลาม้า “สูงสุมารผดุงวิทย์” ที่อนุเคราะห์รูปแบบการเขียนโค้ดที่ดูเข้าใจง่าย แต่ทำงานได้อย่างมีประสิทธิภาพ
ฟังก์ชั่นหมุนตัวไปจนกระทั่งถึงทิศที่ต้องการ
void rightUntil(int c) { while (compass_read()<c){sr(40);} }
void leftUntil(int c) { while (compass_read()>c){sl(40);} }
หลักการเขียนโปรแกรมง่ายๆ คือ ใช้ while ตรวจสอบเงื่อนไขการหมุนตัว โดยหมุนไปจนกระทั่งถึงทิศทางที่ต้องการ การหมุนจะต้องมีทั้งการหมุนทางซ้าย (leftUntil()) และหมุนทางขวา (rightUntil() ) เพื่อป้องกันการเคลื่อนที่ผ่านจุด 0 องศา ซึ่งจะทำให้การตรวจสอบทิศผิดพลาด
ตัวอย่าง
ปัจจุบันหุ่นยนต์อยู่ที่ตำแหน่ง 300 องศา(ทิศตะวันตก :W ) จะเคลื่อนที่ไปที่ตำแหน่ง 50 องศา (ทิศเหนือ : N) โดยปกติเราอาจจะเคลื่อนที่ทางขวา ช่วงเวลาสั้นๆ ได้ แต่ เพื่อไม่ให้ผ่านจุด 0 องศา เราจึงต้องใช้วิธีการเคลื่อนที่หมุนตัวทางซ้ายเพื่อไปที่ตำแหน่ง 50 องศาแทนโดยเขียนได้เป็น
leftUntil(50);
ฟังก์ชั่นเดินตรงไปตามทิศทางที่ต้องการ
สำหรับฟังก์ชั่นนี้ จะเดินตรงไปเรื่อย ๆจนกว่าจะชนกำแพงดังนั้นจะต้องติดตั้งสวิตช์ที่ด้านหน้าหุ่นยนต์ด้วยดังรูป โดยสวิตช์จะติดทั้งด้านหน้าและด้านหลัง เพื่อ ใช้ตรวจสอบทั้งการเดินหน้าและถอยหลัง
จากรูปสวิตช์ด้านหน้าต่อที่ขา 27 และสวิตช์ด้านหลังต่อที่ขา 30
void trackWallCompass(int c){ //แทร็กเข็มทิศ while(in(27)){ if(compass_read()<=c+2&&compass_read()>=c-2){fd(40); } else if (compass_read()<c+2){tr(40);} else if (compass_read()>c-2){tl(40);} }ao(); }
void trackWallBackCompass(int c) { while (in(30)) { if (compass_read()<=c+2&&compass_read()>=c-2){bk(40);} else if (compass_read()<c+2){bk2(0,40);} else if (compass_read()>c-2){bk2(40,0);} } ao(); }
การทำงานของโปรแกรมคือ ทำงานไปเรื่อยๆ จนเจอกำแพง โดยการอ่านค่าทิศทาง ถ้าค่าทิศทางอยู่ในช่วงผิดพลาดไม่เกิน +/- 2 องศาก็ให้หุ่นยนต์เดินตรงไป ถ้าเอียงไปด้านซ้ายก็ให้เลี้ยวซ้าย เอียงไปด้านขวาก็ให้เลี้ยวขวา
ฟังก์ชั่น เดินตรงด้วยเข็มทิศหยุดการเคลื่อนที่ด้วยเวลา
ฟังก์ชั่นนี้ใช้ในกรณีที่เดินตรงไป แล้วหยุดด้วยระยะทางที่กำหนด เนื่องจากเราไม่มี encoder ช่วยระบุเวลาที่กำหนดได้ จึงจำเป็นต้องใช้ ฟังก์ชั่น millis() ซึ่งเป็นค่าเวลาของระบบเข้ามาช่วย โดยฟังก์ชั่นนี้จะทำงานอยู่เบื้องหลังและให้ค่าเวลาส่งกลับมาให้เราตลอดเวลา ในหน่วยเป็นมิลลิวินาที ซึ่งนำค่านี้มาใช้จับเวลาการเคลื่อนที่ที่แม่นยำได้
void trackTimeCompass(int c,long t){ //แทร็กเข็มทิศด้วยเวลา long m=millis(); while(millis()<(m+t)){ if(compass_read()<=c+2&&compass_read()>=c-2){fd(40); } else if (compass_read()<c+2){tr(40);} else if (compass_read()>c-2){tl(40);} }ao(); }
void trackTimeBackCompass(int c,long t){ //แทร็กเข็มทิศ หยุดเมื่อหมดเวลา long m=millis(); while(millis()<(m+t)){ if(compass_read()<=c+2&&compass_read()>=c-2){bk(40); } else if (compass_read()<c+2){bk2(0,40);} else if (compass_read()>c-2){bk2(40,0);} }ao(); }
การทำงานของโปรแกรมจะเคลื่อนที่ตรงไปจนกว่าค่าเวลาจะมากกว่าค่าที่ตั้งไว้
จากฟังก์ชั่นทั้งหมดสามารถนำมาเขียนรูปแบบการเคลื่อนที่ในเขาวงกตได้ดังนี้
void MazeRight() { trackWallCompass(N); bk(30); delay(200); ao(); rightUntil(W); trackWallCompass(W); // ใข่ใบที่ 1 bk(30); delay(200); ao(); leftUntil(N); trackWallCompass(N); bk(30); delay(200); ao(); rightUntil(E); trackWallCompass(E); // ใข่ใบที่ 2 trackTimeBackCompass(E,2700); leftUntil(N+12); trackWallCompass(N+12); // ใข่ใบที่ 3 trackTimeBackCompass(N+12,900); rightUntil(E); trackTimeBackCompass(E,2300); leftUntil(N+12); trackWallCompass(N+12); // ใข่ใบที่ 4 trackWallBackCompass(N+12); fd(40);delay(200);ao(); rightUntil(E); trackWallBackCompass(E); fd(40);delay(200);ao(); leftUntil(N); trackWallBackCompass(N); trackTimeCompass(N,1500); rightUntil(E); trackTimeCompass(E,2000); rightUntil(S+15); trackWallCompass(S+15); bk(40); delay(250); ao(); rightUntil(W); trackWallCompass(W); // ใขใบที่ 5 bk(40); delay(250); ao(); leftUntil(S+19); trackTimeCompass(S+19,3000); bk(40); delay(250); ao(); }
void MazeLeft() { bk(30); delay(100); trackWallCompass(N); bk(30); delay(300); ao(); rightUntil(E); trackWallCompass(E); bk(30); delay(300); ao(); leftUntil(N); trackWallCompass(N); bk(30); delay(250); ao(); rightUntil(W); trackWallCompass(W); bk(30); delay(300); ao(); leftUntil(S); trackWallCompass(S); // ใข่ใบที่ 1 trackWallBackCompass(S); fd(30); delay(250); ao(); leftUntil(E); trackTimeCompass(E, 1000); leftUntil(N); trackWallCompass(N); bk(30); delay(150); ao(); rightUntil(W); trackWallCompass(W); bk(30); delay(100); ao(); leftUntil(N); trackWallCompass(N); // ใข่ใบที่ 2 trackWallBackCompass(N); fd(30); delay(250); ao(); rightUntil(E); trackWallCompass(E); bk(30); delay(100); ao(); leftUntil(N); trackWallCompass(N); bk(30); delay(150); ao(); rightUntil(E); trackWallCompass(E); // ใข่ใบที่ 3 trackTimeBackCompass(E, 1000); rightUntil(S); trackWallCompass(S); bk(30); delay(150); ao(); rightUntil(W); trackWallCompass(W); // ใข่ใบที่ 4 bk(30); delay(1000); ao(); trackTimeBackCompass(W, 1000); leftUntil(S); trackWallCompass(S); bk(30); delay(1000); ao(); // ใข่ใบที่ 5 leftUntil(E); trackWallCompass(E); bk(30); delay(100); ao(); rightUntil(S); trackTimeCompass(S, 3000); LLL(); ao(); }