Maker Pro
Maker Pro

Detecting horizontal position

You can call it a secret:) but actually its an instrument I am trying to work around . I need to know precise coordinates of the platform when the hinged rod is exactly horizontal. As of now we use an arbitrary method i.e when it appears the rod is horizontal we note down the position of the platform. I am trying to make something which could be more precise.

Coming to why I want to freeze the display? well so that I know when the rod was exactly horizontal, the readings from the IMU on the platform when the rod is is in any other position is not required.
I am uploading the code I am using on the IMU . Please let me know where and what I need to modify.

Code:
 /* This is an example where we configure the data of the MPU9250
 * and read the Acceleration data and print it to the serial monitor
 *
 * Arduino pin    |   MPU9250
 * 5V             |   Vcc
 * GND            |   GND
 * A4             |   SDA
 * A5             |   SCL
 */
//Includes
#include <Wire.h>
#include "U8glib.h"

// Display
U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NO_ACK); // Display which does not send AC


//Gyro Variables
float elapsedTime, time, timePrev;        //Variables for time control
int gyro_error=0;                         //We use this variable to only calculate once the gyro data error
float Gyr_rawX, Gyr_rawY, Gyr_rawZ;     //Here we store the raw data read
float Gyro_angle_x, Gyro_angle_y,Gyro_angle_z;         //Here we store the angle value obtained with Gyro data
float Gyro_raw_error_x, Gyro_raw_error_y ,Gyro_raw_error_z; //Here we store the initial gyro data error

//Acc Variables
int acc_error=0;                         //We use this variable to only calculate once the Acc data error
float rad_to_deg = 180/3.141592654;      //This value is for pasing from radians to degrees values
float Acc_rawX, Acc_rawY, Acc_rawZ;    //Here we store the raw data read
float Acc_angle_x, Acc_angle_y,Acc_angle_z;          //Here we store the angle value obtained with Acc data
float Acc_angle_error_x, Acc_angle_error_y,Acc_angle_error_z; //Here we store the initial Acc data error

float Total_angle_x, Total_angle_y,Total_angle_z;


void setup() {
  Wire.begin();                           //begin the wire comunication
 
  Wire.beginTransmission(0x68);           //begin, Send the slave adress (in this case 68)             
  Wire.write(0x6B);                       //make the reset (place a 0 into the 6B register)
  Wire.write(0x00);
  Wire.endTransmission(true);             //end the transmission
  //Gyro config
  Wire.beginTransmission(0x68);           //begin, Send the slave adress (in this case 68)
  Wire.write(0x1B);                       //We want to write to the GYRO_CONFIG register (1B hex)
  Wire.write(0x10);                       //Set the register bits as 00010000 (1000dps full scale)
  Wire.endTransmission(true);             //End the transmission with the gyro
  //Acc config
  Wire.beginTransmission(0x68);           //Start communication with the address found during search.
  Wire.write(0x1C);                       //We want to write to the ACCEL_CONFIG register
  Wire.write(0x10);                       //Set the register bits as 00010000 (+/- 8g full scale range)
  Wire.endTransmission(true);

  Serial.begin(9600);                     //Remember to set this same baud rate to the serial monitor  
  time = millis();                        //Start counting time in milliseconds


/*Here we calculate the acc data error before we start the loop
 * I make the mean of 200 values, that should be enough*/
  if(acc_error==0)
  {
    for(int a=0; a<200; a++)
    {
      Wire.beginTransmission(0x68);
      Wire.write(0x3B);                       //Ask for the 0x3B register- correspond to AcX
      Wire.endTransmission(false);
      Wire.requestFrom(0x68,6,true);
     
      Acc_rawX=(Wire.read()<<8|Wire.read())/4096.0 ; //each value needs two registres
      Acc_rawY=(Wire.read()<<8|Wire.read())/4096.0 ;
      Acc_rawZ=(Wire.read()<<8|Wire.read())/4096.0 ;

     
       /*---X---*/
      Acc_angle_error_x = Acc_angle_error_x + ((atan((Acc_rawY)/sqrt(pow((Acc_rawX),2) + pow((Acc_rawZ),2)))*rad_to_deg));
      /*---Y---*/
      Acc_angle_error_y = Acc_angle_error_y + ((atan(-1*(Acc_rawX)/sqrt(pow((Acc_rawY),2) + pow((Acc_rawZ),2)))*rad_to_deg));
      /*---Z---*/
      Acc_angle_error_z = Acc_angle_error_z + ((atan((Acc_rawX)/sqrt(pow((Acc_rawY),2) + pow((Acc_rawY),2)))*rad_to_deg));
   
   
     
      if(a==199)
      {
        Acc_angle_error_x = Acc_angle_error_x/200;
        Acc_angle_error_y = Acc_angle_error_y/200;
        Acc_angle_error_z = Acc_angle_error_z/200;
        acc_error=1;
      }
    }
  }//end of acc error calculation   


/*Here we calculate the gyro data error before we start the loop
 * I make the mean of 200 values, that should be enough*/
  if(gyro_error==0)
  {
    for(int i=0; i<200; i++)
    {
      Wire.beginTransmission(0x68);            //begin, Send the slave adress (in this case 68)
      Wire.write(0x43);                        //First adress of the Gyro data
      Wire.endTransmission(false);
      Wire.requestFrom(0x68,4,true);           //We ask for just 4 registers
         
      Gyr_rawX=Wire.read()<<8|Wire.read();     //Once again we shif and sum
      Gyr_rawY=Wire.read()<<8|Wire.read();
   
      /*---X---*/
      Gyro_raw_error_x = Gyro_raw_error_x + (Gyr_rawX/32.8);
      /*---Y---*/
      Gyro_raw_error_y = Gyro_raw_error_y + (Gyr_rawY/32.8);
      /*---Z---*/
      Gyro_raw_error_z = Gyro_raw_error_z + (Gyr_rawZ/32.8);
      if(i==199)
      {
        Gyro_raw_error_x = Gyro_raw_error_x/200;
        Gyro_raw_error_y = Gyro_raw_error_y/200;
        Gyro_raw_error_z = Gyro_raw_error_z/200;
        gyro_error=1;
      }
    }
  }//end of gyro error calculation   
}//end of setup void






