-
• #27
Translating Arduino Code into Javascript
The first attempt
/** 'readAccel() reads X,Y,Z accelerometer values'*/ LSM9DS1.prototype.readAccel=function(){ var temp=this.xgReadBytes(Regs.OUT_X_L_XL, 6); var i;var mm=[0,0,0]; this.a[0]=this.twos_comp(temp[0],temp[1]); this.a[1]=this.twos_comp(temp[2],temp[3]); this.a[2]=this.twos_comp(temp[4],temp[5]); etc etc } /** 'xgReadBytes(subAddress,count) read count bytes from gyro/accelerometer at subAddress'*/ LSM9DS1.prototype.xgReadBytes=function(subAddress,count){ var dest= new Uint8Array(count); var x=this.xgAddress; this.i2c.writeTo(x, subAddress|0x80); dest=this.i2c.readFrom(x, count); return dest; };//end xgReadBytes /** 'prototype.twos_comp(low,high) converts low and high bytes'*/ LSM9DS1.prototype.twos_comp=function(low,high){ var t=(high << 8) | low; return(t & 0x8000 ? t - 0x10000 : t); };//end twos_comp
But it can be done differently using ArrayBuffer and DataView
Read the byte stream into an ArrarBuffer, then use a DataView to convert to signed integers, note the littleEndian flag.var A=new ArrayBuffer(12); A[0]=1; A[1]=0; A[2]=0xfe; A[3]=0xff; var B= new Int16Array(A,0,6); console.log(A); console.log(B); console.log("B0= "+B[0]+" B[1]= "+B[1]); //var C=dataview.getUint16(byteOffset [, littleEndian]) var dataview = new DataView(A); console.log("A "+dataview.getInt16(0, true)); console.log("A1 "+dataview.getInt16(0, false)); console.log("A2 "+dataview.getInt16(2, true)); console.log("A3 "+dataview.getInt16(2, false)); B[0]=23;B[1]=-23;B[2]=56;B[3]=-56; console.log(A); console.log(B); A[0]=2;A[1]=0; A[2]=0xfe;A[3]=0xff; console.log(A); console.log(B);
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView/getUint16
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView/getInt16> -
• #28
Getting the I2C Interface Working With the Chip
What is I2C?
https://en.wikipedia.org/wiki/I%C2%B2C
So we have to connect the ground, power, SCL and SDA from the PICO to the chip.
The SCL and SDA lines require a pull-up resistor.
I’m using a breakout board from Sparkfun and the pullup resistors are on the board.
https://www.sparkfun.com/products/13284
As for the pins to use on the PICO
https://www.espruino.com/I2C
look at the PICO picture
http://www.espruino.com/Pico
Looking at the I2C section of the Espruino Reference Page
https://www.espruino.com/Reference
We find the I2C.find command.//////////////////////////////////// //Configuration //The I2C pins that the LSM9D01 is connected to //PICO I2C pins //IC1 sda=B7 scl=B6 //IC1 sda=B9 scl=B8 shim pins //IC3 sda=B4 scl=A8 //IC2 sda=B3 scl=B10 console.log(I2C.find(B7)); console.log(I2C.find(B6)); console.log(I2C.find(B9)); console.log(I2C.find(B8)); console.log(I2C.find(B4)); console.log(I2C.find(A8)); console.log(I2C.find(B3)); console.log(I2C.find(B10)); console.log(I2C.find(B1));
Which produces:
1v92 Copyright 2016 G.Williams >I2C { } I2C { } I2C { } I2C { } I2C { } I2C { } I2C { } I2C { } undefined =undefined
I2C devices have a 7 bit bus address. The LSM9DS1 has two, one for the magnetometer and one for the gyroscope and accelerometer. Jumpers on the Sparkfun board can be used to change the addresses.
There is a register labeled WHO_AM_I for the Gyro-Accel, and one for the magnetometer.
Reading these registers and checking the returned value validates that the I2C interface is working.
The following code sets up an LSM9DS1 object, initializes the I2C interface and reads the WHO_AM_I_XG register on the LSM9DS1 chip connected to I2C3.setup({ scl :A8, sda: B4} ).//Test I2C connection var Regs={ WHO_AM_I_XG: 0x0F, }; ////////////////////////////////////////////// /** the LSM9DS1 object*/ function LSM9DS1(i2c,xgAddress,mAddress) { this.i2c = i2c; this.xgAddress= xgAddress; this.mAddress= mAddress; } /** 'run() initializes the LSM9DS1' */ LSM9DS1.prototype.run=function(){ var xgTest = this.xgReadByte(Regs.WHO_AM_I_XG); console.log("xgTest= "+xgTest); };//end run /** 'xgReadByte(subAddress) read a byte from the gyro/accelerometer at subAddress'*/ LSM9DS1.prototype.xgReadByte=function(subAddress){ var x=this.xgAddress; var data=Uint8Array(1); this.i2c.writeTo(x, subAddress); data=this.i2c.readFrom(x, 1); return data[0]; };//end xgReadByte //////////////////////////////////// //Configuration //The I2C pins that the LSM9D01 is connected to //PICO I2C pins //IC1 sda=B7 scl=B6 //IC1 sda=B9 scl=B8 shim pins //IC3 sda=B4 scl=A8 //IC2 sda=B3 scl=B10 var W; function start(){ // console.log("start"); I2C3.setup({ scl :A8, sda: B4} ); //console.log(I2C3); var xgAddress= 0x6B;// Would be 0x1C if SDO_M is LOW var mAddress= 0x1e;// Would be 0x6A if SDO_AG is LOW //W=require("slimLSM9DS1").connect(I2C3,xgAddress,mAddress); W=new LSM9DS1(I2C3,xgAddress,mAddress); W.run();//Get it started }//end start //Wait for program to finish loading setTimeout(function () { start(); }, 1000);
Which outputs:
1v92 Copyright 2016 G.Williams > =undefined xgTest= 104 >
-
• #29
How to Bobble the Bits in the Registers
The Vogan poetry in the datasheet for the LSM9DS1 can be found here:
http://www.st.com/content/ccc/resource/technical/document/datasheet/1e/3f/2a/d6/25/eb/48/46/DM00103319.pdf/files/DM00103319.pdf/jcr:content/translations/en.DM00103319.pdf
In section six the register mapping is described. This lets us write a table to reference the registers in the code. For example the gyro and accelerometer registers are defined:var Regs={ ACT_THS: 04, ACT_DUR: 05, INT_GEN_CFG_XL: 06, INT_GEN_THS_X_XL: 07, INT_GEN_THS_Y_XL: 08, INT_GEN_THS_Z_XL: 09, INT_GEN_DUR_XL: 0x0A, REFERENCE_G: 0x0B, INT1_CTRL: 0x0C, INT2_CTRL: 0x0D, //Reserved -- 0E -- -- Reserved WHO_AM_I: 0x0F, CTRL_REG1_G: 0x10, CTRL_REG2_G: 0x11, CTRL_REG3_G: 0x12, ORIENT_CFG_G: 0x13, INT_GEN_SRC_G: 0x14, OUT_TEMP_L: 0x15, OUT_TEMP_H: 0x16, STATUS_REG1: 0x17, OUT_X_L_G: 0x18, OUT_X_H_G: 0x19, OUT_Y_L_G: 0x1A, OUT_Y_H_G: 0x1B, OUT_Z_L_G: 0x1C, OUT_Z_H_G: 0x1D, CTRL_REG4: 0x1E, CTRL_REG5_XL: 0x1F, CTRL_REG6_XL: 0x20, CTRL_REG7_XL: 0x21, CTRL_REG8: 0x22, CTRL_REG9: 0x23, CTRL_REG10:0x24, //Reserved -- 25 -- -- Reserved INT_GEN_SRC_XL: 0x26, STATUS_REG2: 0x27, OUT_X_L_XL: 0x28, OUT_X_H_XL: 0x29, OUT_Y_L_XL: 0x2A, OUT_Y_H_XL: 0x2B, OUT_Z_L_XL: 0x2C, OUT_Z_H_XL: 0x2D, FIFO_CTRL: 0x2E, FIFO_SRC: 0x2F, INT_GEN_CFG_G: 0x30, INT_GEN_THS_XH_G: 0x31, INT_GEN_THS_XL_G: 0x32, INT_GEN_THS_YH_G: 0x33, INT_GEN_THS_YL_G: 0x34, INT_GEN_THS_ZH_G: 0x35, INT_GEN_THS_ZL_G: 0x36, INT_GEN_DUR_G: 0x37, //Reserved r 38-7F };
In Section7 of the datasheet the bits in the Accelerometer and gyroscope registers are described.
For example:
7.12 CTRL_REG1_G (10h) Angular rate sensor Control Register 1.
| Bit7 | Bit6| Bit5| Bit4| Bit3| Bit2| Bit1| Bit0|
| --- | --- | --- | --- | --- | --- | --- | --- |
|ODR_G2 |ODR_G1 |ODR_G0 |FS_G1 |FS_G0 |0(1)| BW_G1 |BW_G0 |- This bit must be set to ‘0’ for the correct operation of the device. BW_G1 BW_G0
Bits 5, 6, and 7 control the output data rate of the gyro.
Bits 3, and 4 select the full scale of the gyro.
Bit 2 is always 0, and
Bits 0 and 1 select the gyro bandwidth.
Setting up a data structure to bobble the bits
var REGval={ /* CTRL_REG1_G (10h) Angular rate sensor Control Register ODR_G2, ODR_G1, ODR_G0, FS_G1, FS_G0, 0,BW_G1, BW_G0 */ ODR_G:{reg:Regs.CTRL_REG1_G,shift:5,mask:7}, FS_G:{reg:Regs.CTRL_REG1_G,shift:3,mask:3}, BW_G:{reg:Regs.CTRL_REG1_G,shift:0,mask:3}, //more stuff
And setup functions to read or write the bits
/** Use the datastructure to write bits to AG register */ LSM9DS1.prototype.AGwrite=function(R,value){ var A=this.xgReadByte(R.reg); //console.log(A,value,R,R.mask,R.shift); var v=value&R.mask; // console.log("v= "+v); A=A&(~(R.mask<<R.shift)); A=A|(v<<R.shift); // console.log("A= "+A.toString(2)); this.xgWriteByte(R.reg,A); };//end AGwrite /** Use the data structure to read bit settings from AG register*/ LSM9DS1.prototype.AGread=function(R){ var A=this.xgReadByte(R.reg); A=A>>R.shift; A=A&R.mask; // console.log("A= "+A.toString(2)); return A; };//end AGread
The following tests to see if the communication is working, performs a reset, writes and then reads a value to the ODR bits and then iterates thru the data structure to read and display all the bits.
/** 'run() initializes the LSM9DS1' */ LSM9DS1.prototype.run=function(){ var i; var xgTest = this.xgReadByte(Regs.WHO_AM_I_XG); console.log("XG replied "+xgTest); console.log("do a reset"); this.AGwrite(REGval.SW_RESET,1); console.log("SWreset= "+this.AGread(REGval.SW_RESET)); // console.log("try writing to the ODR_G bits"); this.AGwrite(REGval.ODR_G,7); console.log("ODR_G= "+this.AGread(REGval.ODR_G)); console.log("iterate thru all the AG settings"); for (var x in REGval) console.log(x,this.AGread(REGval[x])); return 1; };//end run
The output looks like this:
1v92 Copyright 2016 G.Williams > =undefined XG replied 104 do a reset SWreset= 0 try writing to the ODR_G bits ODR_G= 7 iterate thru all the AG settings ODR_G 7 FS_G 0 BW_G 0 G_INT_SEL 0 G_OUT_SEL 0 G_LP_mode 0 G_HP_EN 0 HPCF_G 0 SignX_G 0 SignY_G 0 SignZ_G 0 Orient_G 0 Dec_XL 0 Zen_XL 1 Yen_XL 1 Xen_XL 1 ODR_XL 0 FS_XL 0 BW_SCAL_ODR_XL 0 BW_XL 0 HR_XL 0 DCF_XL 0 FDS_XL 0 HPIS1_XL 0 BOOT 0 BDU 0 H_LACTIVE 0 PP_OD 0 SIM 0 IF_ADD_INC 1 BLE 0 SW_RESET 0 SLEEPG 0 FIFO_TEMP_EN 0 DRDY_mask_bit 0 I2C_DISABLE 0 FIFO_EN 0 STOP_ON_FTH 0 ST_G 0 ST_XL 0 FMODE 0 FTH 0 >
1 Attachment
- This bit must be set to ‘0’ for the correct operation of the device. BW_G1 BW_G0
-
• #30
@ClearMemory041063 -> nice work !
I plan to use a LSM9DS0 9-DOF ( from adafruit ) for another project & I wonder how much work it'd be ( & how close it is to the LSM9DS1 ) to adapt you nearly-module-code to handle it ? ( also I'd be willing to help/do so if it's not "too advanced" for me for now ;) )this being said, kudos ++ ;)
-
• #31
I'll take a look at the adafruit part for grins. Might be a close fit.
Advanced is often confused with familiarity with a subject, so don't sell yourself short.
I often puzzle over some of the projects that you post as well and usually learn something in the process. -
• #32
The Magnetometer Bits
The Registers
The way this was done is to pull up the datasheet PDF, highlight the relevant table, paste it into a new Wordpad document, edit search and replace and save it as a text document with .js extension.
Here is a portion of the magnetometer address map. Referring to the test in quotes in the following.
Search “ r/w “ and replace with “: 0x”. Other edits apply as well.Table 22. Magnetic sensor register address map Registers marked as Reserved must not be changed. Writing to those registers may cause permanent damage to the device. To guarantee proper behavior of the device, all registers addresses not listed in the above table must not be accessed and the content stored on those registers must not be changed. The content of the registers that are loaded at boot should not be changed. They contain the factory calibration values. Their content is automatically restored when the device is powered up. Name Type Register address Default Comment Hex Binary Reserved 00 - 04 -- -- Reserved OFFSET_X_REG_L_M r/w 05 00000000 Offset in order to compensate environmental effects OFFSET_X_REG_H_M r/w 06 00000000 OFFSET_Y_REG_L_M r/w 07 00000000 OFFSET_Y_REG_H_M r/w 08 00000000 OFFSET_Z_REG_L_M r/w 09 00000000 OFFSET_Z_REG_H_M r/w 0A 00000000 Reserved 0B - 0E -- -- Reserved WHO_AM_I_M r 0F 0000 1111 00111101 Magnetic Who I am ID Reserved 10 - 1F -- -- Reserved CTRL_REG1_M r/w 20 0010 0000 00010000
Here is a portion of the edited text
var MagRegs={ //Reserved 00 - 04 -- -- Reserved OFFSET_X_REG_L_M:0x05, OFFSET_X_REG_H_M:0x06, OFFSET_Y_REG_L_M:0x07, OFFSET_Y_REG_H_M:0x08, OFFSET_Z_REG_L_M:0x09, OFFSET_Z_REG_H_M:0x0A, //Reserved 0B - 0E -- -- Reserved WHO_AM_I_M: 0x0F, //Reserved 10 - 1F -- -- Reserved CTRL_REG1_M:0x20, CTRL_REG2_M:0x21, CTRL_REG3_M:0x22, CTRL_REG4_M:0x23, CTRL_REG5_M:0x24, //Reserved 25 - 26 -- -- Reserved
Creating the Data Structure
A similar process is used to edit the pasted PDF text into the data structure used to bobble the bits.
Each register description in individually cut and pasted to reduce the editing clutter, for example.8.5 CTRL_REG1_M (20h) Table 110. X and Y axes operative mode selection Table 111. Output data rate configuration Table 107. WHO_AM_I_M register 0 0 1 1 1 1 0 1 Table 108. CTRL_REG1_M register TEMP_ COMP OM1 OM0 DO2 DO1 DO0 FAST_ODR ST 8.6 CTRL_REG2_M (21h) 8.7 CTRL_REG3_M (22h) Table 112. CTRL_REG2_M register 0(1) 1. These bits must be set to ‘0’ for the correct operation of the device. FS1 FS0 0(1) REBOOT SOFT_RST 0(1) 0(1)
I used the bit labels and retained some information as a comment. A portion is shown here:
/**Table 108. CTRL_REG1_M register TEMP_COMP, OM1 OM0, DO2 DO1 DO0, FAST_ODR ,ST */ TEMP_COMP:{reg:MagRegs.CTRL_REG1_M,shift:7,mask:1}, OM:{reg:MagRegs.CTRL_REG1_M,shift:5,mask:3}, DO:reg:{MagRegs.CTRL_REG1_M,shift:2,mask:7}, FAST_ODR:{reg:MagRegs.CTRL_REG1_M,shift:1,mask:1}, ST:{reg:MagRegs.CTRL_REG1_M,shift:0,mask:1}, /** 8.6 CTRL_REG2_M (21h) 0(1),FS1, FS0, 0(1), REBOOT, SOFT_RST, 0(1,) 0(1*/ FS:{reg:MagRegs.CTRL_REG2_M,shift:5,mask:3}, REBOOT:{reg:MagRegs.CTRL_REG2_M,shift:3,mask:1}, SOFT_RST{reg:MagRegs.CTRL_REG2_M,shift:2,mask:1},
2 Attachments
-
• #33
I pulled up the datasheet for the LSM9DS0 and did a quick glance and found there are differences. For instance:
LSM9DS0 Table 40. FIFO mode configuration FM2 FM1 FM0 FIFO mode 0 0 0 Bypass mode 0 0 1 FIFO mode 0 1 0 Stream mode 0 1 1 Stream-to-FIFO mode 1 0 0 Bypass-to-Stream mode
LSM9DS1 Table 84. FIFO mode selection FMODE2 FMODE1 FMODE0 Mode 0 0 0 Bypass mode. FIFO turned off 0 0 1 FIFO mode. Stops collecting data when FIFO is full. 0 1 0 Reserved 0 1 1 Continuous mode until trigger is deasserted, then FIFO mode. 1 0 0 Bypass mode until trigger is deasserted, then Continuous mode. 1 1 0 Continuous mode. If the FIFO is full, the new sample overwrites the older sample.```
-
• #34
@stephaneAG
Adafruit has the LSM9DS1 as well and it's less expensive.
https://www.adafruit.com/product/3387 -
• #35
It is useful to document the bits,, and perhaps sorting them later by function, interaction, ones that have to be set a particular way to work with the module code. (A todo)
Magnetometer bits
TEMP_COMP
Temperature compensation enable. Default value: 0
(0: temperature compensation disabled; 1: temperature compensation enabled)
For the output of the magnetic data compensated by temperature, the
TEMP_COMP bit in CTRL_REG1_M (20h) must be set to ‘1’.OM
0 = Low-power mode
1 = Medium-performance mode
2 = High-performance mode
3 = Ultra-high performanceDO
0 = 0.625 Hz.
1= 1.25
2 = 2.5
3 = 5
4 = 10
5 = 20
6 = 40
7 = 80FAST_ODR
enables data rates higher than 80 Hz. Default value: 0
(0: Fast_ODR disabled; 1: FAST_ODR enabled)ST
Self-test enable. Default value: 0
(0: self-test disabled; 1: self-test enabled)FS
Full scale
0 = ± 4 gauss
1 = ± 8 gauss
2 = ± 12 gauss
3 = ± 16 gaussREBOOT
Reboot memory content. Default value: 0
(0: normal mode; 1: reboot memory content)SOFT_RST
Configuration registers and user register reset function.
(0: default value; 1: reset operation)I2C_DISABLE
Disable I2C interface. Default value 0. (0: I2C enable; 1: I2C disable)
LP
Low-power mode configuration. Default value: 0
If this bit is ‘1’, the DO[2:0] is set to 0.625 Hz and the system performs, for each
channel, the minimum number of averages. Once the bit is set to ‘0’, the magnetic
data rate is configured by the DO bits in the CTRL_REG1_M (20h) register.SIM
SPI Serial Interface mode selection. Default value: 0
(0: SPI only write operations enabled; 1: SPI read and write operations enable).MD
Operating mode selection. Default value: 11
0 = Continuous-conversion mode
1 = Single-conversion mode
2 = Power-down mode
3 = Power-down mode
The magnetic sensor has three operating modes available: power-down (default),
continuous-conversion mode and single-conversion mode. Switching from power-down to
the other modes requires one write operation to CTRL_REG3_M (22h), setting values in the
MD[1:0] bits. For the output of the magnetic data compensated by temperature, the
TEMP_COMP bit in CTRL_REG1_M (20h) must be set to ‘1’.OMZ
Z-axis operative mode selection
0 = Low-power mode
1 = Medium-performance mode
2 = High-performance mode
3 = Ultra-high performance modeBLE
Big/Little Endian data selection. Default value: 0
(0: data LSb at lower address; 1: data MSb at lower address)FAST_READ
FAST_READ allows reading the high part of DATA OUT only in order to increase
reading efficiency. Default value: 0
(0: FAST_READ disabled; 1: FAST_READ enabled)BDU
Block data update for magnetic data. Default value: 0
(0: continuous update; 1: output registers not updated until MSB and LSB have
been read)ZYXOR
X, Y and Z-axis data overrun. Default value: 0
(0: no overrun has occurred;
1: a new set of data has overwritten the previous set)ZOR
Z-axis data overrun. Default value: 0
(0: no overrun has occurred;
1: new data for the Z-axis has overwritten the previous data)YOR
Y-axis data overrun. Default value: 0
(0: no overrun has occurred;
1: new data for the Y-axis has overwritten the previous data)XOR
X-axis data overrun. Default value: 0
(0: no overrun has occurred;
1: new data for the X-axis has overwritten the previous data)ZYXDA
X, Y and Z-axis new data available. Default value: 0
(0: a new set of data is not yet available;
1: a new set of data is available)ZDA
Z-axis new data available. Default value: 0
(0: new data for the Z-axis is not yet available;
1: new data for the Z-axis is available)YDA
Y-axis new data available. Default value: 0
(0: new data for the Y-axis is not yet available;
1: new data for the Y-axis is available)XDA
X-axis new data available. Default value: 0
(0: a new data for the X-axis is not yet available;
1: a new data for the X-axis is available)XIEN
Enable interrupt generation on X-axis. Default value: 0
0: disable interrupt request; 1: enable interrupt requestYIEN
Enable interrupt generation on Y-axis. Default value: 0
0: disable interrupt request; 1: enable interrupt requestZIEN
Enable interrupt generation on Z-axis. Default value: 0
0: disable interrupt request; 1: enable interrupt requestIEA
Interrupt active configuration on INT_MAG. Default value: 0
0: low; 1: highIEL
Latch interrupt request. Default value: 0
0: interrupt request latched; 1: interrupt request not latched)
Once latched, the INT_M pin remains in the same state until INT_SRC_M (31h)) is
read.IEN
Interrupt enable on the INT_M pin. Default value: 0
0: disable; 1: enablePTH_X
Value on X-axis exceeds the threshold on the positive side.
Default value: 0PTH_Y
Value on Y-axis exceeds the threshold on the positive side.
Default value: 0PTH_Z
Value on Z-axis exceeds the threshold on the positive side.
Default value: 0NTH_X
Value on X-axis exceeds the threshold on the negative side.
Default value: 0NTH_Y
Value on Y-axis exceeds the threshold on the negative side.
Default value: 0NTH_Z
Value on Z-axis exceeds the threshold on the negative side.
Default value: 0MROI
Internal measurement range overflow on magnetic value.
Default value: 0INT
This bit signals when the interrupt event occurs.
-
• #36
Testing the LSM9DS1 Module
Note that the module is still under construction at this point.
Setup a project in WebIDE
WebIDE will use a projects folder with the LSM9DS1.js placed in the Modules sub-folder.
In WebIDE click on the gear icon in the upper right corner and then click on Project. You can then create a project if you haven’t done so already. When you “require” a module, the project module subfolder is part of the search chain.Magtest.js
//Magtest.js 30Apr2017 //////////////////////////////////// function testMag(){ var temp; var i; W.Mwrite(W.MREGval.TEMP_COMP,1); /* ON OMZ 0 = Low-power mode 1 = Medium-performance mode 2 = High-performance mode 3 = Ultra-high performance */ W.Mwrite(W.MREGval.OM,3); W.Mwrite(W.MREGval.OMZ,3); /* DO 0 = 0.625 Hz. 1= 1.25 2 = 2.5 3 = 5 4 = 10 5 = 20 6 = 40 7 = 80 */ W.Mwrite(W.MREGval.DO,3);//5 Hz //W.Mwrite(W.MREGval.DO,7);//80 Hz W.Mwrite(W.MREGval.FAST_ODR,0); W.Mwrite(W.MREGval.ST,0); /* FS Full scale 0 = ± 4 gauss 1 = ± 8 gauss 2 = ± 12 gauss 3 = ± 16 gauss */ W.Mwrite(W.MREGval.FS,1); W.Mwrite(W.MREGval.MD,0);//continuous convert //W.Mwrite(W.MREGval.MD,1);//single convert W.Mwrite(W.MREGval.BLE,0);//Endian of data //W.Mwrite(W.MREGval.BDU,0);//continuous update W.Mwrite(W.MREGval.BDU,1);//block update W.Mwrite(W.MREGval.FAST_READ,0); }//end testMag function displayMag(){ var m; if(W.Mread(W.MREGval.ZYXDA)){ //new data available // console.log("Mag data available"); m=W.mReadBytes(W.MagRegs.OUT_X_L_M, 6); console.log(" "+m[0]+","+m[1]+","+m[2]); }//endif }//end displayMag //Configuration //The I2C pins that the LSM9D01 is connected to //PICO I2C pins //IC1 sda=B7 scl=B6 //IC1 sda=B9 scl=B8 shim pins //IC3 sda=B4 scl=A8 //IC2 sda=B3 scl=B10 var W; function start(){ // console.log("start"); I2C3.setup({ scl :A8, sda: B4} ); //console.log(I2C3); var xgAddress= 0x6B;// Would be 0x1C if SDO_M is LOW var mAddress= 0x1e;// Would be 0x6A if SDO_AG is LOW W=require("LSM9DS1").connect(I2C3,xgAddress,mAddress); // W=new LSM9DS1(I2C3,xgAddress,mAddress); W.run();//Get it started W.showAG(); W.showMag(); testMag(); setInterval(function () { displayMag(); }, 200); }//end start //function startPgm(){ //Wait for program to load setTimeout(function () { start(); }, 1000); //}//end startPgm
Some raw output of the magnetometer, X, Y, and Zaxis
( note units are raw counts and no zero offset has been applied )
700,-950,-802 678,-944,-802 703,-947,-806 700,-936,-825 678,-945,-807 677,-948,-830 675,-938,-826 686,-944,-830 685,-964,-831 686,-949,-838 695,-938,-848 672,-975,-855 684,-960,-827 679,-962,-841 680,-968,-845 672,-943,-846 >clearInterval(); =undefined >
The module needs code to read the accelerometer and gyro data.
2 Attachments
-
• #37
Converting the Raw Magnetometer Counts to Calibrated Engineering Units
The ideal case
Three magnetometer sensors place on three orthogonal axis X, Y and Z.
Each magnetometer produces an output of 0.0 when exposed to a zero magnetic field and the same values when each axis is point at the Earth’s magnetic pole.The real world magnetometer chip
Each axis has to have an offset value applied to the raw counts to obtain a zero.
For a given magnetic field each axis may produce a slightly different value.
The axis may not be perfectly orthogonal.Some math:
Let X, Y and Z be the raw readings obtained from the magnetometer.
Let Xoffset, Yoffset and Zoffset be the zero offset that is applied to each axis X, Y and Z to obtain
X1 = X – Xoffset, Y1= Y - Yoffset, and Z1 = Z – Zoffset.
Let X2 = XA*X1 + XB*Y1 + XC*Z1,
Let Y2 = YA*X1 + YB*Y1 + YC*Z1,
Let Z2 = ZA*X1 + ZB*Y1 + ZC*Z1, where
XA, XB, XC,
YA, YB, YC, and
ZA, ZB, ZC are calibration valuesLet R = sqrt ( X2 ^2 + Y2^2 + Z2^2), and
For a large number of samples let avgR = sumof( Rn)/N, the average radius.
Let Error(n) = R(n)- avgR, and Error^2(n)= Error(n) * Error(n).
Finally SumError^2 = sumof(Error^2(n))
All this is done in the attached spreadsheet.Collect some calibration data using the Magtest.js code.
Start the program and point each axis of the magnetometer toward the North magnetic pole.
At my location the pole is 60 degrees below the horizon. Each axis has to be point at and away from the pole to get a good calibration sample. When calibrated the magnetic radius R should be a constant ( at least statistically.Finding the zero offsets and calibration values
The raw data are then pasted into the spreadsheet X, Y , and Z columns.
raw raw raw N X Y Z 0 -735 478 118 1 -700 555 38 2 -660 645 -26 ... More data The X1 etc. columns have to be copied and pasted such that each XYZ sample is calculated.
raw-offset
X1 Y1 Z1 X2 Y2 Z2 R Error^2 -1795.01 461.26 -438.90 -1756.92 235.48 -478.70 1836.13 35.58 -1760.01 538.26 -518.90 -1721.45 315.47 -557.92 1836.90 45.29 The formula view:
raw-offset
X1 Y1 Z1 =+B11-$B$3 =+C11-$B$4 =+D11-$B$5 =+B12-$B$3 =+C12-$B$4 =+D12-$B$5 X2 Y2 Z2 =+$E11$C$3+$F11$D$3+$G11*$E$3 =+$E11$C$4+$F11$D$4+$G11*$E$4 =+$E11$C$5+$F11$D$5+$G11*$E$5 =+$E12$C$3+$F12$D$3+$G12*$E$3 =+$E12$C$4+$F12$D$4+$G12*$E$4 =+$E12$C$5+$F12$D$5+$G12*$E$5 R Error^2 =+SQRT(H11*H11+I11*I11+J11*J11) =+(K11-$K$8)^2 =+SQRT(H12*H12+I12*I12+J12*J12) =+(K12-$K$8)^2 The calculation range in Cells K8 and L7 have to be adjusted to fit the data range.
J K L Sumerr^2 243533.8512 Avg R= 1830.168415 J K L Sumerr^2 =+SUM(L11:L163) Avg R= =+AVERAGE(K11:K163) We start with the offsets in B3 ,B4, and B5 set to zero and the calibration values
Cells C3,D4, and E5 equal to 1
Cells C4, C5, D3, D5, E3, and E4 equal to 0.0.Offset A B C X 0 1 0 0 Y 0 0 1 0 Z 0 0 0 1 The Solver function of Excel (part of the analysis tool pack add in) is used to find the offsets and calibration coefficients.
Track your progress by copying the value in cell L8 into a progress column.
First use the solver to minimize cell L8 by changing cells B3, B4, and B5.
The value in cell L8 should be smaller and cells B3, B4, and B5 should have changed.Offset A B C X 956.5255249 1 0 0 Y 57.48926514 0 1 0 Z 564.9867808 0 0 1 Apply solver once again this time minimizing cell L8 by changing cells
C3, C4, C5, D3, D4, D5, E3, and E4. Note that cell E5 is left to have a value of 1.0.
At this point the error squared should been reduced by a lot.Offset A B C X 1060.011759 0.982416927 0.014146407 0 Y 16.73968712 0.121577401 0.983634984 0 Z 556.9017955 0.02217041 0 1 I use the Descriptive Statistics function in the analysis tool pack to analyze the X2, Y2, Z2, and R values.
R X2 Y2 Z2 Mean 1829.74 -364.59 391.43 632.47 Standard Error 3.23 67.06 76.42 84.77 Median 1829.47 -437.90 486.95 869.72 Standard Deviation 39.96 829.43 945.26 1048.54 Sample Variance 1597.08 687950.89 893521.30 1099436.03 Kurtosis 13.36 -0.80 0.03 -0.81 Skewness -1.24 0.03 -0.81 -0.70 Range 400.83 3116.84 3511.30 3364.00 Minimum 1589.21 -1839.88 -1767.80 -1533.31 Maximum 1990.03 1276.96 1743.49 1830.68 Sum 279950.92 -55782.91 59888.09 96768.49 Count 153.00 153.00 153.00 153.00 Additional measures that may be applied is to remove data that produces an R value more than two standard deviations from the average R, and then recalculate the calibration values.
2 Attachments
-
• #38
Elimination of data outside of 2 standard deviations
The following cell formulas were used to flag data with R > Ravg + 2* Standard Deviation, data with R < Ravg – 2 *Standard Deviations. Addif combines the two test. Sort is a copy of sort but pasting the values.
The data set is then sorted on the sort column so that the data that fails the two test appears at the end.
The range of the average R and error squared cells is then adjusted to omit the failed data.If> If< addif sort =+IF(K11>2*$W$16+$K$8,1,0) =+IF(K11<-2*$W$16+$K$8,1,0) =+M11+N11 0 =+IF(K12>2*$W$16+$K$8,1,0) =+IF(K12<-2*$W$16+$K$8,1,0) =+M12+N12 0 =+IF(K13>2*$W$16+$K$8,1,0) =+IF(K13<-2*$W$16+$K$8,1,0) =+M13+N13 0 The statistics before and after culling points
X2 Y2 Z2 R R culled Mean -364.5748567 391.871392 632.4737844 1830.168415 1836.695918 Standard Error 67.04595875 76.48066792 84.76943069 3.236027167 1.512956317 Median -437.737373 492.0129977 869.7152389 1831.87751 1837.17791 Mode #N/A #N/A #N/A #N/A #N/A Standard Deviation 829.3127091 946.0136164 1048.53995 40.02744545 18.1554758 Sample Variance 687759.5696 894941.7624 1099436.026 1602.19639 329.6213015 Kurtosis -0.804853975 0.040187749 -0.812408283 13.51531831 1.605392491 Skewness 0.029365323 -0.813405054 -0.704273669 -1.200036996 0.376826799 Range 3116.687258 3519.235059 3363.996524 402.5993238 125.1034715 Minimum -1839.702418 -1770.78729 -1533.311636 1588.830427 1780.98384 Maximum 1276.984841 1748.447769 1830.684887 1991.429751 1906.087312 Sum -55779.95308 59956.32298 96768.48901 280015.7674 264484.2122 Count 153 153 153 153 144 Compare the Range of the R and R culled items.
The calibration constants
Mag8Gauss 30Apr2017
Offset A B C X 1060.852426 0.987424002 0.01417124 -0.000599842 Y 24.46995621 0.124389675 0.996380859 -0.000561968 Z 561.2217795 0.020594208 0.00552387 1 Next using the calibrations.
1 Attachment
-
• #39
Applying the Calibrations
There are 4 values to be applied to 3 axis, for each scale and for the magnetometer, accelerometer and the gyroscope sensors.
A data structure for the magnetometer calibration values
var magcal={ scale4:{scale:4,table:[ {offset:0,A:1,B:0,C:0}, {offset:0,A:0,B:1,C:0}, {offset:0,A:0,B:0,C:1} ]}, scale8:{scale:4,table:[ {offset:1060.85,A:0.98742,B:0.01417,C:-0.0005998}, {offset:24.469956,A: 0.124389675,B:0.996380859,C:-0.000561968}, {offset:561.2217795,A:0.020594208 ,B:0.00552387,C:1} ]}, scale12:{scale:4,table:[ {offset:0,A:1,B:0,C:0}, {offset:0,A:0,B:1,C:0}, {offset:0,A:0,B:0,C:1} ]}, scale16:{scale:4,table:[ {offset:0,A:1,B:0,C:0}, {offset:0,A:0,B:1,C:0}, {offset:0,A:0,B:0,C:1} ]}, };
Code to apply the calibration values
function useCalibration(cal,autocalc,data){ var i;var D=[0,0,0];var F=[0,0,0]; if(autocalc<1){ for(i=0;i<3;i++)D[i]=data[i]; return D; }//endif for(i=0;i<3;i++)D[i]=data[i]-cal.table[i].offset; if(autocalc===1)return D; for(i=0;i<3;i++){ F[i]=D[0]*cal.table[i].A; F[i]+=D[1]*cal.table[i].B; F[i]+=D[2]*cal.table[i].C; }//next i for(i=0;i<3;i++)F[i]=F[i]*cal.scale/(1<<15); return F; }//end useCalibration
Applying the Use calibration function
function displayMag(){ var m; if(W.Mread(W.MREGval.ZYXDA)){ //new data available // console.log("Mag data available"); m=W.mReadBytes(W.MagRegs.OUT_X_L_M, 6); //autocalc 0=raw, 1=raw-offset, 2 Gauss var autocalc=2; M=useCalibration(magcal.scale8,autocalc,m); console.log(" "+M[0]+","+M[1]+","+M[2]); //raw }//endif }//end displayMag
Listing the scales
function showscales(){ for(var x in magcal)console.log(x); }
An Output Sample
> =undefined AG replied 104 M replied 61 do a reset of AG AG SWreset= 0 reset the magnetometer scale4 scale8 scale12 scale16 -0.00014387969,-0.09589182669,-0.20146481881 0.00023358480,-0.09475134273,-0.20193948954 -0.00110189705,-0.09552740429,-0.20038360033 0.00167522343,-0.09481362313,-0.19971340522 0.00177061744,-0.09662211209,-0.20106377922 0.00193627169,-0.09344444901,-0.20128787409 0.00032607760,-0.09668255780,-0.20133741284 0.00229249432,-0.09388396965,-0.20384650603
1 Attachment
-
• #40
Code to Read the Gyroscope and Accelerometer Using the FIFO
The Gyroscope ODR (Output Data Rate) Also Controls the Accelerometer ODR if it is On.
/* ODR_G Gyroscope output data rate selection. Default value: 000 Table 46 | Value | ODR [Hz] | Cutoff [Hz] | | --- | --- | --- | | 0 | Power-down | n.a. | | 1 | 14.9 | 5 | | 2 | 59.5 | 19 | | 3 | 119 | 38 | | 4 | 238 | 76 | | 5 | 476 | 100 | | 6 | 952 | 100 | | 7 | n.a. | n.a.| */ W.AGwrite(W.REGval.ODR_G,0);
By setting it to 0 (Off) the Accelerometer is controlled by
/* ODR_XL Accelerometer Output data rate and power mode selection. default value: 000 ###### Table 68 | ODR_XL | ODR selection [Hz] | | --- | --- | | 0 | Power-down | | 1 | 10 Hz | | 2 | 50 Hz | | 3 | 119 Hz | | 4 | 238 Hz | | 5 | 476 Hz | | 6 | 952 Hz | | 7 | n.a. | */ W.AGwrite(W.REGval.ODR_XL,2);
Producing this output:
Alength= 30 A=, -455,-1526,16800 A=, -715,-1489,16801 A=, -595,-1488,16801 A=, -593,-1497,16854 A=, -757,-1442,16755 A=, -527,-1473,16816 A=, -623,-1513,16852 A=, -736,-1483,16771 A=, -511,-1495,16811 A=, -679,-1517,16867 >clearInterval();
Changing the gyro ODR to non zero
W.AGwrite(W.REGval.ODR_G,1);
Produces this output:
Alength= 18 G=, -741,206,-16, A=, -715,-1464,16811 G=, -738,200,-19, A=, -787,-1478,16819 G=, -734,197,-23, A=, -755,-1489,16795 Alength= 18 G=, -737,199,-20, A=, -854,-1499,16796 G=, -740,201,-17, A=, -829,-1453,16775 G=, -727,198,-17, A=, -788,-1484,16802 >clearInterval();
Some Notes
G is Gyro X,Y ,and Z raw counts. A= Accelerometer X,Y, and Z raw counts.
Note a new version of LSM9DS1.js is attached and the test program AGtest1.js
The LSM9DS1.js goes in the modules subdirectory of your WebIDE project.
The data are read every 200 ms, determined by a set interval.
The ODR and the interval interact. At low ODR fewer samples are in the FIFO in a 200 ms interval.
The FIFO can contain up to 32 samples and can be set to fewer samples if needed.
2 Attachments
-
• #41
Thanks for posting this! There's an internal FIFO? That could really help with power efficiency in some devices - in Puck.js for instance I have to wake it up every time a reading is received. It'd be great to be able to wake up only every so often and drain the FIFO.
-
• #42
@Gordon
The Accelerometer, Temperature and Gyroscope use the FIFO, the magnetometer is not included in the FIFO. One interrupt mode is based on the number of samples in the FIFO.
My Sparkfun breakout board didn't bring the interrupt pins to a header. There are also some low power modes as well to explore. -
• #43
Accelerometer/Gyroscope Bits
Used as input to AGread and AGwrite functions.
General Control Bits
BOOT
Reboot memory content. Default value: 0 (0: normal mode; 1: reboot memory content)
- Boot request is executed as soon as internal oscillator is turned-on. It is possible to set bit while in powerdown
mode, in this case it will be served at the next normal mode or sleep mode.
BDU
Block data update. Default value: 0 (0: continuous update; 1: output registers not updated until MSB and LSB read)
H_LACTIVE
Interrupt activation level. Default value: 0
(0: interrupt output pins active high; 1: interrupt output pins active low)PP_OD
Push-pull/open-drain selection on the INT1_A/G pin and INT2_A/G pin.
Default value: 0
(0: push-pull mode; 1: open-drain mode)SIM
SPI serial interface mode selection. Default value: 0
(0: 4-wire interface; 1: 3-wire interface).IF_ADD_INC
Register address automatically incremented during a multiple byte access with a
serial interface (I2C or SPI). Default value: 1
(0: disabled; 1: enabled)BLE
Big/Little Endian data selection. Default value 0
(0: data LSB @ lower address; 1: data MSB @ lower address)SW_RESET
Software reset. Default value: 0
(0: normal mode; 1: reset device)
This bit is cleared by hardware after next flash boot.DRDY_mask_bit
Data available enable bit. Default value: 0
(0: DA timer disabled; 1: DA timer enabled)I2C_DISABLE
Disable I2C interface. Default value: 0
(0: both I2C and SPI enabled; 1: I2C disabled, SPI only)ST_G
Angular rate sensor self-test enable. Default value: 0
(0: Self-test disabled; 1: Self-test enabled)ST_XL
Linear acceleration sensor self-test enable. Default value: 0
(0: Self-test disabled; 1: Self-test enabled)Gyro Configuration Bits
SLEEPG
Gyroscope sleep mode enable. Default value: 0
(0: disabled; 1: enabled)ODR_G
Gyroscope output data rate selection. Default value: 000
Table 46
Value ODR [Hz] Cutoff [Hz] 0 Power-down n.a. 1 14.9 5 2 59.5 19 3 119 38 4 238 76 5 476 100 6 952 100 7 n.a. n.a. Table 47.
ODR_G [2:0] BW_G [1:0] ODR [Hz] Cutoff [Hz] 0 0 Power-down n.a. 0 1 Power-down n.a. 0 2 Power-down n.a. 0 3 Power-down n.a 1 0 14.9 n.a. 1 1 14.9 n.a. 1 2 14.9 n.a. 1 3 14.9 n.a. 2 0 59.5 16 2 1 59.5 16 2 2 59.5 16 2 3 59.5 16 3 0 119 14 3 1 119 31 3 2 119 31 3 3 119 31 4 0 238 14 4 1 238 29 4 2 238 63 4 3 238 78 5 0 476 21 5 1 476 28 5 2 476 57 5 3 476 100 6 0 952 33 6 1 952 40 6 2 952 58 6 3 952 100 7 0 n.a. n.a. 7 1 n.a. n.a. 7 2 n.a. n.a. 7 3 n.a. n.a. ODR_G [2:0] are used to set ODR selection when both the accelerometer and gyroscope
are activated. BW_G [1:0] are used to set gyroscope bandwidth selection.FS_G
Gyroscope full-scale selection. Default value: 00
(00: 245 dps; 01: 500 dps; 10: Not Available; 11: 2000 dps)BW_G
Gyroscope bandwidth selection. Default value: 00
ODR_G [2:0] are used to set ODR selection when both the accelerometer and gyroscope
are activated. BW_G [1:0] are used to set gyroscope bandwidth selection.G_INT_SEL
INT selection configuration. Default value: 00 (Refer to Figure 28)
G_OUT_SEL
Out selection configuration. Default value: 00 (Refer to Figure 28)
G_LP_mode
Low-power mode enable. Default value: 0
(0: Low-power disabled; 1: Low-power enabled)G_HP_EN
High-pass filter enable. Default value: 0
(0: HPF disabled; 1: HPF enabled, refer to Figure 28)HPCF_G
Gyroscope high-pass filter cutoff frequency selection. Default value: 0000
Table 52
HPCF_G [3:0] ODR= 14.9 Hz ODR= 59.5 Hz ODR= 119 Hz ODR= 238 Hz ODR= 476 Hz ODR= 952 Hz 0 1 4 8 15 30 57 1 0.5 2 4 8 15 30 2 0.2 1 2 4 8 15 3 0.1 0.5 1 2 4 8 4 0.05 0.2 0.5 1 2 4 5 0.02 0.1 0.2 0.5 1 2 6 0.01 0.05 0.1 0.2 0.5 1 7 0.005 0.02 0.05 0.1 0.2 0.5 8 0.002 0.01 0.02 0.05 0.1 0.2 9 0.001 0.005 0.01 0.02 0.05 0.1 SignX_G
Pitch axis (X) angular rate sign. Default value: 0
(0: positive sign; 1: negative sign)SignY_G
Roll axis (Y) angular rate sign. Default value: 0
(0: positive sign; 1: negative sign)SignZ_G
Yaw axis (Z) angular rate sign. Default value: 0
(0: positive sign; 1: negative sign)Orient_G
Directional user orientation selection. Default value: 000
REF_G
Reference value for gyroscope’s digital high-pass filter (r/w).
Default value: 0000 0000Accelerometer Bits
Dec_XL
Decimation of acceleration data on OUT REG and FIFO. Default value: 00
(00: no decimation;
01: update every 2 samples;
10: update every 4 samples;
11: update every 8 samples)Zen_XL
Accelerometer’s Z-axis output enable. Default value: 1
(0: Z-axis output disabled; 1: Z-axis output enabled)Yen_XL
Accelerometer’s Y-axis output enable. Default value: 1
(0: Y-axis output disabled; 1: Y-axis output enabled)Xen_XL
Accelerometer’s X-axis output enable. Default value: 1
(0: X-axis output disabled; 1: X-axis output enabled)ODR_XL
Output data rate and power mode selection. default value: 000
Table 68
ODR_XL ODR selection [Hz] 0 Power-down 1 10 Hz 2 50 Hz 3 119 Hz 4 238 Hz 5 476 Hz 6 952 Hz 7 n.a. FS_XL
Accelerometer full-scale selection. Default value: 00
(00: ±2g; 01: ±16 g; 10: ±4 g; 11: ±8 g)BW_SCAL_ODR_XL
Bandwidth selection. Default value: 0
(0: bandwidth determined by ODR selection:- BW = 408 Hz when ODR = 952 Hz, 50 Hz, 10 Hz;
- BW = 211 Hz when ODR = 476 Hz;
- BW = 105 Hz when ODR = 238 Hz;
BW = 50 Hz when ODR = 119 Hz;
1: bandwidth selected according to BW_XL [2:1] selection)BW_XL
Anti-aliasing filter bandwidth selection. Default value: 00
(00: 408 Hz; 01: 211 Hz; 10: 105 Hz; 11: 50 Hz)
HR_XL
High resolution mode for accelerometer enable. Default value: 0
(0: disabled; 1: enabled).Table 71
HR CTRL_REG7 (DCF [1:0]) LP cutoff freq. [Hz] 1 0 ODR/50 1 } 1 ODR/100 1 2 ODR/9 1 3 ODR/400 DCF_XL
Accelerometer digital filter (high pass and low pass) cutoff frequency selection: the bandwidth
of the high-pass filter depends on the selected ODR. See Table 71FDS_XL
Filtered data selection. Default value: 0
(0: internal filter bypassed; 1: data from internal filter sent to output register and FIFO)HPIS1_XL
High-pass filter enabled for acceleration sensor interrupt function on Interrupt. Default
value: 0 (0: filter bypassed; 1: filter enabled)Temperature Bits
FIFO_TEMP_EN
Temperature data storage in FIFO enable. Default value: 0
(0: temperature data not stored in FIFO; 1: temperature data stored in FIFO)FIFO Control Bits
FIFO_EN
FIFO memory enable. Default value: 0
(0: disabled; 1: enabled)STOP_ON_FTH
Enable FIFO threshold level use. Default value: 0
(0: FIFO depth is not limited; 1: FIFO depth is limited to threshold level)FIFO_TEMP_EN
Temperature data storage in FIFO enable. Default value: 0
(0: temperature data not stored in FIFO; 1: temperature data stored in FIFO)FMODE
FIFO mode selection bits. Default value: 000
Table 84
FMODE Mode 0 Bypass mode. FIFO turned off 1 FIFO mode. Stops collecting data when FIFO is full. 2 Reserved 3 Continuous mode until trigger is deasserted, then FIFO mode 4 Bypass mode until trigger is deasserted, then Continuous mode. 6 Continuous mode. If the FIFOis full, the new sample overwrites the older sample. 5 No specification 7 No specification FTH
FIFO threshold level setting. Default value: 0 0000
FIFO Status
FTHstatus
FIFO threshold status.
(0: FIFO filling is lower than threshold level; 1: FIFO filling is equal or higher than
threshold levelOVRN 0
FIFO overrun status.
(0: FIFO is not completely filled; 1: FIFO is completely filled and at least one samples
has been overwritten)FSS 0
Number of unread samples stored into FIFO.
(000000: FIFO empty; 100000: FIFO full, 32 unread samples)
Table 87. FIFO_SRC example: OVR/FSS detailsFTH OVRN FSS5 FSS4 FSS3 FSS2 FSS1 FSS0 Description 0 0 0 0 0 0 0 0 FIFO empty x 0 0 0 0 0 0 1 1 x 0 1 0 0 0 0 0 1 1 1 0 0 0 0 0 At least one sample has been overwritten Interrupt Control Bits
SLEEP_ON_INACT_EN
Gyroscope operating mode during inactivity. Default value: 0
(0: gyroscope in power-down; 1: gyroscope in sleep mode)ACT_THS
Inactivity threshold. Default value: 000 0000
ACT_DUR
Inactivity duration. Default value: 0000 0000
AOI_XL
AND/OR combination of accelerometer’s interrupt events. Default value: 0
(0: OR combination; 1: AND combination)D6
6-direction detection function for interrupt. Default value: 0
(0: disabled; 1: enabled)ZHIE_XL
Enable interrupt generation on accelerometer’s Z-axis high event. Default value: 0
(0: disable interrupt request; 1: interrupt request on measured acceleration value
higher than preset threshold)ZLIE_XL
Enable interrupt generation on accelerometer’s Z-axis low event. Default value: 0
(0: disable interrupt request; 1: interrupt request on measured acceleration value
lower than preset threshold)YHIE_XL
Enable interrupt generation on accelerometer’s Y-axis high event. Default value: 0
(0: disable interrupt request; 1: interrupt request on measured acceleration value
higher than preset threshold)YLIE_XL
Enable interrupt generation on accelerometer’s Y-axis low event. Default value: 0
(0: disable interrupt request; 1: interrupt request on measured acceleration value
lower than preset threshold)XHIE_XL
Enable interrupt generation on accelerometer’s X-axis high event. Default value: 0
(0: disable interrupt request; 1: interrupt request on measured acceleration value
higher than preset threshold)XLIE_XL
Enable interrupt generation on accelerometer’s X-axis low event. Default value: 0
(0: disable interrupt request; 1: interrupt request on measured acceleration value
lower than preset threshold)THS_XL_X
X-axis interrupt threshold. Default value: 0000 0000
THS_XL_Y
Y-axis interrupt threshold. Default value: 0000 0000
THS_XL_Z
Z-axis interrupt threshold. Default value: 0000 0000
WAIT_XL
Wait function enabled on duration counter. Default value: 0
(0: wait function off; 1: wait for DUR_XL [6:0] samples before exiting interrupt)DUR_XL6
Enter/exit interrupt duration value. Default value: 000 0000
INT1_IG_G
Gyroscope interrupt enable on INT 1_A/G pin. Default value: 0
(0: disabled; 1: enabled)INT1_IG_XL
Accelerometer interrupt generator on INT 1_A/G pin. Default value: 0
(0: disabled; 1: enabled)INT1_FSS5
FSS5 interrupt enable on INT 1_A/G pin. Default value: 0
(0: disabled; 1: enabled)INT1_OVR
Overrun interrupt on INT 1_A/G pin. Default value: 0
(0: disabled; 1: enabled)INT1_FTH
FIFO threshold interrupt on INT 1_A/G pin. Default value: 0
(0: disabled; 1: enabled)INT1_Boot
Boot status available on INT 1_A/G pin. Default value: 0
(0: disabled; 1: enabled)INT1_DRDY_G
Gyroscope data ready on INT 1_A/G pin. Default value: 0
(0: disabled; 1: enabled)INT1_DRDY_XL
Accelerometer data ready on INT 1_A/G pin. Default value: 0
(0: disabled; 1: enabled)INT2_INACT
Inactivity interrupt output signal. Default value: 0
(0: no interrupt has been generated; 1: one or more interrupt events have been
generated)INT2_FSS5
FSS5 interrupt enable on INT2_A/G pin. Default value: 0
(0: disabled; 1: enabled)INT2_OVR
Overrun interrupt on INT2_A/G pin. Default value: 0
(0: disabled; 1: enabled)INT2_FTH
FIFO threshold interrupt on INT2_A/G pin. Default value: 0
(0: disabled; 1: enabled)INT2_DRDY_TEMP
Temperature data ready on INT2_A/G pin. Default value: 0
(0: disabled; 1: enabled)INT2_DRDY_G
Gyroscope data ready on INT2_A/G pin. Default value: 0
(0: disabled; 1: enabled)INT2_DRDY_XL
Accelerometer data ready on INT2_A/G pin. Default value: 0
(0: disabled; 1: enabled)
//Status registers
XxxxxxxxxxxxxxxxxxxxxIG_XL 0, IG_XL2 0
Accelerometer interrupt output signal. Default value: 0
(0: no interrupt has been generated; 1: one or more interrupt events have been generated)IG_G 0, IG_G2 0
Gyroscope interrupt output signal. Default value: 0
(0: no interrupt has been generated; 1: one or more interrupt events have been generatedINACT 0, INACT2 0
Inactivity interrupt output signal. Default value: 0
(0: no interrupt has been generated; 1: one or more interrupt events have been generated)BOOT_STATUS 0, BOOT_STATUS2 0
Boot running flag signal. Default value: 0
(0: no boot running; 1: boot running)TDA 0, TDA2 0
Temperature sensor new data available. Default value: 0
(0: new data is not yet available; 1: new data is available)GDA 0, GDA2 0
Gyroscope new data available. Default value: 0
(0: a new set of data is not yet available; 1: a new set of data is available)XLDA 0, XLDA2 0
Accelerometer new data available. Default value: 0
(0: a new set of data is not yet available; 1: a new set of data is available)IA_G
Gyro Interrupt active. Default value: 0
(0: no interrupt has been generated; 1: one or more interrupts have been generated)ZH_G
Gyro Yaw (Z) high. Default value: 0
(0: no interrupt, 1: Z high event has occurred)ZL_G
Gyro Yaw (Z) low. Default value: 0
(0: no interrupt; 1: Z low event has occurred)YH_G
Gyro Roll (Y) high. Default value: 0
(0: no interrupt, 1: Y high event has occurred)YL_G
Gyro Roll (Y) low. Default value: 0
(0: no interrupt, 1: Y low event has occurred)XH_G
Gyro Pitch (X) high. Default value: 0
(0: no interrupt, 1: X high event has occurred)XL_G
Gyro Pitch (X) low. Default value: 0
(0: no interrupt, 1: X low event has occurred)IA_XL
Accelerometer Interrupt active. Default value: 0.
(0: no interrupt has been generated; 1: one or more interrupts have been generated)ZH_XL
Accelerometer's Z high event. Default value: 0
(0: no interrupt, 1: Z high event has occurred)ZL_XL
Accelerometer's Z low event. Default value: 0
(0: no interrupt; 1: Z low event has occurred)YH_XL
Accelerometer's Y high event. Default value: 0
(0: no interrupt, 1: Y high event has occurred)YL_XL
Accelerometer's Y low event. Default value: 0
(0: no interrupt, 1: Y low event has occurred)XH_XL
Accelerometer's X high event. Default value: 0
(0: no interrupt, 1: X high event has occurred)XL_XL
Accelerometer's X low. event. Default value: 0
(0: no interrupt, 1: X low event has occurred)Latest version of the LSM9DS1.js module is attached.
If you need a way to cool your coffee or tea and need to stretch here is a different kind of project.
https://www.youtube.com/watch?v=5_50RuMcc28
1 Attachment
- Boot request is executed as soon as internal oscillator is turned-on. It is possible to set bit while in powerdown
-
• #44
Calibrating the Accelerometer
The procedure is similar to the magnetometer calibration but several things are done differently.
- There are 3 axis, and if the accelerometer is attached to one face of a cube, we need to collect data with each of the six faces of the cube on the bottom. Data taken when the sensor is in motion may contain additional acceleration values that would distort the calibration.
The magnetometer used the average R value, for the accelerometer we will calculate the counts needed to produce a 1G value, taking the range setting of the accelerometer as a factor.
We need a way to signal the program that the sensor is positioned and ready to acquire some data.
With WebIDE this can be achieved by reassigning the console with the setConsole() function.
With a PICO this has its perils if you set the program up to run on boot and save the program.
You need to provide a way to get the console back to the USB port. Preferably several ways!//ConsoleMenu.js 11 May 2017 //How not to brick a PICO when reassigning the console // away from the USB port to do menu programs //Setup the button to light the LED and reset the Pico //Always include this code when a save() and oninit() functions are // used. setWatch(function(e) { digitalWrite(LED1, e.state); USB.setConsole(); reset(); }, BTN, { repeat: true }); E.on('init', function() { console.log("Hello"); startPgm(); }); //input cmd from terminal,send it to parsecmd() var sst=""; //The input buffer USB.on('data', function (data) { var i; sst+=data; // look for control c in input stream if(sst.indexOf(String.fromCharCode(3))>-1){ USB.setConsole(); reset(); }// console.log("control C seen"); USB.print(data); if(sst.length>-1) if(sst.charAt(sst.length-1)==="\r")selectparser(); }); //Espruino replies here LoopbackA.on('data',function(data){ USB.print(data); //sending data to terminal }); console.log("In left pane type startPgm();"); console.log("Use startPgm() first and make sure you can exit back to the console"); console.log("Once you are sure that a proper exit works then type save();"); var menulevel=0; function startPgm(){ setTimeout(function () { // start(); LoopbackB.setConsole(); mainmenu(); }, 1000); }//end startPgm function mainmenu(){ USB.print("\n\rMain Menu\n\rType somthing or a control C to Exit\n\r"); // USB.setConsole(); }//end mainmenu function selectparser(){ USB.print("\n\r"+sst+"\n\r"); // USB.setConsole(); }//end select parser
The attached file CollectAGdata.js combines the above menu program with AGtest1.js to produce a program that collects 32 samples and wait for a carriage return. The sensor can be repositioned and the next setting can be collected by pressing return. When finished type any character followed by a return to exit the program. The data are then copied from the WebIDE left pane and pasted nto a .CSV file. Some example output:
G=, -716,194,-17, A=, -148,-780,16899 G=, -711,193,-18, A=, -154,-787,16901 G=, -718,190,-18, A=, -156,-781,16944 G=, -719,193,-14, A=, -169,-762,16929 G=, -714,194,-12, A=, -178,-765,16942 G=, -714,194,-18, A=, -186,-730,16940 G=, -716,190,-17, A=, -195,-737,16940 G=, -725,191,-17, A=, -210,-736,16887 G=, -711,187,-15, A=, -182,-746,16924 G=, -713,190,-19, A=, -225,-741,16894 G=, -712,192,-21, A=, -209,-760,16893 G=, -704,194,-12, A=, -197,-743,16876 G=, -719,198,-15, A=, -132,-754,16905 G=, -717,217,-15, A=, -145,-706,16794 G=, -713,184,-15, A=, -207,-902,16881 G=, -718,204,-25, A=, -185,-817,16879 G=, -722,193,-9, A=, -110,-743,16895 G=, -721,196,-28, A=, -244,-878,16873 G=, -735,190,-14, A=, -189,-795,16896 G=, -720,214,-21, A=, -179,-749,16898 G=, -714,176,-18, A=, -219,-867,16894 G=, -726,199,-26, A=, -142,-731,16935 G=, -730,190,-18, A=, -156,-772,16936 G=, -719,190,-26, A=, -196,-758,16898 G=, -714,188,-20, A=, -129,-745,16981 G=, -719,193,-26, A=, -203,-777,16936 G=, -726,182,-19, A=, -210,-741,16947 G=, -723,199,-24, A=, -232,-722,16910 G=, -735,187,-27, A=, -149,-738,16921 G=, -729,188,-30, A=, -231,-760,16885 G=, -723,190,-23, A=, -167,-756,16869 G=, -715,192,-21, A=, -221,-760,17003 <- LoopbackB -> USB
The data are then pasted in a spreadsheet similar to the one used for the magnetometer and the twelve calibration values are calculated.
2 Attachments
- There are 3 axis, and if the accelerometer is attached to one face of a cube, we need to collect data with each of the six faces of the cube on the bottom. Data taken when the sensor is in motion may contain additional acceleration values that would distort the calibration.
-
• #45
The Accelerometer and Gyroscope Calibrations
Accelerometer May12 2017 2g scale using average R
Culled Range = 2230.842
Offset A B C X -987.2736361 0.995549457 0.140149893 2.11449E-05 Y 272.0992136 -0.042589517 0.991729217 0.00020329 Z 446.896968 -0.24363696 -0.291923385 1 Accelerometer May12 2017 2g scale using target value
Culled Range = 2159.087
Offset A B C X -1068.093899 0.981090704 0.127644011 4.11128E-05 Y 185.8088179 -0.013882693 0.989541404 3.62454E-05 Z 193.6596862 -0.268744893 -0.20999626 1 Gyroscope May12 2017 245deg per s.
Offsets Only as I’m not set up to spin the sensor and collect data.
Culled Range = 2506.073Offset A B C X -780.9157638 1 0 0 Y 214.1401801 0 1 0 Z -0.657364084 0 0 1 See attached files
3 Attachments
-
• #46
AGmagtest1.js
The attached program AGmagtest.js uses the LSM9DS1.js module and the preceding calibrations to produce data in engineering units.
The variable autocalc controls the type of units displayed.
//autocalc 0=raw, 1=raw-offset, 2 Engineering Units
var autocalc=2;In the function setupAG() the gyro ODR determines if gyro data are available.
W.AGwrite(W.REGval.ODR_G,1);//do gyro and acceleration
//W.AGwrite(W.REGval.ODR_G,0);//do acceleration only.Here is sample output with autocalc=2 and ODR_G=1
M magnetometer values are in Gauss,
G gyroscope values are in degrees per second
A acceleration values are in g, (1= Earth gravity)M,0.0150,-0.0847,-0.1949,G,0.3582,-0.1057,-0.1222,A,0.0839,-0.0478,0.9993, M,0.0172,-0.0830,-0.1933,G,0.3358,-0.1581,-0.1297,A,0.0869,-0.0552,1.0039, M,0.0172,-0.0830,-0.1933,G,0.3433,-0.1655,-0.1297,A,0.0841,-0.0479,1.0000, M,0.0172,-0.0830,-0.1933,G,0.3807,-0.1057,-0.1222,A,0.0831,-0.0438,0.9987, M,0.0151,-0.0866,-0.1965,G,0.4031,-0.2104,-0.1222,A,0.0817,-0.0398,0.9956, M,0.0151,-0.0866,-0.1965,G,0.3807,-0.0833,-0.1222,A,0.0821,-0.0416,0.9960, M,0.0151,-0.0866,-0.1965,G,0.4031,-0.1879,-0.1147,A,0.0831,-0.0460,0.9991, M,0.0162,-0.0845,-0.1933,G,0.3732,-0.0982,-0.1446,A,0.0822,-0.0459,1.0009, M,0.0162,-0.0845,-0.1933,G,0.3059,-0.1132,-0.1297,A,0.0834,-0.0461,1.0031, >clearInterval();
Changing ODR_G to 0 produces:
M,0.0154,-0.0826,-0.1849,A,0.0864,-0.0516,1.0014, M,0.0154,-0.0826,-0.1849,A,0.0868,-0.0537,1.0017, M,0.0154,-0.0826,-0.1849,A,0.0858,-0.0549,1.0009, M,0.0154,-0.0826,-0.1849,A,0.0862,-0.0567,1.0032, M,0.0154,-0.0826,-0.1849,A,0.0861,-0.0594,1.0028, M,0.0154,-0.0826,-0.1849,A,0.0852,-0.0598,1.0009, M,0.0154,-0.0826,-0.1849,A,0.0883,-0.0601,0.9992, M,0.0154,-0.0826,-0.1849,A,0.0877,-0.0574,0.9964, >clearInterval();
1 Attachment
-
• #47
...I expected you to put the sensor onto the stirling engine fly wheel... a centered / balanced puck and sensor would work to measure the RPM. ;-)
-
• #48
Now that's an interesting idea. The flywheel shaft is 10mm long with a crank on each end, so there's not much room for the Puck. Perhaps a photo interrupter with a tab on the flywheel would be easier for RPM sensing.
The LTD (Low Temperature Differential) Stirling is right up against the wall to work using hot coffee and small design changes can move the needed temperature differential.
One idea to pursue is a pressure sensor tapped into the displacer chamber. This would allow one to study the differences in displacer designs such as size, materials and motion of the displacer. -
• #49
Correction to AGMagtest1
The index values were corrected in the displayAg() function when set to display Accelerometer and Magnetometer values. AGMagtest2.js is attached.
Adding the Rodrigues.js module to level the compass
The background for this module is described here:
http://forum.espruino.com/conversations/298151/The basic idea is to take the accelerometer readings and determine the vector transformation needed to level the compass. This is done with the function A=FF.Setup(AA,[0,0,1]); where FF is an instance of Rodrigues. The tilt angle theta is then available and subsequent calls to the function BB=FF.RotVector(t) will transform other vectors (magnetometer) into level coordinates.
The attached Rodrigues.js should be placed in the modules subdirectory of your WebIDE project.
The attached program AGMagCompass1.js will then produce the following output when autocalc=2 and W.AGwrite(W.REGval.ODR_G,1);//do gyro and acceleration.M,0.0744,-0.1211,-0.1714,G,-0.1053,0.0413,-0.0948,A,0.1575,0.3104,0.8621, Tilt,21.98781027298,Heading,306.68106708380,Dip,72.16684715533 M,0.0735,-0.1221,-0.1734,G,-0.1128,0.0563,-0.1072,A,0.1559,0.3118,0.8613, Tilt,22.03654082060,Heading,306.02287887278,Dip,72.48561573888 M,0.0730,-0.1207,-0.1713,G,-0.1165,0.0251,-0.0998,A,0.1551,0.3114,0.8618, Tilt,21.98386692289,Heading,306.35699288042,Dip,72.36622200953 M,0.0742,-0.1194,-0.1707,G,-0.0928,0.0712,-0.0823,A,0.1538,0.3145,0.8604, Tilt,22.14296350951,Heading,308.33309975404,Dip,72.42224117781 M,0.0736,-0.1171,-0.1704,G,-0.0679,0.0313,-0.0674,A,0.1558,0.3134,0.8606, Tilt,22.13447453002,Heading,308.75984729535,Dip,72.83761339423 >clearInterval();
Changing W.AGwrite(W.REGval.ODR_G,0);//do acceleration only produces the following output:
M,0.0747,-0.1202,-0.1713,A,0.1563,0.3096,0.8569, Tilt,22.03355580117,Heading,307.43511787449,Dip,72.28617992890 M,0.0763,-0.1235,-0.1719,A,0.1563,0.3094,0.8568, Tilt,22.02918941321,Heading,306.91511852880,Dip,71.66990038608 M,0.0741,-0.1204,-0.1721,A,0.1560,0.3093,0.8569, Tilt,22.01028842165,Heading,306.98156662314,Dip,72.44988041050 M,0.0780,-0.1226,-0.1704,A,0.1559,0.3090,0.8568, Tilt,22.00089649394,Heading,308.38042963598,Dip,71.31936469986 >clearInterval();
```
3 Attachments
-
• #50
Why would you use a
.connect()
function / method to create a Rodrigues instance?I know hat this pattern is typical for connecting devices. But in this case, it is just a transformer, isn't?
To return a constructor function in a require, just set the exported object to it:
exports = Rodrigues;
.If you want to stick with the pattern, you can return
exports.getInstance = function() { return new Rodrigues(); }
to provide a self documenting function.
Translating Arduino code is only as good as the original code.
Having reviewed the fine Vogan poetry in the datasheet a rewrite seems in order.