[UNICON] [CMPS10] Compass Sensor with UNICON

รู้ทิศและความเอียงด้วย CMPS10 โมดูลเข็มทิศอิเล็กทรอนิกส์

<อ้างอิงจากวารสาร The Prototype Electronics ฉบับที่ 40>

 

รูปหัวเรื่อง

 

เบื้องต้นกับ CMPS10

 

        CMPS10 เป็นโมดูลเข็มทิศและวัดความเอียงผลงานของ Devantech ภายในตัวโมดูลประกอบไปด้วยตัวตรวจจับแม่เหล็กขั้วโลก 3 แกนกับตัวตรวจจับความเร่ง 3 แกนที่ทำงานร่วมกับชิปประมวลผลขนาด 16 บิต เพื่อวัดทิศทางได้ว่า โมดูลหันไปในทิศใด รวมถึงวัดความเอียงได้ด้วย

รูปที่ 1หน้าตา, การจัดขา และการกำหนดทิศอ้างอิงของโมดูลเข็มทิศ CMPS10

        โมดูล CMPS10 มีหน้าตา, การจัดขา และการกำหนดทิศทางหลักจากผู้ผลิตแสดงในรูปข้างบนโดยตำแหน่งดังกล่าวจะอ้างอิงกับขั้วของแม่เหล็กโลกหรือเป็นทิศเหนือ อย่างไรก็ตาม ผู้ใช้งานสามารถกำหนดทิศอ้างอิงใหม่ได้ โดยไม่จำเป็นต้องเป็นทิศเหนือเสมอไป ด้วยกระบวนการทางซอฟต์แวร์และขั้นตอนทางฮาร์ดแวร์เล็กน้อย

 

รูปที่ 2ที่มาของค่าที่อ่านได้จากโมดูลเข็มทิศ 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 ตัว ดังแสดงในตาราง

ตารางที่ 1  ตารางรายละเอียดของรีจิสเตอร์ทั้งหมดของโมดูลเข็มทิศ 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

 

UniconProject04-fig19_CO-[Converted]วงจรเชื่อมต่อเพื่อใช้งานโมดูลเข็มทิศ 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 สามารถวัดความเอียงได้ด้วย

UniconProject04-fig20-[Converted] รูปแสดงค่ามุมของทิศ (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

 

UniconProject04-fig21_CO-[Converted]การปรับแต่งทิศอ้างอิงของโมดูล 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);
}

 

 

Facebook Comments