void loop() {
  timePrev = time;                        // the previous time is stored before the actual time read
  time = millis();                        // actual time read
  elapsedTime = (time - timePrev) / 1000; //divide by 1000 in order to obtain seconds

  //////////////////////////////////////Gyro read/////////////////////////////////////

    Wire.beginTransmission(0x68);            //begin, Send the slave adress (in this case 68)
    Wire.write(0x43);                        //First adress of the Gyro data
    Wire.endTransmission(false);
    Wire.requestFrom(0x68,4,true);           //We ask for just 4 registers
       
    Gyr_rawX=Wire.read()<<8|Wire.read();     //Once again we shif and sum
    Gyr_rawY=Wire.read()<<8|Wire.read();
    Gyr_rawZ=Wire.read()<<8|Wire.read();
    /*Now in order to obtain the gyro data in degrees/seconds we have to divide first
    the raw value by 32.8 because that's the value that the datasheet gives us for a 1000dps range*/
    /*---X---*/
    Gyr_rawX = (Gyr_rawX/32.8) - Gyro_raw_error_x;
    /*---Y---*/
    Gyr_rawY = (Gyr_rawY/32.8) - Gyro_raw_error_y;
    /*---Z---*/
    Gyr_rawZ = (Gyr_rawZ/32.8) - Gyro_raw_error_z;
   
    /*Now we integrate the raw value in degrees per seconds in order to obtain the angle
    * If you multiply degrees/seconds by seconds you obtain degrees */
    /*---X---*/
    Gyro_angle_x = Gyr_rawX*elapsedTime;
    /*---X---*/
    Gyro_angle_y = Gyr_rawY*elapsedTime;
     /*---Z---*/
    Gyro_angle_z = Gyr_rawZ*elapsedTime;


   
 
  //////////////////////////////////////Acc read/////////////////////////////////////

  Wire.beginTransmission(0x68);     //begin, Send the slave adress (in this case 68)
  Wire.write(0x3B);                 //Ask for the 0x3B register- correspond to AcX
  Wire.endTransmission(false);      //keep the transmission and next
  Wire.requestFrom(0x68,6,true);    //We ask for next 6 registers starting withj the 3B  
  /*We have asked for the 0x3B register. The IMU will send a brust of register.
  * The amount of register to read is specify in the requestFrom function.
  * In this case we request 6 registers. Each value of acceleration is made out of
  * two 8bits registers, low values and high values. For that we request the 6 of them  
  * and just make then sum of each pair. For that we shift to the left the high values
  * register (<<) and make an or (|) operation to add the low values.
  If we read the datasheet, for a range of+-8g, we have to divide the raw values by 4096*/   
  Acc_rawX=(Wire.read()<<8|Wire.read())/4096.0 ; //each value needs two registres
  Acc_rawY=(Wire.read()<<8|Wire.read())/4096.0 ;
  Acc_rawZ=(Wire.read()<<8|Wire.read())/4096.0 ;
 /*Now in order to obtain the Acc angles we use euler formula with acceleration values
 after that we substract the error value found before*/  
 /*---X---*/
 Acc_angle_x = (atan((Acc_rawY)/sqrt(pow((Acc_rawX),2) + pow((Acc_rawZ),2)))*rad_to_deg) - Acc_angle_error_x;
 /*---Y---*/
 Acc_angle_y = (atan(-1*(Acc_rawX)/sqrt(pow((Acc_rawY),2) + pow((Acc_rawZ),2)))*rad_to_deg) - Acc_angle_error_y;   
/*---Z---*/
Acc_angle_z = (atan(-1*(Acc_rawX)/sqrt(pow((Acc_rawZ),2) + pow((Acc_rawY),2)))*rad_to_deg) - Acc_angle_error_z;

 //////////////////////////////////////Total angle and filter/////////////////////////////////////
 /*---X axis angle---*/
 Total_angle_x = 0.98 *(Total_angle_x + Gyro_angle_x) + 0.02*Acc_angle_x;
 /*---Y axis angle---*/
 Total_angle_y = 0.98 *(Total_angle_y + Gyro_angle_y) + 0.02*Acc_angle_y;
  /*---Z axis angle---*/
  /*---X axis angle---*/
 Total_angle_z = 0.98 *(Total_angle_z + Gyro_angle_z) + 0.02*Acc_angle_z;

 /*Uncoment the rest of the serial prines
 * I only print the Y angle value for this test */
 // text display tests
 
   u8g.firstPage();  
  do {
    u8g.setFont(u8g_font_unifont);
    u8g.setPrintPos(5,10);
    u8g.setFontLineSpacingFactor(uint8_t (51));
    u8g.print("X: ");
    u8g.print(Total_angle_x);
    u8g.setPrintPos(5,30);
     u8g.print("Y: ");
    u8g.print(Total_angle_y);
    u8g.setPrintPos(5,50);
    u8g.print("Z: ");
    u8g.print(Total_angle_z);
  } while( u8g.nextPage() );

 Serial.print(" :Xº");
 Serial.print(Total_angle_x);
 Serial.print("   |   ");
 Serial.print(" :Yº");
 Serial.print(Total_angle_y);
 Serial.print(" | ");
 Serial.print(" :Zº");
 Serial.print(Total_angle_z);
 Serial.println(" ");

delay(200);

}

