bolderflight / invensense-imu

Arduino and CMake library for communicating with the InvenSense MPU-6500, MPU-9250 and MPU-9255 nine-axis IMUs.
MIT License
508 stars 213 forks source link

Magnetometer Values are wrong on NodeMcu esp8266 when used with ROS #74

Closed hex-plex closed 4 years ago

hex-plex commented 4 years ago

I Have used I2C communication on the nodemcu with MPU9250 . The output is correct when i run the example sketches. The board works well with Ros serial and its Wireless implementation as well (that is i have tried it out and it sends in any value fine). The problem is reading of one of the axis of magnetometer is like -1e+34. I checked the reading using serial terminal while ros topic was being published through wifi and it was this big value being read. This is the code i am using.

#include "MPU9250.h"
#include <ros.h>
#include <sensor_msgs/Imu.h>
#include <sensor_msgs/MagneticField.h>
#include <std_msgs/String.h>
#include <Wire.h>
#ifdef ESP8266
  #include <ESP8266WiFi.h>
  const char* ssid = "No";
  const char* pass = "abcdq1987654";
  IPAddress server(192,168,43,18);
  const uint16_t serverPort = 11411;
#endif 
MPU9250* IMU;
int stat;
ros::NodeHandle nh;

sensor_msgs::Imu msg_dat;
sensor_msgs::MagneticField mag_dat;
ros::Publisher raw("imu/data_raw",&msg_dat);
ros::Publisher mag("imu/mag",&mag_dat);
void setup() {
#ifdef ESP8266
  Wire.begin(); //D1,D2);
  Serial.begin(115200);
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid,pass);
  while(WiFi.status()!=WL_CONNECTED){
      delay(500);
      Serial.print(".");
    }
  nh.getHardware() -> setConnection(server,serverPort);
  nh.initNode();
  Serial.print("IP = ");
  Serial.println(nh.getHardware()->getLocalIP());

#else
  Wire.begin();
  nh.initNode();
#endif
  IMU = new MPU9250(&Wire,(uint8_t)0x68);
  while(!nh.connected()){
      nh.spinOnce();
    }
  stat = IMU->begin();
  char buff[7];
  if(stat<0){
      nh.logfatal("IMU initialization unsuccessful");
      nh.logerror("Check IMU wiring or try cycling power");
      itoa(stat,buff,10);
      nh.loginfo(strcat("Status: ",buff));
      while(1){nh.spinOnce();delay(1000);}  // Nodemcu doesnt like empty while loops
    }
  nh.advertise(raw);
  nh.advertise(mag);
  msg_dat.header.frame_id="/case_link";
  mag_dat.header.frame_id="/chase_link";
  msg_dat.orientation.x=0;msg_dat.orientation.y=0;msg_dat.orientation.z=0;msg_dat.orientation.w=0;
  for(int i=0;i<9;i++)msg_dat.orientation_covariance[i] =-1;
  for(int i=0;i<9;i++)msg_dat.angular_velocity_covariance[i]=0;
  for(int i=0;i<9;i++)msg_dat.linear_acceleration_covariance[i] = 0;
  for(int i=0;i<9;i++)mag_dat.magnetic_field_covariance[i] = 0;
}

void loop() {
  if(nh.connected()){
    IMU->readSensor();
    msg_dat.angular_velocity.x = IMU->getGyroX_rads();
    msg_dat.angular_velocity.y = IMU->getGyroY_rads();
    msg_dat.angular_velocity.z = IMU->getGyroZ_rads();
    msg_dat.linear_acceleration.x = IMU->getAccelX_mss();
    msg_dat.linear_acceleration.y = IMU->getAccelY_mss();
    msg_dat.linear_acceleration.z = IMU->getAccelZ_mss();
    mag_dat.magnetic_field.x = IMU->getMagX_uT();
    mag_dat.magnetic_field.y = IMU->getMagY_uT();
    mag_dat.magnetic_field.z = IMU->getMagZ_uT();
    mag_dat.header.stamp = nh.now();
    msg_dat.header.stamp = nh.now();
    mag.publish(&mag_dat);
    raw.publish(&msg_dat);
  }else{
    Serial.println(".");
    delay(100);  
  }
  nh.spinOnce();
  delay(50);
}

And a Important thing to tell is that i modded the library files to takein the pointer of the Twowire object and not run _i2c->begin , so that i would not be running it twice begin as i tried different ports of Wire.begin(D5,D6) and soon. I believe the problem is to do with the value of float being used or interpreted and calculated in a way suitable for a 8 bit Processor and not generalizing for 32 Bit Processor and due to some hickups in performance the value is being calculated wrong or being bit shifted. This is a demo output of ROS node that i am receiveing from it. The problem only exits for magnetometer and not for Accel or gyro. Thanks in advanced.

---
header: 
  seq: 15151
  stamp: 
    secs: 1601909944
    nsecs: 921860963
  frame_id: "/chase_link"
magnetic_field: 
  x: 24.4541053772
  y: 84.6991043091
  z: -1.03845937171e+34
magnetic_field_covariance: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
---
header: 
  seq: 15152
  stamp: 
    secs: 1601909944
    nsecs: 973860963
  frame_id: "/chase_link"
magnetic_field: 
  x: 24.4541053772
  y: 84.6991043091
  z: -1.03845937171e+34
magnetic_field_covariance: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
---
flybrianfly commented 4 years ago

All of our libraries were developed and tested on the Teensy 3.x and LC line of 32 bit microcontrollers. I don't have any experience with ESP8266 or ROS. I would try to see if the unmodified library example outputs reasonable magnetometer values to the serial monitor as a starting point for debugging.

hex-plex commented 4 years ago

Yes the modification doesnt make any difference both work perfectly as expected even the ros topics work but the code that has both together just fails to work by giving a random value like this. I initially thought ROS took up the heap memory overflow there where wrong values outputted.

Executable segment sizes:
IROM   : 256700          - code in flash         (default or ICACHE_FLASH_ATTR) 
IRAM   : 28220   / 32768 - code in IRAM          (ICACHE_RAM_ATTR, ISRs...) 
DATA   : 1268  )         - initialized variables (global, static) in RAM/HEAP 
RODATA : 1452  ) / 81920 - constants             (global, static) in RAM/HEAP 
BSS    : 28736 )         - zeroed variables      (global, static) in RAM/HEAP 

But that is not the case as well i thought there were some pins that was intefering with I2C but i disabled anykind of serial communication from ROS libs as well only have one serial port (the standard Uart over usb one) at 11500 the one that you can see in the code. I thought many cases were it would be caused in the ros side of the things but i couldnt find one. So i what i was thinking is that there is some error in calculation from the processor as it may be liitle too resource intensive or something but that didnt make any sense to me . So for now i have been debugging this for a pretty good amount of time and i can say ROS is working MPU9250 library is working but them together is causing some kind of interference. I even tried it with Arduino Mega where in i was getting 2 values with this mutated form (with the ros obviously the them seperately work well and ros delievers the right message as i tried trivial zeros and ones which it passes through well but the sensor reading is messaged up). So could you say me if there is some specific memory locations that your library tries to access that is not allocated and reserved for itself so that i can debug further Thanking you

flybrianfly commented 4 years ago

All memory allocation occurs in the constructor and the library doesn't access memory outside of its class.

hex-plex commented 4 years ago

Yes I believe the problem is not the MPU9250 library but the esp8266/arduino compiler as WiFi and I2C interfere #1331 was a issue in their repo. And i have not been able to trackdown the version of it which worked for them . I did try SPI as well but i guess i have no more luck down this lane.