HMC5883L - FabLabSeoul/WingProject GitHub Wiki
HMC5883L์ HoneyWell ์ฌ๊ฐ ๋ง๋ 3์ถ ์ง์๊ธฐ ์ผ์๋ค.
์ง์๊ธฐ ์ผ์๋ ์ง๊ตฌ์ ์๊ธฐ์ฅ์ ์ด์ฉํด ๋ฐฉํฅ์ ์ธก์ ํ๋ค. ๋๋ฌธ์ ์ฃผ์์ ์ ์๊ธฐ๊ธฐ๊ฐ ์๊ฑฐ๋, ์๊ธฐ๋ ฅ์ ์ผ์ผํค๋ ๋ฌผ๊ฑด์ด ์๋ค๋ฉด ์ ๋๋ก ๋์ํ์ง ์๋๋ค. 3์ถ ์ง์๊ธฐ ์ผ์๋ x,y,z์ถ์ ์๊ธฐ์ฅ์ ํฌ๊ธฐ(guass)๋ฅผ ์ธก์ ํ๋ค.
HMC5883L์ MPU-6050์์ ๊ณ์ฐํ๊ธฐ ํ๋ Yaw๊ฐ์ ์์์ค๋ ์ฉ๋๋ก ์ฐ์ธ๋ค. ๊ทธ๋ฌ๋ MPU-6050 ์ผ์์ ์จ๋ํน์ฑ์ ๋ฐ๋ฅธ ๋๋ฆฌํํธ ํน์ฑ์ ๊ฐ์ํ ์๊ณ ๋ฆฌ์ฆ์ ์ฌ์ฉํ๋ค๋ฉด MPU-6050์ผ๋ก๋ Yaw๊ฐ์ ๊ตฌํ ์ ์๋ค.
HMC5883L๋ MPU-6050๊ณผ ๋ง์ฐฌ๊ฐ์ง๋ก I2Cํต์ ์ผ๋ก ์ ๋ณด๋ฅผ ์ป๊ฑฐ๋ ์ฐ๊ณ , ๋ ์ง์คํฐ ์ฃผ์๋ก ์ํ๋ ์ ๋ณด์ ์ ๊ทผํ๋ค. ์ง์๊ธฐ ์ผ์์ x,y,z์ถ์ ๋จ์๋ gauss๋ฅผ ์ฌ์ฉํ๋, ์ผ์๊ฐ ๊ฐ๋ฅดํค๋ ๋ฐฉํฅ์ ์๊ธฐ์ํด์๋ ๋จ์๋ฅผ ์ ๊ฒฝ์ฐ์ง ์๊ณ , atan2(my, mx)
๊ณต์์ ์ด์ฉํด ๋ฐ๋ก ๊ตฌํ ์ ์๋ค.
์ด ๊ธ์ Stm32 Value line discovery๋ณด๋ ๊ฐ๋ฐ์ ์ํ ๊ธ์ด๋ค.
Stm32 Value line discovery ๋ณด๋๋ก ์ง์๊ธฐ ์ผ์๋ฅผ ํ ์คํธํ๋ ์ฝ๋๋ STM32\stm32vldiscovery_package\Project\Examples\HMC5883L ๊ฒฝ๋ก์ ์๋ค.
Arduino๋ก ์ง์๊ธฐ ์ผ์๋ฅผ ํ ์คํธํ๋ ์ฝ๋๋ Arduino\Adafruit_HMC5883_Unified-master\examples\magsensor ๊ฒฝ๋ก์ ์๋ค.
HMC5883L ์ผ์๊ฐ ์ฌ๋ฐ๋ก ์๋ํ๋์ง ์ํํด๋ณด๊ธฐ ์ํด์๋ Stm32๋ก ํ ๊ฒฝ์ฐ, HMC5883L ํ๋ก์ ํธ๋ก Stm32๋ฅผ ์คํํ๊ณ , PB11-SCL, PB10-SDA ํ์ HMC5883L์ผ์์ ์ฐ๊ฒฐํ๋ค. ์๋ฆฌ์ผํต์ ์ผ๋ก ์ผ์ ๊ฐ์ ๋ณด๋ด๊ธฐ ๋๋ฌธ์, Processing ํ๋ก์ ํธ HMC5883L_test_stm32๋ฅผ ์คํํ๋ฉด HMC5883L ์ ์ง์๊ธฐ์ผ์ x,y,z๋ฅผ ์ฝ์ด๋ค์ฌ 3D๋ก ๋์นจ๋ฐ์ ์ถ๋ ฅํ๋ค.
Stm32 Serial Debugging๋ฌธ์๋ฅผ ์ฐธ๊ณ ํ๋ฉด Stm32๋ก ๋ฐ๋ก ์๋ฆฌ์ผ ํต์ ํ๋ ๋ฐฉ๋ฒ์ ์ ์์๋ค.
์๋์ด๋ ธ๋ก HMC5883L ์ผ์๋ฅผ ์ํํ ๊ฒฝ์ฐ, ์๋์ด๋ ธ ํ๋ก์ ํธ magsensor๋ฅผ ์คํํ๋ค. ์ด ๋ HMC5883L๊ณผ I2Cํต์ ํ ํฌํธ A4-SDA, A5-SCL์ ์ฐ๊ฒฐํ๋ค. ์ ์์ ์ผ๋ก ์คํ๋์๋ค๋ฉด, ์ง์๊ธฐ ์ผ์์ ๋ณด๊ฐ ์๋ฆฌ์ผ์ ํตํด PC๋ก ์ ๋ฌ๋๊ฒ ๋๋ค. ๊ทธ ํ Processing ํ๋ก์ ํธ HMC5883L_test_arduino๋ฅผ ์ด์ด ์คํํ๋ฉด 3D ๋์นจ๋ฐ์ด ์ถ๋ ฅ๋๋ค.
GY-271 ๋ณด๋๋ SCL, SDA ํฌํธ์ ํ์ ์ ํญ์ด ๋ถ์ด์๊ธฐ ๋๋ฌธ์, ๋ฐ๋ก ๋ฌ์์ค ํ์ ์๋ค. ๋๋จธ์ง ๋ณด๋๋ค์ ํ๋ก๋๋ฅผ ํ์ธํ๊ณ ํ์ ์ ํญ์ ๋ฌ์.
Stm32 ์์ค๋ https://harinadha.wordpress.com/2012/05/24/hmc5883llib/ ๋ฅผ ์ด์ฉํ๋ค. MPU-6050 ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์์ฑํ ์ฌ๋๊ณผ ๋์ผํ๋ค. ์ด ์ฝ๋์ ์ฌ๊ฐํ ๋ฌธ์ ๋ while()
๋ฌธ์ผ๋ก ACK๊ฐ ์ฌ ๋๊น์ง ๋๊ธฐํ๋ ๋ถ๋ถ์ด๋ค. ๋ง์ฝ ์ผ์์ I2C๋ผ์ธ์ด ๋ฌผ๋ฆฌ์ ์ผ๋ก ๋์ด์ง ๊ฒฝ์ฐ, ๋งค์ธ ํ๋ก๊ทธ๋จ์ ๋ฉ์ถฐ๋ฒ๋ฆฌ๊ฒ ๋๋ค. ๊ทธ๋์ ์ด ์ฝ๋๋ HMC5883L์ผ์๋ฅผ ํ
์คํธํ๋ ์ฉ๋๋ก๋ง ์ฐ์ด๊ณ , ์ค์ ํ๋ธ๋ฅผ ๋ ๋ฆด ๋๋ ์ฐ์ง ์์ ๊ณํ์ด๋ค.
(multiwii์ baseflight ํ๋ก์ ํธ๋ ๋ฌดํ์ ๋๊ธฐํ๋ ๋ฌธ์ ๋ฅผ ์ด๋ฒคํธ๋ก ํด๊ฒฐํ๋ค.)
HMC5883L ์ด๊ธฐํ
HMC5883L_I2C_Init()
ํจ์์์๋ HMC5883L๊ณผ ํต์ ์ ์ํ I2Cํฌํธ๋ฅผ ์ค์ ํ๋ค.(PB10-SCL, PB11-SDA) ๊ทธ๋ฆฌ๊ณ SerialSetup()
ํจ์์์ ์ผ์๋ก๋ถํฐ ์ป์ด ์จ ์ ๋ณด๋ฅผ ํ๋ฉด์ ์ถ๋ ฅํ๊ธฐ ์ํ ์๋ฆฌ์ผํต์ ํฌํธ PA10-Rx, PA9-Tx๋ฅผ ์ค์ ํ๋ค. InitSysTick()
ํจ์๋
GetTickCount()
ํจ์๋ฅผ ๋์ํ ์ ์๊ฒ ์ด๊ธฐํ ํ๋ค.
HMC5883L_Initialize()
ํจ์์์ +-1.3 Gauss ๋ฒ์๋ฅผ ์ค์ ํ๊ณ , ์ฑ๊ธ๋ชจ๋๋ก ๋์ํ๊ฒ ํ๋ค. ์ด ์ต์
๋ค์ ๋ชจ๋ ๊ธฐ๋ณธ์ค์ ์ฌํญ์ด๋ค.
#define HMC5883L_I2C I2C2
#define HMC5883L_I2C_RCC_Periph RCC_APB1Periph_I2C2
#define HMC5883L_I2C_Port GPIOB
#define HMC5883L_I2C_SCL_Pin GPIO_Pin_10
#define HMC5883L_I2C_SDA_Pin GPIO_Pin_11
#define HMC5883L_I2C_RCC_Port RCC_APB2Periph_GPIOB
#define HMC5883L_I2C_Speed 100000
void setup()
{
InitSysTick();
SerialSetup();
HMC5883L_I2C_Init();
HMC5883L_Initialize();
}
/**
* @brief Initializes the I2C peripheral used to drive the HMC5883L
* @param None
* @retval None
*/
void HMC5883L_I2C_Init()
{
I2C_InitTypeDef I2C_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
/* Enable I2C and GPIO clocks */
RCC_APB1PeriphClockCmd(HMC5883L_I2C_RCC_Periph, ENABLE);
RCC_APB2PeriphClockCmd(HMC5883L_I2C_RCC_Port, ENABLE);
/* Configure I2C pins: SCL and SDA */
GPIO_InitStructure.GPIO_Pin = HMC5883L_I2C_SCL_Pin | HMC5883L_I2C_SDA_Pin;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
GPIO_Init(HMC5883L_I2C_Port, &GPIO_InitStructure);
/* I2C configuration */
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
I2C_InitStructure.I2C_OwnAddress1 = HMC5883L_DEFAULT_ADDRESS; // HMC5883L 7-bit adress = 0x1E;
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_InitStructure.I2C_ClockSpeed = HMC5883L_I2C_Speed;
/* Apply I2C configuration after enabling it */
I2C_Init(HMC5883L_I2C, &I2C_InitStructure);
I2C_Cmd(HMC5883L_I2C, ENABLE);
}
/** Power on and prepare for general usage.
* This will prepare the magnetometer with default settings, ready for single-
* use mode (very low power requirements). Default settings include 8-sample
* averaging, 15 Hz data output rate, normal measurement bias, a,d 1090 gain (in
* terms of LSB/Gauss). Be sure to adjust any settings you need specifically
* after initialization, especially the gain settings if you happen to be seeing
* a lot of -4096 values (see the datasheet for mor information).
*/
void HMC5883L_Initialize()
{
// write CONFIG_A register
uint8_t tmp = (HMC5883L_AVERAGING_8 << (HMC5883L_CRA_AVERAGE_BIT - HMC5883L_CRA_AVERAGE_LENGTH + 1))
| (HMC5883L_RATE_15 << (HMC5883L_CRA_RATE_BIT - HMC5883L_CRA_RATE_LENGTH + 1))
| (HMC5883L_BIAS_NORMAL << (HMC5883L_CRA_BIAS_BIT - HMC5883L_CRA_BIAS_LENGTH + 1));
HMC5883L_I2C_ByteWrite(HMC5883L_DEFAULT_ADDRESS, &tmp, HMC5883L_RA_CONFIG_A);
// write CONFIG_B register
HMC5883L_SetGain(HMC5883L_GAIN_1090);
// write MODE register
HMC5883L_SetMode(HMC5883L_MODE_SINGLE);
}
void SerialSetup(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
// RCC Configuration
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE );
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
// Port ์ค์
// PA9 - Tx
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// PA10 - Rx
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// UART Port ์ค์
USART_InitStructure.USART_BaudRate = 19200;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No ;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART1, &USART_InitStructure);
USART_Cmd(USART1, ENABLE);
}
HMC5883L ์ผ์์ ๋ณด๋ฅผ ๊ฐ์ ธ์จ๋ค.
์ดํดํ ์ ์๋ ์ฝ๋๊ฐ ๋ช ๊ตฐ๋ฐ ์์ง๋ง, ๋์ด๊ฐ๊ณ HMC5883L_I2C_BufferRead()
ํจ์๋ฅผ ๋ณด์. MPU-6050์ผ์์ ๋ง์ฐฌ๊ฐ์ง๋ก, ์ฝ์ด ์ฌ HMC5883L ๋ ์ง์คํฐ ์ฃผ์๋ฅผ ๋จผ์ ๋ณด๋ด๊ณ , ์ฌ์ฏ ๋ฒ ๋ฐ๋ณตํด์ Readํด์ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์จ๋ค. ๋ ์ง์คํฐ ์ฃผ์๋ HMC5883L_RA_DATAX_H์์ ๋ถํฐ ์ฌ์ฏ ๋ฒ ์ฝ์ด์จ๋ค. ๋ ์ง์คํฐ ์ฃผ์๋ HAL_HMC5883L.h
ํค๋ํ์ผ์ ๋ค์๊ณผ ๊ฐ์ด ์ ์ ๋์ด ์๋ค.
Y์ถ๊ณผ Z์ถ ๋ ์ง์คํฐ์ฃผ์๊ฐ ์๋ก ๋ฐ๊ผ์ง๋ง, ์ฌ์ฏ ๋ฒ์ ์์๋๋ก ์ฝ๊ธฐ ๋๋ฌธ์, ์ ๋ณด๊ฐ ๋น ์ง์ง๋ ์๋๋ค.
#define HMC5883L_RA_CONFIG_A 0x00
#define HMC5883L_RA_CONFIG_B 0x01
#define HMC5883L_RA_MODE 0x02
#define HMC5883L_RA_DATAX_H 0x03
#define HMC5883L_RA_DATAX_L 0x04
#define HMC5883L_RA_DATAY_H 0x05
#define HMC5883L_RA_DATAY_L 0x06
#define HMC5883L_RA_DATAZ_H 0x07
#define HMC5883L_RA_DATAZ_L 0x08
#define HMC5883L_RA_STATUS 0x09
#define HMC5883L_RA_ID_A 0x0A
#define HMC5883L_RA_ID_B 0x0B
#define HMC5883L_RA_ID_C 0x0C
์ค์ ๋ ์ง์คํฐ ์ฃผ์๋ ๋ค์๊ณผ ๊ฐ๋ค.
int16_t MagneticHeading[3]={0};
HMC5883L_GetHeading(MagneticHeading);
/** Get 3-axis heading measurements.
* In the event the ADC reading overflows or underflows for the given channel,
* or if there is a math overflow during the bias measurement, this data
* register will contain the value -4096. This register value will clear when
* after the next valid measurement is made. Note that this method automatically
* clears the appropriate bit in the MODE register if Single mode is active.
* @param x 16-bit signed integer container for X,Y,Z-axis heading
* @see HMC5883L_RA_DATAX_H
*/
void HMC5883L_GetHeading(s16* Mag)
{
int i=0;
uint8_t tmp;
uint8_t tmpbuff[6] = { 0 };
HMC5883L_I2C_BufferRead(HMC5883L_DEFAULT_ADDRESS, tmpbuff, HMC5883L_RA_DATAX_H, 6);
tmp = HMC5883L_MODE_SINGLE << (HMC5883L_MODEREG_BIT - HMC5883L_MODEREG_LENGTH + 1);
if (HMC5883Lmode == HMC5883L_MODE_SINGLE)
HMC5883L_I2C_ByteWrite(HMC5883L_DEFAULT_ADDRESS, &tmp, HMC5883L_RA_MODE);
for (i = 0; i < 3; i++)
Mag[i] = ((s16) ((u16) tmpbuff[2 * i] << 8) + tmpbuff[2 * i + 1]);
}
HMC5883L.h
๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ์ผ์์ ๋ณด๋ฅผ ์ด๋ ๊ฒ ๊ฐ์ ธ์ค๊ณ ๋๋๋ค. ์ด ๊ฐ์ gauss ๋จ์์ด์ง๋ง, ์ค์ ๊ฐ์ ์๋๊ณ , Scale Factor๋ก ๋๋ ์ค์ผ ํ๋ค. ๋ง์ฝ ์ผ์๊ฐ ๋ฐ๋ผ๋ณด๊ณ ์๋ ๋ฐฉํฅ๊ฐ๋ง ์๊ณ ์ถ๋ค๋ฉด gauss ํ๋ณํ ์์ด ๋ฐ๋ก atan2(my, mx)
๋ก ๊ตฌํ ์ ์๋ค.
์ด๋ ๊ฒ ๊ตฌํด์ง ๊ฐ์ ์ค์ ๋ฐฉํฅ์ ๊ตฌํ๊ธฐ์ํด์ ํธ๊ฐ(declination)์ ๋ํ๊ฑฐ๋ ๋นผ์ค์ผ ํ๋ค. ์๋ํ๋ฉด ์๊ธฐ์ฅ์ด ๊ฐ๋ฅดํค๋ ๋ถ๊ทน์ ์ค์ ๋ถ๊ทนํ๊ณ ๋ค๋ฅด๊ธฐ ๋๋ฌธ์ด๋ค.
Main ํจ์
HMC5883L_GetHeading()
ํจ์๋ก ์ผ์์ ๋ณด๋ฅผ ๊ฐ์ ธ์จ ํ, ๋ฐ๋ก SendSerialMagnetometer()
ํจ์๋ฅผ ํตํด ์๋ฆฌ์ผํต์ ์ผ๋ก ๋ณด๋ธ๋ค. x,z,y ์์๋๋ก ์ ๋ณด๋ฅผ ๋ฐ์์ค๊ณ ์๋ค๋ ๊ฒ์ ์ฃผ๋ชฉํ์. ์ด๋ HMC5883L ์ผ์์ ๋ ์ง์คํฐ ์ฃผ์ ์์ ๋๋ฌธ์ด๋ค.
์ผ์๊ฐ ๋ฐ๋ผ๋ณด๋ ๋ฐฉํฅ์ ๊ตฌํ ๋, atan2(my, mx)
๋ก ๊ณ์ฐํ๋ ์ด์ ๋ MEMS ์ผ์๋ฅผ ์ด์ฉํ ๋ฌด์ธํญ๊ณต๊ธฐ์ฉ ์์ธ์ธก์ ์ฅ์น์ ํน์ฑ์ ๋ํ ์ฐ๊ตฌ.pdf ๋ฌธ์์ ์ ๋์ ์๋ค. STM32\pdf\MEMS ์ผ์๋ฅผ ์ด์ฉํ ๋ฌด์ธํญ๊ณต๊ธฐ์ฉ.pdf ๊ฒฝ๋ก์ ์๋ค.
int main()
{
int curTick=0, oldTick=0;
int16_t MagneticHeading[3]={0};
setup();
if( HMC5883L_TestConnection())
{
// connection success
}
else
{
// connection failed
return 1;
}
while(1)
{
curTick = GetTickCount();
if (curTick - oldTick > 50)
{
HMC5883L_GetHeading(MagneticHeading);
SendSerialMagnetometer(MagneticHeading);
oldTick = curTick;
}
}
}
// ์ง์๊ธฐ ์ผ์ ์ ๋ณด๋ฅผ ์๋ฆฌ์ผํต์ ์ผ๋ก ๋ณด๋ธ๋ค.
void SendSerialMagnetometer( int16_t magnetometer[3] )
{
int16_t mag_x = magnetometer[0];
int16_t mag_y = magnetometer[2];
int16_t mag_z = magnetometer[1];
print_byte( 'S' );
print_short( mag_x );
print_short( mag_y );
print_short( mag_z );
}
๋ ํผ๋ฐ์ค
- HMC5883L ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ ์
- http://blog.bitify.co.uk/2013/12/pitch-roll-and-yaw-using-mpu6050.html
- http://pinkwink.tistory.com/338
- http://thinkslowly.tistory.com/entry/%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B801%EC%BF%BC%EB%93%9C%EC%BD%A5%ED%84%B0-%EC%A0%9C%EC%9E%91010-%EC%A0%84%EC%9E%90-%EB%82%98%EC%B9%A8%EB%B0%98-%EC%99%84%EC%84%B1
- http://zmflftodn.tistory.com/category/%EB%A9%80%ED%8B%B0%EC%BD%A5%ED%84%B0/ArduCopter?page=2
- http://6333.tistory.com/14
- https://learn.adafruit.com/adafruit-hmc5883l-breakout-triple-axis-magnetometer-compass-sensor/wiring-and-test
- MEMS ์ผ์๋ฅผ ์ด์ฉํ ๋ฌด์ธํญ๊ณต๊ธฐ์ฉ ์์ธ์ธก์ ์ฅ์น์ ํน์ฑ์ ๋ํ ์ฐ๊ตฌ.pdf