And this is the code for Tilt senson from Robojax
Code:
*
  // Tilt Sensor code for Robojax.com
#define TILT 2 // pin 2 for front-left sensor
#define LED 8 // pin 3 for front-right sensor


void setup() {
  Serial.begin(9600);
  Serial.println("Robojax Tilt Test");
  pinMode(TILT, INPUT);//define Data input pin input pin
  pinMode(LED,OUTPUT);// define LED pint  pin as output
}

 void loop() {
   
  int TILT_SENSED = digitalRead(TILT);// read TILT sensor

  // if tilt is sensed
  if( TILT_SENSED ==LOW)
  {
    digitalWrite(LED,HIGH);// set the LED pin HIGH and buzzer will buzz
    Serial.println("Tilt detected");
  }else{
    digitalWrite(LED,LOW); // Set the LED pin LOW to turn it OFF or buzzer OFF
    Serial.println("Normal");
  }

  delay(200);
}

I need to change the LED .HIGH to something to freeze the display. Buzzer is optional.

Looking forward to your advice.
 
Surely if you only need a two position sensor, there is small magnet sensors such as Honeywell SS400 series,
The have 3 or 4 different varieties, such as latch/unlatch, unipolar, bi-polar etc.
M.
 

hevans1944

Hop - AC8NS
its an instrument I am trying to work around . I need to know precise coordinates of the platform when the hinged rod is exactly horizontal.
Still not enough information to understand what your are trying to DO, unless your only problem now is how to "freeze" the display when the rod is horizontal. Presumably you have tried out the tilt switch or switches and now have a "tilt sensor" input to your Arduino which you can use to command the display to "freeze" when the "rod" is horizontal.

