element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • Members
    Members
    • Benefits of Membership
    • Achievement Levels
    • Members Area
    • Personal Blogs
    • Feedback and Support
    • What's New on element14
  • Learn
    Learn
    • Learning Center
    • eBooks
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Dev Tools
    • Manufacturers
    • Raspberry Pi
    • RoadTests & Reviews
    • Avnet Boards Community
    • Product Groups
  • Store
    Store
    • Visit Your Store
    • Choose Another Store
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
RIoTboard
  • Products
  • Dev Tools
  • Single-Board Computers
  • RIoTboard
  • More
  • Cancel
RIoTboard
Blog Riotboard Xtrinsic accelerometer : Calculate Pitch & Roll
  • Blog
  • Forum
  • Documents
  • Members
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
RIoTboard requires membership for participation - click to join
Blog Post Actions
  • Subscribe by email
  • More
  • Cancel
  • Share
  • Subscribe by email
  • More
  • Cancel
Group Actions
  • Group RSS
  • More
  • Cancel
Engagement
  • Author Author: tusharp
  • Date Created: 26 Nov 2014 5:24 PM Date Created
  • Views 409 views
  • Likes 0 likes
  • Comments 1 comment
  • driver
  • tusharp
  • Ubuntu
  • yocto
  • gpio
  • freescale
  • imx6
  • riotboard
  • accelerometer
  • embedded
  • xtrinsic
  • setup
  • riot
  • cortex-a9
  • mma8491q
  • bsp
  • roll
  • arm
  • arm9
  • pitch
  • sensor
  • linux
Related
Recommended

Riotboard Xtrinsic accelerometer : Calculate Pitch & Roll

tusharp
tusharp
26 Nov 2014

In the previous blog we setup the xtrinsic board to read accelerometer registers.

However the raw register values doesn't mean anything by itself. It needs to be converted to suitable human readable format to be useful in measurement applications.

 

In this guide we shall use a proper logic to calculate the elevation and bank, other wise called Pitch and Roll of xtrinsic mma8491q accelerometer.

 

A self-explanatory image of Pitch, Roll & Yaw.

11ujhat.jpg

 

Pitch:

Pitch is the measurement of elevation of a surface on which an accelerometer is mounted.

It helps to calculate the magnitude of ascent, descent and inclination against the 3-dimensional axis.

 

Roll:

This property helps to determine if the object is spinning/rotate around itself.


Check this : http://howthingsfly.si.edu/flight-dynamics/roll-pitch-and-yaw



What is g-value & how to find one ??


Earth's gravity by itself acts downwards.

In case of accelerometer the gravity is experienced on either/all of the axis when movement happens.

 

 

Below is the register bitmap from mma8491q data sheet.

294jpte.jpg

According to above we will get 8bits in MSB & 6bits in LSB, so total 14bits to read for.

so max value that can be read is (2^14 -1) = 16383.

Any value obtained from the registers above is a signed value.

We will consider the values between 0 to 8191 is positive  & ones between 8192 to 16383 is the negative (opposite direction.)

Differentiating the values will help us determine which direction the xtrinsic mma8491q is titled.

 

g-value during pitch

When xtrinsic is held flat on surface level with ground, gvalue across X-axis  is near 0.

rh08jl.jpg

 

Increasing the tilt across X-axis, the head is pointing up, gvalue across X-axis increase from 0 to 1g.

23k41gj.jpg

 

Similarly, decreasing the tilt across X-axis, the head is pointing down, gvalue across X-axis decrease from 0 to -1g.

ayt6jb.jpg

 

 

g-value during roll

When xtrinsic is held flat on surface level with ground, gvalue across Y-axis is near 0.

skwbqf.jpg

 

Lowering the board across Y-axis, the sideways goes down, g-value across Y-axis increase from 0 to 1g.

23w5rnd.jpg

 

Similarly, Lowering the board in opposite direction on Y-axis, g-value across Y-axis decrease from 0 to -1g.

14to6tx.jpg

 

 

The pitch & roll values can be determined  in 3 steps.

  1. convert register readings to g value.
  2. convert g-value to axis based angle.
  3. convert the measured angle to Pitch & Roll.

 

We will be using the math.h library to calculate the required values.

 

 

Convert register readings to g-value.

double register_to_gvalue(unsigned char msb,unsigned char lsb)     //we get unsigned register values

{

    signed int data1;

    double data2;

    data1 = (signed int)((msb<<6)|(lsb>>2));   //convert values to signed data

 

    if (data1 > 16383/2 )

        data1 = data1-16383;

 

    data2 = (double)data1/1000.0;  //convert signed data to g-value

    return data2;

 

}

 

 

Convert g-value to angle

 

Next we need to convert the gvalue in double data-type to an angle against an axis.

we use arcsine function from math.h library to get this done.

double gvalue_to_angle(double gvalue)  //we got the gvalue form previous calculation
{

    double data1;    

    data1 = asin(gvalue/1)*(180/PI);   //convert gvalue to angle against an axis

    return data1;

}

 

 

Convert the measured angle to Pitch & Roll


we use arctan2 and multiple the resulting value to get an approximate tilt value for Pitch & Roll.

pitch = (atan2(gvalue_x, sqrt(gvalue_y*gvalue_y + gvalue_z*gvalue_z))*180.0)/M_PI;

roll  = (atan2(-gvalue_y, gvalue_z)*180.0)/M_PI;

 

The complete code for the above setup :

#include <stdio.h>
#include <stdint.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <string.h>
#include <math.h>

