รู้ทิศและความเอียงด้วย CMPS10 โมดูลเข็มทิศอิเล็กทรอนิกส์
<อ้างอิงจากวารสาร The Prototype Electronics ฉบับที่ 40>
เบื้องต้นกับ CMPS10
CMPS10 เป็นโมดูลเข็มทิศและวัดความเอียงผลงานของ Devantech ภายในตัวโมดูลประกอบไปด้วยตัวตรวจจับแม่เหล็กขั้วโลก 3 แกนกับตัวตรวจจับความเร่ง 3 แกนที่ทำงานร่วมกับชิปประมวลผลขนาด 16 บิต เพื่อวัดทิศทางได้ว่า โมดูลหันไปในทิศใด รวมถึงวัดความเอียงได้ด้วย
หน้าตา, การจัดขา และการกำหนดทิศอ้างอิงของโมดูลเข็มทิศ CMPS10
โมดูล CMPS10 มีหน้าตา, การจัดขา และการกำหนดทิศทางหลักจากผู้ผลิตแสดงในรูปข้างบนโดยตำแหน่งดังกล่าวจะอ้างอิงกับขั้วของแม่เหล็กโลกหรือเป็นทิศเหนือ อย่างไรก็ตาม ผู้ใช้งานสามารถกำหนดทิศอ้างอิงใหม่ได้ โดยไม่จำเป็นต้องเป็นทิศเหนือเสมอไป ด้วยกระบวนการทางซอฟต์แวร์และขั้นตอนทางฮาร์ดแวร์เล็กน้อย
ที่มาของค่าที่อ่านได้จากโมดูลเข็มทิศ CMPS10
CMPS10 ใช้ไฟเลี้ยงในช่วง +3.6 ถึง +5V การเชื่อมต่อกับ CMPS10 ทำได้ 3 วิธีคือ โหมดบัส I2C, โหมดอนุกรมหรือ Serial และโหมด PWM ค่าที่ได้เลือกได้ทั้งแบบ Bearing, Pitch และ Roll โดย Bearing เป็นค่าทิศทางรอบตัวในแนวแกนนอน มีค่าระหว่าง 0 ถึง 359.9 องศา ส่วน Pitch เป็นมุมยกมีค่าระหว่าง -85 ถึง 85 องศาเทียบกับแนวระนาบ และ Roll เป็นมุมเอียงมีค่าระหว่าง -85 ถึง 85 องศาเทียบกับแนวระนาบ ดูรูปที่ 2 ประกอบ
การติดต่อในโหมดบัส I2C
ในมินิโปรเจ็กต์นี้เลือกติดต่อกับโมดูล CMPS10 ผ่านทางบัส I2C เนื่องจากช่วยลดจำนวนพอร์ตที่ใช้งานได้ เพราะด้วยการใช้บัส I2C ผู้ใช้งานสามารถต่อพ่วงขาพอร์ต SDA และ SCL ของบอร์ด Unicon เพียง 2 ขากับตัวตรวจจับที่ใช้บัส I2C ได้หลายตัวร่วมบนบัสเดียวกัน นอกจากนั้น จากการทดสอบพบว่า การติดต่อกับโมดูล CMPS10 ในโหมดบัส I2C สะดวกกว่าแบบอนุกรมและแบบ PWM Mode
สำหรับ CMPS10 มีแอดเดรสสำหรับเชื่อมต่อผ่านระบบบัส I2C อยู่ที่ 0x60 มีรีจิสเตอร์เก็บค่าต่างๆ รวม 22 ตัว ดังแสดงในตาราง
ตารางรายละเอียดของรีจิสเตอร์ทั้งหมดของโมดูลเข็มทิศ CMPS10
หากส่งข้อมูลคำสั่งเป็น 0x00 จะเป็นการอ่านค่าเวอร์ชันเฟิร์มแวร์ของโมดูล CMPS10
หากส่งข้อมูลคำสั่งเป็น 0x02 จะเป็นการอ่านข้อมูล โดย CMPS10 จะส่งข้อมูลกลับมา 4 ไบต์ ไบต์แรกเป็นไบต์สูงของค่ามุมทิศ (bearing), ไบต์ที่สองเป็นไบต์ต่ำของค่ามุมทิศ, ไบต์ที่สามจะเป็นค่ามุมยก (pitch) และไบต์สุดท้ายจะเป็นค่ามุมเอียง (roll) โดยค่ามุมทิศที่อ่านได้มีค่าระหว่าง 0 ถึง 3599 (16 บิต) จึงต้องหารด้วย 10 เพื่อให้ได้ค่ามุมทิศที่มีค่าระหว่าง 0 ถึง 359.9 องศา
การต่อวงจรเพื่อใช้งานกับบอร์ด Unicon
เตรียมอุปกรณ์โดยจะมีสาย JST3AC-8 จำนวน 2 เส้นต่อระหว่างบอร์ด Unicon และโมดูล CMPS10 โดยปลายสายด้านหัวต่อ IDC ตัวเมียของสาย JST3AC-8 เส้นที่ 1 ต่อกับคอนเน็กเตอร์ของ CMPS10 ที่ขาไฟเลี้ยง (+V), กราวด์ (GND) และ SDA ส่วนเส้นที่ 2 ให้ต่อสายสัญญาณ (สีขาว เส้นกลาง) กับขา SCL ส่วนหัวต่อ IDC ตัวเมียของสายสีแดงและดำที่เหลือให้ปล่อยลอยไว้ ส่วนปลายสายด้านที่เป็นหัวต่อ JST ให้นำไปเสียบจุดต่อพอร์ต SDA และ SCL บนบอร์ด Unicon
อุปกรณ์ทั้งหมดที่ต้องใช้ในการใช้งานโมดูลเข็มทิศ CMPS10 กับบอร์ด Unicon
วงจรเชื่อมต่อเพื่อใช้งานโมดูลเข็มทิศ CMPS10 กับบอร์ด Unicon
หากต้องการติดตั้งโมดูลเข็มทิศ CMPS10 เข้ากับแท่นหรือฐานยึดใดๆ จะต้องใช้สกรูและนอตพลาสติกในการติดตั้งเพื่อลดผลกระทบจากโลหะที่อาจมีต่อการตรวจจับแม่เหล็กขั้วโลกของตัวตรวจจับภายใน CMPS10 (ในชุดอุปกรณ์ของ CMPS10 มีเตรียมไว้ให้แล้ว – ดูได้จากรูปข้างบน)
โปรแกรมอ่านค่าจากโมดูลเข็มทิศ CMPS10 ของบอร์ด Unicon
/***************************************************** * * TITLE : COMPASS AND TILT * CATAGORIES : I2C * CREATED DATE : DECEMBER 6, 2013 * AUTHOR : INNOVATIVE EXPERIMENT CO., LTD. (INEX) * WEBSITE : HTTP://WWW.INEX.CO.TH * DESCRIPTION : Get direction of geography and tilt * on BMPS10 with I2C interface * then show value on GLCD * โปรแกรมอ่านค่าเข็มทิศและความเอียง * จากโมดุล CMPS10 ผ่านระบบบัส I2C * โดยจะนำค่าที่วัดได้มาแสดงบน GLCD * ******************************************************/ #include <unicon.h> // Register address for CMPS10 #define ADDRESS 0x60 // highByte and lowByte store high // and low bytes of the bearing // and fine stores decimal place of bearing byte highByte, lowByte, fine; // Stores pitch and roll values of CMPS10, // chars are used because they support signed value char pitch, roll; // Stores full bearing int bearing; void setup() { // Initiate I2C Wire.begin(); } void loop() { // Get data from CMPS10 measurement(); // Pressed OK for calibration if(sw_ok()) { calibrate(); } // Show bearing, pitch and roll display_data(); // Delay time 50 millisecond delay(50); } // Get bearing, pitch and roll data void measurement() { //starts communication with CMPS10 Wire.beginTransmission(ADDRESS); Wire.write(2); Wire.endTransmission(); // Request 4 bytes from CMPS10 Wire.requestFrom(ADDRESS, 4); // Wait for bytes to become available while(Wire.available() < 4); // Get high byte of bearing highByte = Wire.read(); // Get low byte of bearing lowByte = Wire.read(); // Get pitch pitch = Wire.read(); // Get roll roll = Wire.read(); // Calculate full bearing bearing = ((highByte << 8) + lowByte) / 10; // Calculate decimal place of bearing fine = ((highByte << 8) + lowByte) % 10; } // Show data on GLCD void display_data(){ glcd(0, 0, "CMPS10 V:%d ", soft_ver()); glcd(1, 0, "Bearing=%d.%d ", bearing, fine); glcd(2, 0, "Pitch=%d ", pitch); glcd(3, 0, "Roll=%d ", roll); } // Calibrating CMPS10 by pressed OK button void calibrate() { glcdClear(); glcd(0, 0, "Calibrate Start"); glcd(1, 0, "Turn module to north."); sleep(500); sw_ok_press(); writeCalibrateData(); glcd(1, 0, "Turn module to east. "); sw_ok_press(); writeCalibrateData(); glcd(1, 0, "Turn module to south."); sw_ok_press(); writeCalibrateData(); glcd(1, 0, "Turn module to west. "); sw_ok_press(); writeCalibrateData(); glcd(1, 0, "Calibration complete"); sleep(1000); glcdClear(); } void writeCalibrateData() { // Begin I2C transmission with CMPS10 address Wire.beginTransmission(ADDRESS); // Send register address Wire.write(0x22); // Send data 0xF5 to address 0x022 Wire.write(0xF5); // End I2C trasmission Wire.endTransmission(); } // Get software version int soft_ver() { // Software version of CMPS10 is read into data and then returned int data; //starts communication with CMPS10 Wire.beginTransmission(ADDRESS); // Sends the register we wish to start reading from // Note : Values of 0 being sent with write need to be // masked as a byte so they are not misinterpreted as NULL // this is a bug in arduino 1.0 Wire.write((byte)0); Wire.endTransmission(); // Request byte from CMPS10 Wire.requestFrom(ADDRESS, 1); // Wait for bytes to become available while(Wire.available() < 1); // Get software version data = Wire.read(); // Return software version return(data); }
เขียนโค้ด
โค้ดตัวอย่างสำหรับอ่านค่าของโมดูลเข็มทิศ CMPS10 จะนำค่าที่ได้มาแสดงผลที่จอ GLCD-XT ที่ติดตั้งบนบอร์ด Unicon
ฟังก์ชั่นหลักๆ ของโปรแกรมมี 3 ตัวคือ measurement();, display_data(); และ calibration(); โดยฟังก์ชั่นแรกเป็นฟังก์ชั่นติดต่อเพื่ออ่านค่าจาก CMPS10 ผ่านรูปแบบการสื่อสารข้อมูลระบบบัส I2C ค่าที่ได้มี 3 ค่าคือ bearing, pitch และ roll จากนั้นนำค่าทั้งหมดมาแสดงผลที่ GLCD-XT ด้วยฟังก์ชั่น display_data();
ส่วนฟังก์ชั่น calibrate(); ใช้ปรับเทียบทิศอ้างอิงให้แก่โมดูล CMPS10 โดยทำการเขียนค่า 0xF0 ไปยังรีจิสเตอร์ 22 ของโมดูล CMPS10 เพื่อเริ่มต้นการปรับเทียบ จากนั้นเมื่อกำหนดทิศอ้างอิงเริ่มต้นได้ ให้เขียนข้อมูล 0xF5 ไปยังรีจิส
เตอร์ 22 ของโมดูล CMPS10 โดยในการเขียนแต่ละครั้งจะเกิดขึ้นเมื่อมีการกดสวิตช์ที่ต่อกับขาพอร์ต 30 ในการปรับแต่งต้องทำทั้งสิ้น 4 ครั้งตามทิศหลัก แต่ละทิศจะมีมุมต่างกัน 90 องศา
ทดสอบวัดทิศทาง
หลังจากอัปโหลดโปรแกรมไปยังบอร์ด Unicon ระบบจะทำงานทันที Unicon จะติดต่อกับโมดูล CMPS10 เพื่ออ่านค่าและแสดงผล หากไม่มีการกำหนดทิศทางอ้างอิงเป็นอย่างอื่น ตำแหน่ง 0 องศาจะหมายถึง ทิศเหนือ ซึ่งจะอ้างอิงกับขั้วแม่เหล็กโลก
หากมีการหมุนหรือบิดตัวโมดูลไปมา ค่าของมุมยก (pitch) และมุมเอียง (roll) จะเปลี่ยนแปลง เป็นการแสดงให้เห็นว่าโมดูล CMPS10 สามารถวัดความเอียงได้ด้วย
รูปแสดงค่ามุมของทิศ (Bearing), มุมยก (Pitch) และมุมเอียง (Roll) ผ่านทางบอร์ด Unicon
การปรับแต่งทิศอ้างอิง
อย่างไรก็ตาม ในการใช้งานจริง ควรมีการปรับแต่งทิศอ้างอิงให้ถูกต้องเพื่อขจัดหรือลดผลจากสนามแม่เหล็กที่อาจค่างอยู่ภายในตัวตรวจจับสนามแม่เหล็กของโมดูล CMPS10 มีขั้นตอนโดยสรุปดังนี้
(1) เริ่มต้นด้วยการกดสวิตช์ที่ต่อกับพอร์ต 30 เพื่อเข้าสู่โหมดปรับทิศอ้างอิง จอแสดงผล GLCD-XT แสดงข้อความ Calibrate Start ตามด้วยข้อความ Turn module to North. ทำการหมุนตัวโมดูล CMPS10 ไปยังทิศที่กำหนดให้เป็นทิศเหนือ (อาจเป็นทิศเหนือจริงๆ หรือทิศใดๆ ที่ต้องการอ้างอิงก็ได้) แล้วกดสวิตช์ที่ต่อกับพอร์ต 30 เพื่อกำหนดทิศอ้างอิงครั้งที่ 1 จะเห็น LED ที่โมดูล CMPS10 ติดสว่าง
(2) ที่จอแสดงผล GLCD-XT แสดงข้อความ Turn module to East. หมุนตัวโมดูล CMPS10 ไปทางขวาในทิศทางตามเข็มนาฬิกา 90 องศา แล้วกดสวิตช์ครั้งที่ 2 อันการกำหนดทิศตะวันออก
(3) จอแสดงผล GLCD-XT แสดงข้อความ Turn module to South. หมุนตัวโมดูล CMPS10 ไปทางขวาในทิศทางตามเข็มนาฬิกาไปอีก 90 องศา แล้วกดสวิตช์ครั้งที่ 3 เพื่อกำหนดเป็นทิศใต้
(4) จอแสดงผล GLCD-XT แสดงข้อความ Turn module to West. จากนั้นหมุนโมดูลไปทางขวาในทิศทางตามเข็มนาฬิกาอีก 90 องศา แล้วกดสวิตช์ครั้งที่ 4 เป็นครั้งสุดท้าย LED ของโมดูล CMPS10 จะดับลง เป็นอันสิ้นสุดการปรับแต่งทิศอ้างอิงของโมดูล CMPS10
การปรับแต่งทิศอ้างอิงของโมดูล CMPS10
แก้โค้ดลดอุปกรณ์
จากโปรแกรมตัวอย่างสามารถนำไปใช้กับบอร์ด Arduino ได้ทุกแบบ โดยอาจแก้โค้ดเพื่อเปลี่ยนอุปกรณ์แสดงผลเป็นโมดูล LCD 16 ตัวอักษร 2 บรรทัด หรือ LED รวมถึงแสดงผ่าน Serial Monitor ของ Arduino IDE สำหรับผู้ใช้งานบอร์ด Unicon และใช้การแสดงผลผ่านจอ GLCD-XT สามารถใช้สวิตช์ OK ในการเข้าสู่โหมดปรับเทียบทิศอ้างอิงแทนการใช้สวิตช์ภายนอกได้
โปรแกรมสำหรับอ่านค่าจากโมดูลเข็มทิศ CMPS10 ของบอร์ด Unicon และใช้สวิตช์ OK บนบอร์ดแสดงผล GLCD-XT ในการปรับแต่งทิศอ้างอิง
/***************************************************** * * TITLE : COMPASS AND TILT * CATAGORIES : I2C * CREATED DATE : DECEMBER 6, 2013 * AUTHOR : INNOVATIVE EXPERIMENT CO., LTD. (INEX) * WEBSITE : HTTP://WWW.INEX.CO.TH * DESCRIPTION : Get direction of geography and tilt * on BMPS10 with I2C interface * then show value on GLCD * โปรแกรมอ่านค่าเข็มทิศและความเอียง * จากโมดุล CMPS10 ผ่านระบบบัส I2C * โดยจะนำค่าที่วัดได้มาแสดงบน GLCD * ******************************************************/ #include "unicon.h" // Register address for CMPS10 #define ADDRESS 0x60 // highByte and lowByte store high // and low bytes of the bearing // and fine stores decimal place of bearing byte highByte, lowByte, fine; // Stores pitch and roll values of CMPS10, // chars are used because they support signed value char pitch, roll; // Stores full bearing int bearing; void setup() { //Delay 1 second sleep(1000); // Clear GLCD screen glcdClear(); // Initiate I2C Wire.begin(); } void loop() { // Get data from CMPS10 measurement(); // Pressed OK for calibration if(sw_ok()) { calibrate(); } // Show bearing, pitch and roll display_data(); // Delay time 50 millisecond delay(50); } // Get bearing, pitch and roll data void measurement() { //starts communication with CMPS10 Wire.beginTransmission(ADDRESS); Wire.write(2); Wire.endTransmission(); // Request 4 bytes from CMPS10 Wire.requestFrom(ADDRESS, 4); // Wait for bytes to become available while(Wire.available() < 4); // Get high byte of bearing highByte = Wire.read(); // Get low byte of bearing lowByte = Wire.read(); // Get pitch pitch = Wire.read(); // Get roll roll = Wire.read(); // Calculate full bearing bearing = ((highByte << 8) + lowByte) / 10; // Calculate decimal place of bearing fine = ((highByte << 8) + lowByte) % 10; } // Show data on GLCD void display_data() { glcd(0, 0, "CMPS10 V:%d ", soft_ver()); glcd(1, 0, "Bearing=%d.%d ", bearing, fine); glcd(2, 0, "Pitch=%d ", pitch); glcd(3, 0, "Roll=%d ", roll); } // Calibrating CMPS10 by pressed OK button void calibrate() { // Show calibration message on GLCD glcdClear(); glcd(0, 0, "Calibrate Start"); // Send data 0xF0 to starting calibration writeCalibrateData(0xF0); // Delay 500 milliseconds sleep(500); // Show message to turn module to north glcd(1, 0, "Turn module to North."); // Wait for pressed OK button sw_ok_press(); // Send data 0xF5 to set north writeCalibrateData(0xF5); // Show message to turn module to east glcd(1, 0, "Turn module to East. "); // Wait for pressed OK button sw_ok_press(); // Send data 0xF5 to set east writeCalibrateData(0xF5); // Send data 0xF5 to set South glcd(1, 0, "Turn module to south."); // Wait for pressed OK button sw_ok_press(); // Send data 0xF5 to set east writeCalibrateData(0xF5); // Show message to turn module to west glcd(1, 0, "Turn module to West. "); // Wait for pressed OK button sw_ok_press(); // Send data 0xF5 to set west writeCalibrateData(0xF5); // Show calibration finishing on GLCD glcd(1, 0, "Calibration complete"); // Delay 1 second sleep(1000); // Clear GLCD screen glcdClear(); } void writeCalibrateData(int data) { // Begin I2C transmission with CMPS10 address Wire.beginTransmission(ADDRESS); // Send register address Wire.write(22); // Send data to address 0x022 Wire.write(data); // End I2C trasmission Wire.endTransmission(); } // Get software version int soft_ver() { // Software version of CMPS10 is read into data and then returned int data; //starts communication with CMPS10 Wire.beginTransmission(ADDRESS); // Sends the register we wish to start reading from // Note : Values of 0 being sent with write need to be // masked as a byte so they are not misinterpreted as NULL // this is a bug in arduino 1.0 Wire.write((byte)0); Wire.endTransmission(); // Request byte from CMPS10 Wire.requestFrom(ADDRESS, 1); // Wait for bytes to become available while(Wire.available() < 1); // Get software version data = Wire.read(); // Return software version return(data); }