Created
November 26, 2018 12:09
-
-
Save satakagi/493d4e6277c92080c60dffb7c1f17926 to your computer and use it in GitHub Desktop.
MPU9250/MPU9255 driver
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Ported from https://github.com/tuupola/micropython-mpu9250/blob/master/ak8963.py | |
// by Satoru Takagi | |
var AK8963 = function(i2cPort,slaveAddress){ | |
this.devConst={ | |
_WIA : (0x00), | |
_HXL : (0x03), | |
_HXH : (0x04), | |
_HYL : (0x05), | |
_HYH : (0x06), | |
_HZL : (0x07), | |
_HZH : (0x08), | |
_ST2 : (0x09), | |
_CNTL1 : (0x0a), | |
_ASAX : (0x10), | |
_ASAY : (0x11), | |
_ASAZ : (0x12), | |
_MODE_POWER_DOWN : 0b00000000, | |
MODE_SINGLE_MEASURE : 0b00000001, | |
MODE_CONTINOUS_MEASURE_1 : 0b00000010, // 8Hz | |
MODE_CONTINOUS_MEASURE_2 : 0b00000110, // 100Hz | |
MODE_EXTERNAL_TRIGGER_MEASURE : 0b00000100, | |
_MODE_SELF_TEST : 0b00001000, | |
_MODE_FUSE_ROM_ACCESS : 0b00001111, | |
OUTPUT_14_BIT : 0b00000000, | |
OUTPUT_16_BIT : 0b00010000, | |
_SO_14BIT : 0.6, // μT per digit when 14bit mode | |
_SO_16BIT : 0.15 // μT per digit when 16bit mode | |
} | |
this.i2cPort = i2cPort; | |
this.i2cSlave = null; | |
if ( slaveAddress ){ | |
this.slaveAddress = slaveAddress; | |
} else { | |
this.slaveAddress = 0x0c; | |
} | |
}; | |
AK8963.prototype = { | |
init: async function(mode,output,offset,scale){ | |
var cs = this.devConst; | |
if ( !mode){ | |
mode=cs.MODE_CONTINOUS_MEASURE_1; | |
} | |
if ( !output){ | |
output=cs.OUTPUT_16_BIT; | |
} | |
if ( !offset ){ | |
offset=[0, 0, 0]; | |
} | |
if ( !scale){ | |
scale=[1, 1, 1]; | |
} | |
this._offset = offset; | |
this._scale = scale; | |
this.i2cSlave = await this.i2cPort.open(this.slaveAddress); | |
var whoamiVal = await this.i2cSlave.read8(cs._WIA); | |
if ( whoamiVal ==0x48){ | |
console.log("This device is AK8963 magnetometer"); | |
} else { | |
console.log("This device is NOT Supported..."); | |
return(null); | |
} | |
// Sensitivity adjustement values | |
await this.i2cSlave.write8(cs._CNTL1, cs._MODE_FUSE_ROM_ACCESS); | |
var asax = await this.i2cSlave.read8(cs._ASAX); | |
var asay = await this.i2cSlave.read8(cs._ASAY); | |
var asaz = await this.i2cSlave.read8(cs._ASAZ); | |
await this.i2cSlave.write8(cs._CNTL1, cs._MODE_POWER_DOWN); | |
// Should wait atleast 100us before next mode | |
this._adjustement = [ | |
(0.5 * (asax - 128)) / 128 + 1, | |
(0.5 * (asay - 128)) / 128 + 1, | |
(0.5 * (asaz - 128)) / 128 + 1 | |
]; | |
// Power on | |
await this.i2cSlave.write8(cs._CNTL1, (mode | output)); | |
if (output == cs.OUTPUT_16_BIT){ | |
this._so = cs._SO_16BIT; | |
} else { | |
this._so = cs._SO_14BIT; | |
} | |
console.log("init AK8963 ok: this._adjustement :",this._adjustement ," this._so:",this._so ," this.cs:",cs); | |
}, | |
readData: async function(){ | |
var cs = this.devConst; | |
// X, Y, Z axis micro-Tesla (uT) as floats. | |
var mx = this.getVal(await this.i2cSlave.read16(cs._HXL)); // read16 is little endian | |
var my = this.getVal(await this.i2cSlave.read16(cs._HYL)); | |
var mz = this.getVal(await this.i2cSlave.read16(cs._HZL)); | |
console.log(mx,my,mz); | |
await this.i2cSlave.read8(cs._ST2) // Enable updating readings again | |
//Apply factory axial sensitivy adjustements | |
mx *= this._adjustement[0]; | |
my *= this._adjustement[1]; | |
mz *= this._adjustement[2]; | |
// Apply output scale determined in constructor | |
var so = this._so; | |
mx *= so; | |
my *= so; | |
mz *= so; | |
// Apply hard iron ie. offset bias from calibration | |
mx -= this._offset[0]; | |
my -= this._offset[1]; | |
mz -= this._offset[2]; | |
// Apply soft iron ie. scale bias from calibration | |
mx *= this._scale[0]; | |
my *= this._scale[1]; | |
mz *= this._scale[2]; | |
return { | |
x: mx, | |
y: my, | |
z: mz | |
} | |
}, | |
getVal: function( w ){ | |
// Convert to signed integer while maintaining endianness | |
// console.log("getVal:",w.toString(16)," :" , w); | |
// console.log("getVal:",w); | |
// var l = w >>> 8; | |
// var b = w & 0xff; | |
// var v = l + ( b << 8 ); | |
var v = w; | |
// console.log("Val:",w.toString(16),b.toString(16),l.toString(16),v.toString(16),b,l,v); | |
if ( v >= 0x8000 ){ | |
return ( - ((65535 - v ) + 1 ) ); | |
} else { | |
return(v); | |
} | |
}, | |
calibrate: async function (count, delay){ | |
console.log("start calibrate: "); | |
if ( !count){ | |
count=128; | |
} | |
if ( !delay){ | |
delay=100; | |
} | |
this._offset = [0, 0, 0]; | |
this._scale = [1, 1, 1]; | |
var reading = await this.readData(); | |
var minx = reading.x; | |
var miny = reading.y; | |
var minz = reading.z; | |
var maxx = minx; | |
var maxy = miny; | |
var maxz = minz; | |
while (count>0){ | |
await sleep(delay); | |
reading = await this.readData(); | |
minx = Math.min(minx, reading.x); | |
maxx = Math.max(maxx, reading.x); | |
miny = Math.min(miny, reading.y); | |
maxy = Math.max(maxy, reading.y); | |
minz = Math.min(minz, reading.z); | |
maxz = Math.max(maxz, reading.z); | |
count -= 1; | |
console.log(count," : " , reading); | |
} | |
// Hard iron correction | |
var offset_x = (maxx + minx) / 2; | |
var offset_y = (maxy + miny) / 2; | |
var offset_z = (maxz + minz) / 2; | |
this._offset = [offset_x, offset_y, offset_z]; | |
// Soft iron correction | |
var avg_delta_x = (maxx - minx) / 2; | |
var avg_delta_y = (maxy - miny) / 2; | |
var avg_delta_z = (maxz - minz) / 2; | |
var avg_delta = (avg_delta_x + avg_delta_y + avg_delta_z) / 3; | |
var scale_x = avg_delta / avg_delta_x; | |
var scale_y = avg_delta / avg_delta_y; | |
var scale_z = avg_delta / avg_delta_z; | |
this._scale = [scale_x, scale_y, scale_z]; | |
console.log("end calibrate: offset:",this._offset," scale:",this._scale ); | |
// return self._offset, self._scale | |
} | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// MPU 6500 driver | |
// Ported from | |
// https://raw.githubusercontent.com/tuupola/micropython-mpu9250/master/mpu6500.py | |
// https://github.com/tuupola/micropython-mpu9250/blob/master/mpu6500.py | |
// https://www.invensense.com/wp-content/uploads/2015/02/MPU-6000-Register-Map1.pdf | |
// https://github.com/MomsFriendlyRobotCompany/mpu9250/blob/master/mpu9250/mpu9250.py | |
// By Satoru Takagi | |
// Note: MPU9250 ( or MPU9255(almost equal to 9250)) is a chip in which MPU 6500 and AK8963 are integrated. | |
// When initializing the MPU6500 first, AK8963 with address 0x0C appears on the I2C bus. | |
var MPU6500 = function(i2cPort,slaveAddress){ | |
this.devConst={ | |
_GYRO_CONFIG : 0x1b, | |
_ACCEL_CONFIG : 0x1c, | |
_ACCEL_CONFIG2 : 0x1d, | |
_INT_PIN_CFG : 0x37, | |
_ACCEL_XOUT_H : 0x3b, | |
_ACCEL_XOUT_L : 0x3c, | |
_ACCEL_YOUT_H : 0x3d, | |
_ACCEL_YOUT_L : 0x3e, | |
_ACCEL_ZOUT_H : 0x3f, | |
_ACCEL_ZOUT_L: 0x40, | |
_TEMP_OUT_H : 0x41, | |
_TEMP_OUT_L : 0x42, | |
_GYRO_XOUT_H : 0x43, | |
_GYRO_XOUT_L : 0x44, | |
_GYRO_YOUT_H : 0x45, | |
_GYRO_YOUT_L : 0x46, | |
_GYRO_ZOUT_H : 0x47, | |
_GYRO_ZOUT_L : 0x48, | |
_WHO_AM_I : 0x75, | |
// #_ACCEL_FS_MASK : 0b00011000, | |
ACCEL_FS_SEL_2G : 0b00000000, | |
ACCEL_FS_SEL_4G : 0b00001000, | |
ACCEL_FS_SEL_8G : 0b00010000, | |
ACCEL_FS_SEL_16G : 0b00011000, | |
_ACCEL_SO_2G : 16384, // 1 / 16384 ie. 0.061 mg / digit | |
_ACCEL_SO_4G : 8192, // 1 / 8192 ie. 0.122 mg / digit | |
_ACCEL_SO_8G : 4096, // 1 / 4096 ie. 0.244 mg / digit | |
_ACCEL_SO_16G : 2048, // 1 / 2048 ie. 0.488 mg / digit | |
// #_GYRO_FS_MASK : 0b00011000, | |
GYRO_FS_SEL_250DPS : 0b00000000, | |
GYRO_FS_SEL_500DPS : 0b00001000, | |
GYRO_FS_SEL_1000DPS : 0b00010000, | |
GYRO_FS_SEL_2000DPS : 0b00011000, | |
_GYRO_SO_250DPS : 131, | |
_GYRO_SO_500DPS : 62.5, | |
_GYRO_SO_1000DPS : 32.8, | |
_GYRO_SO_2000DPS : 16.4, | |
// # Used for enablind and disabling the i2c bypass access | |
_I2C_BYPASS_MASK : 0b00000010, | |
_I2C_BYPASS_EN : 0b00000010, | |
_I2C_BYPASS_DIS : 0b00000000, | |
SF_G : 1, | |
SF_M_S2 : 9.80665,// # 1 g : 9.80665 m/s2 ie. standard gravity | |
SF_DEG_S : 1, | |
SF_RAD_S : 57.295779578552// # 1 rad/s is 57.295779578552 deg/s | |
} | |
this.i2cPort = i2cPort; | |
this.i2cSlave = null; | |
if ( slaveAddress ){ | |
this.slaveAddress = slaveAddress; | |
} else { | |
this.slaveAddress = 0x68; | |
} | |
}; | |
MPU6500.prototype = { | |
init: async function(accel_fs,gyro_fs,accel_sf,gyro_sf){ | |
var cs = this.devConst; | |
if ( !accel_fs){ | |
accel_fs=cs.ACCEL_FS_SEL_2G; | |
} | |
if ( !gyro_fs){ | |
gyro_fs=cs.GYRO_FS_SEL_250DPS; | |
} | |
if ( !accel_sf ){ | |
accel_sf=cs.SF_M_S2; | |
} | |
if ( !gyro_sf){ | |
gyro_sf=cs.SF_RAD_S; | |
} | |
this.i2cSlave = await this.i2cPort.open(this.slaveAddress); | |
var whoamiVal = await this.i2cSlave.read8(cs._WHO_AM_I); | |
if ( whoamiVal ==0x70){ | |
console.log("This device is MPU6500"); | |
} else if ( whoamiVal ==0x71){ | |
console.log("This device is MPU9250"); | |
} else if ( whoamiVal ==0x73){ | |
// https://github.com/kriswiner/MPU9250/issues/47 | |
console.log("This device is MPU9255"); | |
} else { | |
console.log("This device is NOT Supported..."); | |
return(null); | |
} | |
cs._accel_so = await this._accel_fs(accel_fs); | |
cs._gyro_so = await this._gyro_fs(gyro_fs); | |
cs._accel_sf = accel_sf; | |
cs._gyro_sf = gyro_sf; | |
console.log("init ok:"+this.i2cSlave+ " constant:",cs); | |
// await this.i2cSlave.write8(0x6B, 0x00); // clear power management | |
// # Enable I2C bypass to access for MPU9250 magnetometer access. | |
var chr = await this.i2cSlave.read8(cs._INT_PIN_CFG); | |
console.log("bypass:",chr); | |
chr &= ~cs._I2C_BYPASS_MASK; //# clear I2C bits | |
chr |= cs._I2C_BYPASS_EN; | |
console.log("bypass_:",chr); | |
await this.i2cSlave.write8(cs._INT_PIN_CFG, chr); | |
console.log("init2 ok:"); | |
}, | |
_accel_fs: async function(value){ | |
var cs = this.devConst; | |
await this.i2cSlave.write8(cs._ACCEL_CONFIG, value); | |
console.log("_accel_fs:",value); | |
//# Return the sensitivity divider | |
if (cs.ACCEL_FS_SEL_2G == value){ | |
console.log("ACCEL_FS_SEL_2G::sel"); | |
return cs._ACCEL_SO_2G; | |
} else if (cs.ACCEL_FS_SEL_4G == value){ | |
return cs._ACCEL_SO_4G; | |
} else if (cs.ACCEL_FS_SEL_8G == value){ | |
return cs._ACCEL_SO_8G; | |
} else if (cs.ACCEL_FS_SEL_16G == value){ | |
return cs._ACCEL_SO_16G; | |
} | |
}, | |
_gyro_fs: async function( value){ | |
var cs = this.devConst; | |
await this.i2cSlave.write8(cs._GYRO_CONFIG, value); | |
//# Return the sensitivity divider | |
if (cs.GYRO_FS_SEL_250DPS == value){ | |
return cs._GYRO_SO_250DPS; | |
} else if (cs.GYRO_FS_SEL_500DPS == value){ | |
return cs._GYRO_SO_500DPS; | |
} else if (cs.GYRO_FS_SEL_1000DPS == value){ | |
return cs._GYRO_SO_1000DPS; | |
} else if (cs.GYRO_FS_SEL_2000DPS == value){ | |
return cs._GYRO_SO_2000DPS; | |
} | |
}, | |
getAcceleration: async function(self){ | |
/** | |
Acceleration measured by the sensor. By default will return a | |
3-tuple of X, Y, Z axis acceleration values in m/s^2 as floats. Will | |
return values in g if constructor was provided `accel_sf=SF_M_S2` | |
parameter. | |
**/ | |
var cs = this.devConst; | |
var so = cs._accel_so; | |
var sf = cs._accel_sf; | |
var x = this.getVal(await this.i2cSlave.read16(cs._ACCEL_XOUT_H)); | |
var y = this.getVal(await this.i2cSlave.read16(cs._ACCEL_YOUT_H)); | |
var z = this.getVal(await this.i2cSlave.read16(cs._ACCEL_ZOUT_H)); | |
console.log("acc:",x,y,z," addr:",cs._ACCEL_XOUT_H," sosf:",so,sf); | |
return { | |
x: x / so * sf, | |
y: y / so * sf, | |
z: z / so * sf | |
} | |
}, | |
getGyro: async function(self){ | |
/** | |
X, Y, Z radians per second as floats. | |
**/ | |
var cs = this.devConst; | |
var so = cs._gyro_so; | |
var sf = cs._gyro_sf; | |
var x = this.getVal(await this.i2cSlave.read16(cs._GYRO_XOUT_H)); | |
var y = this.getVal(await this.i2cSlave.read16(cs._GYRO_YOUT_H)); | |
var z = this.getVal(await this.i2cSlave.read16(cs._GYRO_ZOUT_H)); | |
console.log("gyr:",x,y,z," addr:",cs._GYRO_XOUT_H," sosf:",so,sf); | |
return { | |
x: x / so * sf, | |
y: y / so * sf, | |
z: z / so * sf | |
} | |
}, | |
getVal: function( w ){ | |
var l = w >>> 8; | |
var b = w & 0xff; | |
var v = l + ( b << 8 ); | |
// console.log("Val:",w.toString(16),b.toString(16),l.toString(16),v.toString(16),b,l,v); | |
if ( v >= 0x8000 ){ | |
return ( - ((65535 - v ) + 1 ) ); | |
} else { | |
return(v); | |
} | |
} | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!doctype html> | |
<html> | |
<head> | |
<meta charset="UTF-8" /> | |
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1"> | |
<title>i2c-MPU9250</title> | |
<script src="../../../polyfill/polyfill.js"></script> | |
<script src="../../drivers/i2c-MPU6500.js"></script> | |
<script src="../../drivers/i2c-AK8963.js"></script> | |
<script src="./mainMpu92.js"></script> | |
<style> | |
table,p { | |
color: blue; | |
text-align: center; | |
font-size: 24px; | |
} | |
img { | |
position: absolute; | |
top: 50px; | |
right: 0px; | |
display: block; | |
margin-left: auto; | |
margin-right: auto; | |
} | |
</style> | |
</head> | |
<body> | |
<img src="schematic.png" width="400"> | |
<p id="head">MPU-9250</p> | |
<table> | |
<tr><td>temp</td><td id="temp"></td></tr> | |
<tr><td>Gx</td><td id="gx"></td></tr> | |
<tr><td>Gy</td><td id="gy"></td></tr> | |
<tr><td>Gz</td><td id="gz"></td></tr> | |
<tr><td>Rx</td><td id="rx"></td></tr> | |
<tr><td>Ry</td><td id="ry"></td></tr> | |
<tr><td>Rz</td><td id="rz"></td></tr> | |
<tr><td>Hx</td><td id="hx"></td></tr> | |
<tr><td>Hy</td><td id="hy"></td></tr> | |
<tr><td>Hz</td><td id="hz"></td></tr> | |
</table> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"use strict"; | |
var head; | |
window.addEventListener( | |
"load", | |
function() { | |
head = document.querySelector("#head"); | |
mainFunction(); | |
}, | |
false | |
); | |
async function mainFunction() { | |
try { | |
var i2cAccess = await navigator.requestI2CAccess(); | |
var port = i2cAccess.ports.get(1); | |
var mpu6500 = new MPU6500(port, 0x68); | |
var ak8963 = new AK8963(port, 0x0c); | |
await mpu6500.init(); | |
await ak8963.init(); | |
while (1) { | |
var val0 = await mpu6500.getAcceleration(); | |
var val1 = await mpu6500.getGyro(); | |
var val2 = await ak8963.readData(); | |
// console.log('value:', value); | |
gx.innerHTML=val0.x; | |
gy.innerHTML=val0.y; | |
gz.innerHTML=val0.z; | |
rx.innerHTML=val1.x; | |
ry.innerHTML=val1.y; | |
rz.innerHTML=val1.z; | |
hx.innerHTML=val2.x; | |
hy.innerHTML=val2.y; | |
hz.innerHTML=val2.z; | |
await sleep(600); | |
} | |
} catch (error) { | |
console.error("error", error); | |
} | |
} | |
function sleep(ms) { | |
return new Promise(function(resolve) { | |
setTimeout(resolve, ms); | |
}); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
実体配線図