8 #include <linux/i2c-dev.h> 15 int main(
int argc,
char** argv) {
17 auto commandlineArguments = cluon::getCommandlineArguments(argc, argv);
19 if (0 == commandlineArguments.count(
"dev") || 0 == commandlineArguments.count(
"freq") ||
20 0 == commandlineArguments.count(
"cid") || 0 == commandlineArguments.count(
"verbose")) {
21 std::cerr <<
"argv[0] reads inputs from the IMU Sensors and transmits them to the car's components." 23 std::cerr <<
"Usage: " << argv[0] <<
" --dev=<path toIMU> --freq=<int Frequency> --cid=<OD4Session Session>" 25 std::cerr <<
"Example: " << argv[0] <<
" --dev=/dev/i2c-2 --freq=100 --cid=200 " << std::endl;
29 const std::string DEV = commandlineArguments[
"dev"];
30 std::cout << DEV << std::endl;
31 const uint16_t CID = (uint16_t) std::stoi(commandlineArguments[
"cid"]);
32 const float FREQ = std::stof(commandlineArguments[
"freq"]);
33 const bool VERBOSE = commandlineArguments.count(
"verbose") != 0;
35 int16_t deviceFile = open(DEV.c_str(), O_RDWR);
38 std::cerr <<
"Failed to open the i2c bus." << std::endl;
42 initializeMpu(deviceFile);
43 initializeAK8963(deviceFile);
44 setGyroOffset(calibrateMPU9250(deviceFile), deviceFile);
46 cluon::OD4Session od4{CID};
48 auto atFrequency{[&deviceFile, &VERBOSE, &od4]() ->
bool {
49 opendlv::proxy::GyroscopeReading gyroscopeReading = readGyroscope(deviceFile);
50 od4.send(gyroscopeReading);
52 opendlv::proxy::AccelerationReading accelerometerReading = readAccelerometer(deviceFile);
53 od4.send(accelerometerReading);
55 opendlv::proxy::MagneticFieldReading magnetometerReading = readMagnetometer(deviceFile);
56 od4.send(magnetometerReading);
58 opendlv::proxy::AltitudeReading altimeterReading = readAltimeter(deviceFile);
59 od4.send(altimeterReading);
61 opendlv::proxy::TemperatureReading thermometerReading = readThermometer(deviceFile);
62 od4.send(thermometerReading);
65 std::cout <<
"[OD4] Sending IMU data: " << std::endl
67 " X: " << gyroscopeReading.GyroscopeReadingX() <<
68 " Y: " << gyroscopeReading.GyroscopeReadingY() <<
69 " Z: " << gyroscopeReading.GyroscopeReadingZ() << std::endl
70 <<
"Accelerometer -" <<
71 " X: " << accelerometerReading.accelerationX() <<
72 " Y: " << accelerometerReading.accelerationY() <<
73 " Z: " << accelerometerReading.accelerationZ() << std::endl
75 " X: " << magnetometerReading.magneticFieldX() <<
76 " Y: " << magnetometerReading.magneticFieldY() <<
77 " Z: " << magnetometerReading.magneticFieldZ() << std::endl
79 " Altitude: " << altimeterReading.altitude() << std::endl
81 " Temperature: "<< thermometerReading.temperature() << std::endl;
85 od4.timeTrigger(FREQ, atFrequency);
90 int8_t i2cAccessDevice(int16_t deviceFile, uint8_t
const addr) {
91 if (ioctl(deviceFile, I2C_SLAVE, addr) < 0) {
92 std::cerr <<
"[MPU9250] Failed to acquire bus access or talk to slave device. " << std::endl;
98 int8_t i2cWriteRegister(std::vector<uint8_t> a_data, int16_t deviceFile) {
99 uint8_t* buffer = a_data.data();
101 uint8_t status = write(deviceFile, buffer, a_data.size());
103 if (status != a_data.size()) {
104 std::cerr <<
"[MPU9250] Failed to write on I2C bus." << std::endl;
110 int8_t i2cReadRegister(int16_t deviceFile, uint8_t
const addr, uint8_t *data, uint8_t
const length) {
113 uint8_t statusOut = write(deviceFile, buffer, 1);
114 uint8_t statusIn = read(deviceFile, data, length);
115 if (statusOut != 1 || statusIn != length) {
116 std::cerr <<
"[MPU9250] Failed to read I2C on bus." << std::endl;
122 void initializeMpu(int16_t deviceFile) {
125 uint8_t addr = MPU9250_ADDRESS;
126 i2cAccessDevice(deviceFile, addr);
127 uint8_t reg = MPU9250::PWR_MGMT_1;
128 i2cWriteRegister(std::vector<uint8_t>{reg,0x00}, deviceFile);
133 i2cWriteRegister(std::vector<uint8_t>{reg,0x01}, deviceFile);
144 reg = MPU9250::CONFIG;
145 i2cWriteRegister(std::vector<uint8_t>{reg,0x03}, deviceFile);
150 reg = MPU9250::SMPLRT_DIV;
151 i2cWriteRegister(std::vector<uint8_t>{reg, 0x04}, deviceFile);
159 reg = MPU9250::GYRO_CONFIG;
160 i2cReadRegister(deviceFile, reg, &c, 1);
163 c = c | m_gscale << 3;
165 i2cWriteRegister(std::vector<uint8_t>{reg, c}, deviceFile);
169 reg = MPU9250::ACCEL_CONFIG;
170 i2cReadRegister(deviceFile, reg, &c, 1);
172 c = c | m_ascale << 3;
174 i2cWriteRegister(std::vector<uint8_t>{reg, c}, deviceFile);
181 reg = MPU9250::ACCEL_CONFIG2;
182 i2cReadRegister(deviceFile, reg, &c, 1);
186 i2cWriteRegister(std::vector<uint8_t>{reg, c}, deviceFile);
195 reg = MPU9250::INT_PIN_CFG;
196 i2cWriteRegister(std::vector<uint8_t>{reg, 0x22}, deviceFile);
198 reg = MPU9250::INT_ENABLE;
199 i2cWriteRegister(std::vector<uint8_t>{reg, 0x01}, deviceFile);
203 void initializeAK8963(int16_t deviceFile) {
206 i2cWriteRegister(std::vector<uint8_t>{MPU9250::AK8963_CNTL, 0x00}, deviceFile);
208 i2cWriteRegister(std::vector<uint8_t>{MPU9250::AK8963_CNTL, 0x0F}, deviceFile);
210 i2cReadRegister(deviceFile, MPU9250::AK8963_ASAX, &rawData[0], 3);
211 i2cWriteRegister(std::vector<uint8_t>{MPU9250::AK8963_CNTL, 0x00}, deviceFile);
216 i2cWriteRegister(std::vector<uint8_t>{MPU9250::AK8963_CNTL, 1 << 4 | 0110}, deviceFile);
220 std::vector<float> calibrateMPU9250(int16_t deviceFile) {
222 std::cout <<
"[MPU9250] Starting calibration...\n";
225 i2cAccessDevice(deviceFile, MPU9250_ADDRESS);
227 i2cWriteRegister(std::vector<uint8_t>{MPU9250::PWR_MGMT_1, 0x80}, deviceFile);
229 i2cWriteRegister(std::vector<uint8_t>{MPU9250::PWR_MGMT_1, 0x01}, deviceFile);
230 i2cWriteRegister(std::vector<uint8_t>{MPU9250::PWR_MGMT_2, 0x00}, deviceFile);
233 i2cWriteRegister(std::vector<uint8_t>{MPU9250::INT_ENABLE, 0x00}, deviceFile);
234 i2cWriteRegister(std::vector<uint8_t>{MPU9250::FIFO_EN, 0x00}, deviceFile);
235 i2cWriteRegister(std::vector<uint8_t>{MPU9250::PWR_MGMT_1, 0x00}, deviceFile);
236 i2cWriteRegister(std::vector<uint8_t>{MPU9250::I2C_MST_CTRL, 0x00}, deviceFile);
237 i2cWriteRegister(std::vector<uint8_t>{MPU9250::USER_CTRL, 0x00}, deviceFile);
238 i2cWriteRegister(std::vector<uint8_t>{MPU9250::USER_CTRL, 0x0C}, deviceFile);
241 i2cWriteRegister(std::vector<uint8_t>{MPU9250::CONFIG, 0x01}, deviceFile);
242 i2cWriteRegister(std::vector<uint8_t>{MPU9250::SMPLRT_DIV, 0x00}, deviceFile);
243 i2cWriteRegister(std::vector<uint8_t>{MPU9250::GYRO_CONFIG, 0x00}, deviceFile);
244 i2cWriteRegister(std::vector<uint8_t>{MPU9250::ACCEL_CONFIG, 0x00}, deviceFile);
246 float const gyroSens = (250.0f / 32768.0f *
static_cast<float>(M_PI) / 180.0f);
248 i2cWriteRegister(std::vector<uint8_t>{MPU9250::USER_CTRL, 0x40}, deviceFile);
249 i2cWriteRegister(std::vector<uint8_t>{MPU9250::FIFO_EN, 0x78}, deviceFile);
251 i2cWriteRegister(std::vector<uint8_t>{MPU9250::FIFO_EN, 0x00}, deviceFile);
253 i2cReadRegister(deviceFile, MPU9250::FIFO_COUNTH, &rawData[0], 2);
255 uint16_t fifoCount = ((uint16_t) rawData[0] << 8) | rawData[1];
256 std::cout <<
"[MPU9250] FIFO Count: " << fifoCount << std::endl;
257 uint16_t packetCount = fifoCount/12;
258 std::cout <<
"[MPU9250] Packet Count: " << packetCount << std::endl;
260 int32_t gyroBias[3] = {0,0,0};
261 for (uint8_t i = 0; i < packetCount; i++) {
262 int16_t gyroSampl[3] = {0,0,0};
263 i2cReadRegister(deviceFile, MPU9250::FIFO_R_W, &rawData[0], 12);
265 gyroSampl[0] = (int16_t) (((int16_t)rawData[6] << 8) | rawData[7] );
266 gyroSampl[1] = (int16_t) (((int16_t)rawData[8] << 8) | rawData[9] );
267 gyroSampl[2] = (int16_t) (((int16_t)rawData[10] << 8) | rawData[11]);
269 gyroBias[0] += (int32_t) gyroSampl[0];
270 gyroBias[1] += (int32_t) gyroSampl[1];
271 gyroBias[2] += (int32_t) gyroSampl[2];
274 gyroBias[0] /= packetCount;
275 gyroBias[1] /= packetCount;
276 gyroBias[2] /= packetCount;
280 std::vector<float> gyroBiasVec;
281 gyroBiasVec.push_back(gyroBias[0] * gyroSens);
282 gyroBiasVec.push_back(gyroBias[1] * gyroSens);
283 gyroBiasVec.push_back(gyroBias[2] * gyroSens);
284 std::cout <<
"[MPU9250] Gyro bias: " << gyroBiasVec.at(0) <<
", " << gyroBiasVec.at(1) <<
", " << gyroBiasVec.at(2) << std::endl;
288 int8_t setGyroOffset(std::vector<float>
const a_offset, int16_t deviceFile) {
289 if (a_offset.size() != 3) {
290 std::cerr <<
"[MPU9250] setGyroOffset received a vector of a length not supported." << std::endl;
294 float const gyroSens = (250.0f / 32768.0f *
static_cast<float>(M_PI) / 180.0f);
296 int32_t xOffset = std::lround(a_offset.at(0) / gyroSens);
297 int32_t yOffset = std::lround(a_offset.at(1) / gyroSens);
298 int32_t zOffset = std::lround(a_offset.at(2) / gyroSens);
300 uint8_t xh = (-xOffset/4 >> 8);
301 uint8_t xl = ((-xOffset/4) & 0xFF);
302 uint8_t yh = (-yOffset/4 >> 8);
303 uint8_t yl = ((-yOffset/4) & 0xFF);
304 uint8_t zh = (-zOffset/4 >> 8);
305 uint8_t zl = ((-zOffset/4) & 0xFF);
307 i2cAccessDevice(deviceFile, MPU9250_ADDRESS);
308 i2cWriteRegister(std::vector<uint8_t>{MPU9250::XG_OFFSET_H, xh, xl, yh, yl, zh, zl}, deviceFile);
313 opendlv::proxy::AccelerationReading readAccelerometer(int16_t deviceFile) {
314 uint8_t addr = MPU9250_ADDRESS;
315 i2cAccessDevice(deviceFile, addr);
316 uint8_t reg = MPU9250::ACCEL_XOUT_H;
318 i2cReadRegister(deviceFile, reg, &rawData[0], 6);
320 float const c = getAscale();
322 int16_t x = (((int16_t)rawData[0] << 8) | rawData[1] );
323 int16_t y = (((int16_t)rawData[2] << 8) | rawData[3] );
324 int16_t z = (((int16_t)rawData[4] << 8) | rawData[5] );
325 opendlv::proxy::AccelerationReading accelerometerReading;
326 accelerometerReading.accelerationX(x*c);
327 accelerometerReading.accelerationY(y*c);
328 accelerometerReading.accelerationZ(z*c);
329 return accelerometerReading;
332 opendlv::proxy::MagneticFieldReading readMagnetometer(int16_t deviceFile) {
333 uint8_t addr = AK8963_ADDRESS;
334 i2cAccessDevice(deviceFile, addr);
335 uint8_t reg = MPU9250::AK8963_XOUT_L;
337 i2cReadRegister(deviceFile, reg, &rawData[0], 7);
339 float const c = getMscale();
341 int16_t x = (((int16_t) rawData[0] << 8) | rawData[1]);
342 int16_t y = (((int16_t) rawData[2] << 8) | rawData[3]);
343 int16_t z = (((int16_t) rawData[4] << 8) | rawData[5]);
345 opendlv::proxy::MagneticFieldReading magneticFieldReading;
346 magneticFieldReading.magneticFieldX(x);
347 magneticFieldReading.magneticFieldY(y);
348 magneticFieldReading.magneticFieldZ(z);
350 return magneticFieldReading;
353 opendlv::proxy::GyroscopeReading readGyroscope(int16_t deviceFile) {
354 uint8_t addr = MPU9250_ADDRESS;
355 i2cAccessDevice(deviceFile, addr);
356 uint8_t reg = MPU9250::GYRO_XOUT_H;
358 i2cReadRegister(deviceFile, reg, &rawData[0], 6);
360 float const c = getGscale(
true);
362 int16_t x = (((int16_t)rawData[0] << 8) | rawData[1] );
363 int16_t y = (((int16_t)rawData[2] << 8) | rawData[3] );
364 int16_t z = (((int16_t)rawData[4] << 8) | rawData[5] );
366 opendlv::proxy::GyroscopeReading gyroscopeReading;
367 gyroscopeReading.GyroscopeReadingX(x*c);
368 gyroscopeReading.GyroscopeReadingY(y*c);
369 gyroscopeReading.GyroscopeReadingZ(z*c);
370 return gyroscopeReading;
373 opendlv::proxy::AltitudeReading readAltimeter(int16_t deviceFile) {
374 opendlv::proxy::AltitudeReading altimeterReading;
375 altimeterReading.altitude(0);
376 return altimeterReading;
379 opendlv::proxy::TemperatureReading readThermometer(int16_t deviceFile) {
380 uint8_t addr = MPU9250_ADDRESS;
381 i2cAccessDevice(deviceFile, addr);
382 uint8_t reg = MPU9250::TEMP_OUT_H;
384 i2cReadRegister(deviceFile, reg, &rawData[0], 2);
386 int16_t temp = (((int16_t)rawData[0] << 8) | rawData[1]) / 1.0f;
388 opendlv::proxy::TemperatureReading temperatureReading;
389 temperatureReading.temperature(21.0f + temp / 333.87f);
391 return temperatureReading;
394 float getGscale(
bool a_radFlag) {
395 float conversion = 1;
397 conversion =
static_cast<float>(M_PI) / 180.0f;
401 return (250.0f / 32768.0f) * conversion;
403 return (500.0f / 32768.0f) * conversion;
405 return (1000.0f / 32768.0f) * conversion;
407 return (2000.0f / 32768.0f) * conversion;
416 return (9.82f * 2.0f / 32768.0f);
418 return (9.82f * 4.0f / 32768.0f);
420 return (9.82f * 8.0f / 32768.0f);
422 return (9.82f * 16.0f / 32768.0f);
433 return 10.0f * 4912.0f / 8190.0f;
435 return 10.0f * 4912.0f / 32760.0f;