#define I2CFILE "/dev/i2c-3"
#define PI 3.14159

static int write_register(int file,unsigned char address,unsigned char reg,unsigned char data)
{

   unsigned char output_buffer[2];
   struct i2c_rdwr_ioctl_data packets;
   struct i2c_msg messages[1];

    messages[0].addr  = address;
    messages[0].flags = 0;
    messages[0].len   = sizeof(output_buffer);
    messages[0].buf   = output_buffer;

    output_buffer[0] = reg;
    output_buffer[1] = data;

    packets.msgs  = messages;
    packets.nmsgs = 1;

    if(ioctl(file, I2C_RDWR, &packets) < 0) {
        perror("Error sending data");
        return 1;
    }

    return 0;
}


static int read_register(int file, unsigned char address, unsigned char reg, unsigned char *data)
{
    unsigned char input_buffer, output_buffer;
    struct i2c_rdwr_ioctl_data packets;
    struct i2c_msg messages[2];


    output_buffer = reg;
    messages[0].addr  = address;
    messages[0].flags = 0;
    messages[0].len   = sizeof(output_buffer);
    messages[0].buf   = &output_buffer;

    messages[1].addr  = address;
    messages[1].flags = I2C_M_RD;
    messages[1].len   = sizeof(input_buffer);
    messages[1].buf   = &input_buffer;


    packets.msgs      = messages;
    packets.nmsgs     = 2;
    if(ioctl(file, I2C_RDWR, &packets) < 0) {
        perror("Error Receiving data");
        return 1;
    }
    *data = input_buffer;

    return 0;
}

double gvalue_to_angle(double gvalue)
{
    double data1;
    data1 = asin(gvalue/1)*(180/PI);
    return data1;
}


double register_to_gvalue(unsigned char msb,unsigned char lsb)
{
    signed int data1;
    double data2;
    data1 = (signed int)((msb<<6)|(lsb>>2));    //convert

    if (data1 > 16383/2 )
        data1 = data1-16383;

    data2 = (double)data1/1000.0;
    return data2;

}

int main() {
    int file, i;
    unsigned char data_m;
    unsigned char data_l;
    double gvalue_x;
    double gvalue_y;
    double gvalue_z;
    double angle_x;
    double angle_y;
    double angle_z;
    double pitch;
    double roll;

if ((file = open(I2CFILE, O_RDWR)) < 0)
{
    perror("Error openning file!");
    exit(1);
}
else
    printf("%s opened\n",I2CFILE);


while(1)
{
//accel status
   if(read_register(file, 0x55, 0x00, &data_m))
      exit(1);
   else
     printf("\n\n\nAcc Status: [0x%02X]: 0x%02X\n" , 00 , data_m);


//read accel MSB/LSB - X axis
   if(read_register(file, 0x55, 0x01, &data_m))
     exit(1);
   if(read_register(file, 0x55, 0x02, &data_l))
     exit(1);
/*   printf("X-Register : 0x%02X:0x%02X\n" , data_m, data_l);*/

    gvalue_x = register_to_gvalue(data_m,data_l);
    printf("\nX-gvalue  : %.02lfg\n" , gvalue_x);

    angle_x = gvalue_to_angle(gvalue_x);
    printf("X-angle      : %.02lf\n\n" , angle_x);



//read accel MSB/LSB - Y axis
   if(read_register(file, 0x55, 0x03, &data_m))
     exit(1);
   if(read_register(file, 0x55, 0x04, &data_l))
     exit(1);
/*   printf("Y-Register : 0x%02X:0x%02X\n" , data_m, data_l);*/

    gvalue_y = register_to_gvalue(data_m,data_l);
    printf("Y-gvalue  : %.02lfg\n" , gvalue_y);

    angle_y = gvalue_to_angle(gvalue_y);
    printf("Y-angle      : %.02lf\n\n" , angle_y);



//read accel MSB/LSB - Z axis
   if(read_register(file, 0x55, 0x05, &data_m))
     exit(1);
   if(read_register(file, 0x55, 0x06, &data_l))
     exit(1);
/*    printf("Z-Register : 0x%02X:0x%02X\n" , data_m, data_l);*/

    gvalue_z = register_to_gvalue(data_m,data_l);
    printf("Z-gvalue  : %.02lfg\n" , gvalue_z);

    angle_z = gvalue_to_angle(gvalue_z);
    printf("Z-angle      : %.02lf\n\n" , angle_z);

pitch = (atan2(gvalue_x, sqrt(gvalue_y*gvalue_y + gvalue_z*gvalue_z))*180.0)/M_PI;
roll  = (atan2(-gvalue_y, gvalue_z)*180.0)/M_PI;

printf("pitch :%lf:\n", pitch);
printf("roll  :%lf:\n", roll);

system("echo out > /sys/class/gpio/gpio112/direction");
system("echo 1 > /sys/class/gpio/gpio112/value");
usleep(1000000);

}
    close(file);
    return 0;
}

 

 

Start the Application, you will get something similar as below:

I got the below readings with board resting on table.

2v2bn2s.jpg

2ryftqb.jpg

 

In the Next blog we shall detect Accelerometer tilts & configure GPIO pins for same.

Attachments:
1157.xtrinsic_acc.c.zip
  • Sign in to reply
  • DAB
    DAB over 8 years ago

    Nice update.

     

     

    DAB

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2023 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

ICP 备案号 10220084.

Follow element14

  • Facebook
  • Twitter
  • linkedin
  • YouTube