最近文章

Arduino筆記(二十一):電子羅盤 GY-273 / HMC5883L透過vPython 呈現立體圖

[2017/04/10]
最近在研究 Arduino 讀取電子羅盤 GY-273 / HMC5883L的座標,將讀取的座標顯示在Console上,只要使用Serial.print()就可以簡單做到,可是如果要呈現一個 3D的圖像,經由 GY-273座標值的改變,讓畫面上的3D圖樣也跟著轉動。在Arduino 的環境下,我不確定圖形介面的Scratch for Arduino (簡稱S4A)是否可以完成?

先前寫過一篇:「Arduino筆記(十三):使用Firmata 協定,Arduino 也可以執行 Python」,如果將 Arduino測得的資料,透過 PyMata 及 Python 的3D 函式庫,將結果呈現在螢幕上,應該是一個很不錯的想法。

另一個作法是將Arduino 測得的資料,透過 Serial Port單向傳給 Python,再由 Python根據接收的資料,改變圖形的形狀或角度。

在搜尋Python 繪圖庫的文件時,找到一個很容易就可以畫出3D圖形的程式: VPython,我試著用 Python 接收來自 Serial Port 的資料,結合座標軸,畫出立體的影像。以下就是在 Vpython畫出一個地球的畫面。


[vPython]

Vpython 是 Python 的一個套裝軟體,可以在螢幕上呈現出 3D 的圖形,包括球形體、長方體、彈簧、金字塔體、箭號等形狀,所有的圖形都以 3 維座標表示,並以向量控制位置或方向。
如有興趣可到以下 vPython 的文件網站,查詢相關指令:

網址是:http://vpython.org/contents/docs/

[pySerial]

pyserial程式的功能,是要讓 Python 程式透過 Serial Port (RS232) 來進行通訊傳輸。傳輸前需進行速率()設定程式下載位置及相關文件,可參考 pyserial 的網站:

網址是:https://pypi.python.org/pypi/pyserial/2.7

[材料]

• Arduino Nano  x 1
• GY-273 / HMC5883L   x1
• 連接線 x 4條

[接線圖]

•GY-273 / HMC5883L 電子羅盤模組連接線路
GY-273 / HMC5883L模組
Arduino
1 - VCC
VCC
2 - GND
GND
3 - SCL
Pin A5
4 - SDA
Pin A4
5- DRDY
-


[Arduino程式一]

以下是修改自Korneliusz Jarzebski的程式,產生一列X,Y,Z座標的數字,以逗號隔開。

#include <Wire.h>
#include <HMC5883L.h>

HMC5883L compass;

void setup()
{
  Serial.begin(38400);

  // Initialize HMC5883L
  while (!compass.begin())
  {
    delay(500);
  }
  
  // +/- 1.30 Ga: HMC5883L_RANGE_1_3GA (default)
  compass.setRange(HMC5883L_RANGE_1_3GA);

  // Set measurement mode
  // Continuous-Measurement: HMC5883L_CONTINOUS (default)
  compass.setMeasurementMode(HMC5883L_CONTINOUS);
 
  // Set data rate
  // 15.00Hz: HMC5883L_DATARATE_15HZ (default)
  compass.setDataRate(HMC5883L_DATARATE_15HZ);

  // Set number of samples averaged
  // 1 sample:  HMC5883L_SAMPLES_1 (default)
  compass.setSamples(HMC5883L_SAMPLES_1);
}


void loop()
{
  Vector raw = compass.readRaw();
  Vector norm = compass.readNormalize();

//  Serial.print(" Xraw = ");
//  Serial.print(raw.XAxis);
//  Serial.print(", ");
//  Serial.print(raw.YAxis);
//  Serial.print(", ");
//  Serial.println(raw.ZAxis);
//  Serial.print(" Xnorm = ");
  Serial.print(norm.XAxis);
  Serial.print(", ");
  Serial.print(norm.YAxis);
  Serial.print(", ");
  Serial.print(norm.ZAxis);
  Serial.println();  

  delay(100);
}

[Arduino程式二]

以下是修改自 Henry's Bench的 HMC5883 Arduino 程式,使用I2C讀取 HMC5883的暫存器,再利用位移的方式計算X,Y,Z座標的值。

#include <Wire.h>:        //I2C Arduino Library
#define addr 0x1E         //I2C Address for The HMC5883

