MRPT / mrpt

:zap: The Mobile Robot Programming Toolkit (MRPT)
https://docs.mrpt.org/reference/latest/
BSD 3-Clause "New" or "Revised" License
1.94k stars 630 forks source link

Add RTIMULib support for low-end IMU devices #189

Open jolting opened 8 years ago

jolting commented 8 years ago

RTIMULib supports many cheap IMUs. RTIMULib would be a great addition to mrpt's limited set of supported IMU libraries because it would allow mrpt to support a significant number of IMUs.

It implements the i2c/spi communication, which is necessary to communicate with most cheap IMUs. There is also a program for creating calibration data for the sensor inputs, which is necessary for accurate readings. Additionally, it has a couple of methods for sensor fusion which provides similar data to what is outputted by devices like XSens.

Here is an example how to read the IMU data from a precalibrated sensor. https://github.com/richards-tech/RTIMULib2/blob/master/Linux/RTIMULibDrive/RTIMULibDrive.cpp

RTIMU_DATA is defined like this:

typedef struct
{
    uint64_t timestamp;
    bool fusionPoseValid;
    RTVector3 fusionPose;
    bool fusionQPoseValid;
    RTQuaternion fusionQPose;
    bool gyroValid;
    RTVector3 gyro;
    bool accelValid;
    RTVector3 accel;
    bool compassValid;
    RTVector3 compass;
    bool pressureValid;
    RTFLOAT pressure;
    bool temperatureValid;
    RTFLOAT temperature;
    bool humidityValid;
    RTFLOAT humidity;
} RTIMU_DATA;

XYZ components can be accessed like this.

imuData.fusionPose.x();
imuData.fusionPose.y();
imuData.fusionPose.z();
jlblancoc commented 8 years ago

Thanks for the recommendation, didn't know that lib. Will take a look at it for the release after the next one.

Do you know if it works in both Windows and GNU/Linux?

jolting commented 8 years ago

I think the problem you run into with Windows is there isn't a standard i2c interface. On Linux your i2c buses show up as /dev/i2c-%d

In RTIMUHal.cpp they have some stub code for implementing a windows version.

Your best bet for windows is using an Arduino for i2c. You can use RTArduLinkIMU. I don't have an experience with that though, but with a breadboard, an imu, some wires and an arduino you have a cheap system.

jlblancoc commented 8 years ago

Thanks! I prefer to always offer consistent features and API for Linux & Windows, but if some feature is only easily available in Linux, we can live with it ;-)

jolting commented 8 years ago

I was thinking about the parity with Windows. What about an I2C abstraction layer?

I found this: https://msdn.microsoft.com/en-us/library/windows.devices.i2c.aspx

It appears to be support on the Raspberry Pi 2 and the MinnowBoard Max on Windows, but I don't know if it supports any Desktop hardware.

In Linux it's really low level. You create an array of commands and call an ioctl on an i2c device.

struct i2c_msg {
        __u16 addr;     /* slave address                        */
        __u16 flags;
#define I2C_M_TEN               0x0010  /* this is a ten bit chip address */
#define I2C_M_RD                0x0001  /* read data, from slave to master */
#define I2C_M_STOP              0x8000  /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_NOSTART           0x4000  /* if I2C_FUNC_NOSTART */
#define I2C_M_REV_DIR_ADDR      0x2000  /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_IGNORE_NAK        0x1000  /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_NO_RD_ACK         0x0800  /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_RECV_LEN          0x0400  /* length will be first received byte */
        __u16 len;              /* msg length                           */
        __u8 *buf;              /* pointer to msg data                  */
};
struct i2c_rdwr_ioctl_data {
         struct i2c_msg __user *msgs;    /* pointers to i2c_msgs */
         __u32 nmsgs;                    /* number of i2c_msgs */
};

libi2c-dev on Ubuntu installs a header file which contains a bunch of helper functions. /usr/include/linux/i2c-dev.h

jlblancoc commented 8 years ago

Is libi2c-dev a dependency of RTIMULib ?

I think such a low-level thing could be left as supported in Linux only without being a big deal...

jolting commented 8 years ago

No, the libi2c-dev isn't necessary. It's just a bunch of helper functions.

The helper functions mimic the internal kernel interface. http://lxr.free-electrons.com/source/drivers/i2c/i2c-core.c

There are tons of ways to access your I2C from userspace: http://lxr.free-electrons.com/source/Documentation/i2c/dev-interface

RTIMULib uses write(), read() and uses an ioctl to switch between the slave addresses.

Simply reading a byte using i2c requires 1 write(to set the address of the register) and 1 read(to get the byte). I believe the I2C_RDWR ioctl is probably the best for streaming over i2c, since it allows you to dispatch multiple read/writes with a single ioctl without stopping. RTIMULib doesn't use I2C_RDWR.

jlblancoc commented 8 years ago

Due to the overwhelming number of open fronts, I think this feature request can be dropped as a blocker to "milestone 1.5.0"...

jolting commented 8 years ago

@jlblancoc Agreed