If all of that is true, your problem is now software that will scan the "tilt sensor" and disable screen updates. Thank you for the software listing, but it made almost no sense to me, despite the extensive comments. Maybe someone else here can look it over, make suggestions, and get this project moving further along.
 
Bit of confusion here but what is with the two sets of code?
First is for an accelerometer and second for the tilt switch approach.
Are you trying to combine the two?
Had very little to do with accelerometers so can't comment there but in the second code, a small error in comments (neither here nor there but..)

Code:
// Tilt Sensor code for Robojax.com
#define TILT 2 // pin 2 for front-left sensor
#define LED 8 // pin 3 for front-right sensor

Perhaps barking up the wrong tree here but.........
Code:
 void loop() {
 
  int TILT_SENSED = digitalRead(TILT);// read TILT sensor

  // if tilt is sensed
  if( TILT_SENSED ==LOW)
  {
   digitalWrite(LED,HIGH);// set the LED pin HIGH and buzzer will buzz
   Serial.println("Tilt detected");
  }else{
   digitalWrite(LED,LOW); // Set the LED pin LOW to turn it OFF or buzzer OFF
   updateDisplay();
   Serial.println("Normal");
  }
Still don't know why you would want to freeze the display, other indicator such as the LED would suffice.
No need for a uC or code .......
Looks to me like your serial prints might be reversed also (depends on your point of view I guess)
 
Last edited:

hevans1944

Hop - AC8NS
@Bluejets, we may have a language problem here since the OP is from India. Maybe a cultural problem too. After spending the last eighteen of my working years working with and for these people, I can assure you that their view of the world is... different. Perhaps @tarun71gaur is reluctant to reveal WTF he is trying to DO because he does not want to admit that he doesn't have a clue.

From what I have been able to gather, guess, and rectally extract so far, the "instrument I am trying to work around" is some sort of medical device that is portable, or at least movable on wheels, and that someone has attached to it a small arm on a pivot. Somehow the base of this instrument moves around (hence the surmise that it's portable or on wheels) and he wants to know where the base is when the arm is horizontal, or presumably parallel to the floor. Not a clue as to when, where, or what moves the arm. This display freezing consideration appears to be after-the-fact of adding the Arduino, the OLED readout, and the rate gyroscope/accelerometer module to whatever is moving around and needs position information recorded when the "arm-on-a-pivot" is horizontal. It appears he doesn't know much about the interface between the display and the Arduino to allow the update of the display to be interrupted and held for inspection. Sounds like a "monkey see, monkey do" approach to design, with cut-and-paste from various sources to create a mélange of functionality. Two libraries are cited as include files, wire.h and u8glib.h, but so far with no explanation or documentation about where these libraries came from or how to use them.

Personally, I have been looking for a free, off-the-shelf, Arduino "sketch" for a touch LCD shield I purchased several years ago, when I first began playing with Arduino, but I saw nothing in posted code that indicates how an OLED alphanumeric display (presumably an SSD1306, 128x64 display) uses the u8glib.h library, much less how this display connects and communicates with the Arduino, or where to obtain the library code. Perhaps this link, provided by this Google search would help, but I don't have time to reverse engineer this project.

I have no experience with modern accelerometers or rate gyroscopes implemented with MEMS technology, but the devices are ubiquitous in cell phones, among other applications. There is a company (a subsidiary of Japanese TDK Corporation) in California, USA, that seems to have a "lock" on manufacturing through patents and proprietary techniques (closely guarded trade secrets... the ONLY way to protect IP IMHO). There is a nice website that showcases their product line. Visit TDK InvenSense here. You might also want to visit the TDK website... they manufacture a fascinating line of electronics products.

I do have some experience with precision rate gyroscopes of the electro-mechanical persuasion. We used three of these, orthogonal mounted, as an inertial reference while tracking targets between radar "lock on" and just before firing the 20mm Gatling gun. This allowed the B-52H bomber to perform all sorts of maneuvers, called "jinks" in a effort to evade bullets and missiles fired at it from fighter interceptor aircraft approaching from the rear while the gyros kept the B-52H guns pointed at the target.

Mechanical rate gyroscopes were not very accurate long-term (days and weeks versus seconds and minutes) inertial guidance components. They also take a loooong time to warm up and reach operational temperatures significantly higher than ambient. IIRC, it took almost an hour for the gyros I worked with to become ready. Unlike the familiar "toy" gyroscope, which is free to move and precess in any direction, these rate gyros were "caged" until ready for use. After uncaging, a torque motor inside the gyro kept the output axis constrained from precession by using feedback from a resolver (that sensed axis rotation) to control the torque motor that restored the output axis to its original position. Thus the amount of current in the torque motor was proportional to the precession and therefore proportional also to the rate at which the gyro was rotated about its input axis.

IIRC, the long-term accuracy problem had to do with the long-term drift of analog integrators used to convert angular rate into total angle of motion. The same problem held with accelerometers used to measure linear motion. The integral of acceleration is velocity, and the integral of velocity yields distance... provided of course that your integrating electronics doesn't drift and add error to your distance measurement. Today this is mostly avoided by digitizing the "signal" and performing the integration as a series of time-sampled sums. With a sufficiently "long enough" register to hold the added sums, integration could occur over weeks or months without error caused by integrator drift.

Another reason for better accuracy today is we now have GPS to determine location and distance traveled. Missiles in silos don't need their inertial navigation systems updated (they already know where they are) but missiles on submarines, or ships at sea, or on movable platforms (like the Pershing IRBM) need to be updated just prior to launch. GPS is just one way to do that. Or you can manually type in latitude, longitude, and altitude coordinates taken from a paper map or obtained by other means.

I am somewhat curious about the InvenSense nine-axis package with built-in Digital Motion Processor (DMP). The DMP is supposed to relieve the off-chip computational load by crunching the raw transducer data on-board the MEMS integrated circuit. I haven't had time to explore this in depth, much less order one to play with at home. If I decide to explore this rabbit hole, it will be in conjunction with high-resolution GPS surveying to allow movement between surveyed GPS locations without having to maintain a GPS "fix". Some earth-moving equipment already augments GPS location by tying in odometer readings with IMU data, so it's not like I am inventing the wheel. Just trying to build a more affordable wheel that does the same thing as the high-priced commercial units, cheaper but with comparable accuracy.

Edit: Took a look at Digi-Key for IMU devices... found hundreds listed. So InvenSense doesn't have a "lock" on the production. Might want to look at bundled development kits first though if wanting to "roll yer own" or just experiment with the technology. I should have realized the devices were everywhere in drones now... <sigh> It's becoming hard to keep up with the tech advancing so rapidly now.
 
Last edited:
, we may have a language problem here since the OP is from India. Maybe a cultural problem too..

Incidentally India is the second largest nation of English speaking people in the world.
India's official second language.
Also maybe we British messing around there for 300+ years had some cultural effect!:D
M.
 
Last edited:

hevans1944

Hop - AC8NS
...maybe we British messing around there for 300+ years had some cultural effect...
Well, it sure as hell screwed up their English. It's too bad neither Australia nor the USA had territorial ambitions in India at the time. OTOH, it's a "good thing" that English (veddy British version, eh wat?) is their official second language, because most folks have no interest in learning Hindi or whatever passes for their official first language. Actually, India has twenty-something "official" languages, but only Hindi and English are mandated by their Constitution.
 
I have many East Indian friends and have no problem conversing with them at all!;)
BTW the British first showed up in India before the Puritans landed in the Americas. And Australia was not settled at that time.
The initial reason for the exploration of trade was the 'over night' hike in the price of pepper by the Dutch!
The British Raj came a little later.
M.
 
What accuracy of horizontal do you need? And will it be important to establish a dead band to avoid the repeated switching between the horizontal and non-horizontal state?
 

bertus

Moderator
Hello,

How about a potmeter?
From the sensor booklet of Forrest Mims:

tilt measurement.png

The voltage will give you a measure for the angle.
You could use a window comparator to see if the platform is to high or to low.

Bertus
 
Top