void setup(){
  
  Serial.begin(38400);
  Wire.begin();
 
  Wire.beginTransmission(addr); //start talking
  Wire.write(0x02);             // Set the Register
  Wire.write(0x00);             // Tell the HMC5883 to Continuously Measure
  Wire.endTransmission();
}

void loop(){
  
  int x,y,z;      //triple axis data

  //Tell the HMC what regist to begin writing data into
  Wire.beginTransmission(addr);
  Wire.write(0x03);       //start with register 3.
  Wire.endTransmission();
 
  //Read the data.. 2 bytes for each axis.. 6 total bytes
  Wire.requestFrom(addr, 6);

  if(6 <= Wire.available()){
  
    x = Wire.read() <<8;    //MSB  x 
    x |= Wire.read();      //LSB  x
    z = Wire.read() <<8;   //MSB  z
    z |= Wire.read();      //LSB z
    y = Wire.read() <<8;   //MSB y
    y |= Wire.read();      //LSB y
  }
  
  // Show Values
  Serial.print(x);
  Serial.print(", ");
  Serial.print(y);
  Serial.print(", ");
  Serial.println(z);
  
  delay(10);
}   


打開Serial串列的視窗,已經可以看到座標值,如上圖。

接下來要在電腦端安裝 Python所需的軟體,包括 Serial 跟 vPython兩種。 vPython 分成32跟64位元兩種,且分為Python 2.7 跟3.2兩個版本,安裝時要對應 Python 安裝的版本,否則會產生錯誤。我是採用比較傳統的作法,安裝 Python 2.7.13 版,vPython安裝2.7-6.11,執行時沒有發生問題。以下是軟體取得的位址與安裝方式(略) :

(1) 下載安裝 Python 2.7.x 版 32位元程式 (目前最新是2.7.13) 。 下載後執行接著按「下一步」即可完成安裝。

(2) 下載安裝 PySerial 2.7 版 。下載後執行接著按「下一步」即可完成安裝。

(3) 下載安裝 VPython-Win-32-Py2.7-6.11 。下載後執行,會詢問Python 2.7的目錄,接著按「下一步」即可完成安裝。

完成上述安裝後,開啟「VIDLE for python」視覺化的開發環境(Python's Integrated DeveLopment Environment),輸入以下程式,按「F5」(Run Module)或是從視窗選單「Run」➔ 「Run Module」。

• 以下是Python 程式:

import serial         #import serial library
from visual import *  #import vPython library

scene2 = display(title='Examples of HMC5883L Triple Axis Digital Compass', x=0, y=0, width=600, height=600, center=(5,0,0), background=(0,0,0))
scene2.fullscreen = True

Earth = sphere(raduis = 100, material = materials.earth)      # print Earth
PosLabel = label(text='Position is: ', box=false, height=15)  # print position

sensorData= serial.Serial('com4',38400)    # Get data from serial port

while True:
    rate(50)    # Delay
    if (sensorData.inWaiting()>0):     

        textline = sensorData.readline()
        str2 = 'Position is: ' + textline
        Pos = textline.split(',')     

        xPos = float(Pos[0]) /100   
        yPos = float(Pos[1]) /100       
        zPos = float(Pos[2]) /100         
 
        Earth.pos = vector(xPos, yPos, zPos)
        PosLabel.text= str2


程式中有幾個要注意的地方:
•  我的 Arduino Serial 通訊埠是 COM4,如果不同時,記得要修改。
•  傳輸速率 38400 是我試過比較剛好的,在畫面上顯示3D的圖時,不會因畫面顯示來不及,而造成資料在背景儲存多筆在緩衝區。
•  xPos、yPos及zPos各除以100,是因為該數字常超過座標的值,造成程式錯誤中斷,除以100,可套用於目前座標中。

[執行結果]

看到一個地球及座標的畫面,會隨著HCM5883L的轉動而改變位置。

video

[後記]

在執行 Python 的過程中,使用 vPython 的 函數 sphere 畫一個地球,只要一行指令即可。但執行的過程中,都沒有改變地球的半徑 raduis 的值,可是在畫面上的地球,會忽大忽小的改變,一直讓我找不出原因。其次是地球只是在座標平移,而非真的做到 3D 的旋轉。還有座標的位置,我也常無法有效的控制物件所在位置,這些小地方還不熟悉,後續還有很大的努力空間。下次有些研究的心得再跟各位分享。

[參考資料]

• Henry's Bench:Arduino GY-273 HMC5883L Magnetometer Compass Tutorial
• github:jarzebski/Arduino-HMC5883L
• Palma Quarter:Using Python with Arduino

沒有留言