{"id":12293,"date":"2021-08-14T09:30:16","date_gmt":"2021-08-14T09:30:16","guid":{"rendered":"https:\/\/wolles-elektronikkiste.de\/icm-20948-9-axis-sensor-part-i"},"modified":"2026-02-01T20:04:42","modified_gmt":"2026-02-01T20:04:42","slug":"icm-20948-9-axis-sensor-part-i","status":"publish","type":"post","link":"https:\/\/wolles-elektronikkiste.de\/en\/icm-20948-9-axis-sensor-part-i","title":{"rendered":"ICM-20948 9-Axis Sensor Part I"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\" id=\"uber-den-beitrag\">About this Post<\/h2>\n\n<p>In this article, I introduce another 9-axis sensor, the ICM-20948. A few months ago I had already reported on its predecessor, the <a href=\"https:\/\/wolles-elektronikkiste.de\/en\/mpu9250-9-axis-sensor-module-part-1\" target=\"_blank\" rel=\"noopener\">MPU-9250<\/a>. The MPU-9250 is marked by the manufacturer as &#8220;EoL&#8221; (End of Life). But even though it will certainly be available for quite a while, it is time to take a closer look at the successor.<\/p>\n<p>At first glance, the differences between the ICM-20948 and the MPU-9250 are not great. If you have worked with my library for the MPU-9250, you will quickly get along with my library for ICM-20948.<\/p>\n<p>&#8220;Under the hood&#8221;, i.e. at register level, the differences are considerable. So, even if it seems otherwise &#8211; the creation of the library was more than a small modification of the MPU-9250 library.<\/p>\n\n<h2 class=\"wp-block-heading\" id=\"eigenschaften-und-technische-daten-des-icm-20948\">Features and specifications of the ICM-20948<\/h2>\n\n<p>The ICM-20948 is called the 9-axis sensor because it combines three sensors, each covering three axes. It is:<\/p>\n<ul>\n<li><strong>Accelerometer<\/strong>,<\/li>\n<li><strong>Gyroscope<\/strong>,<\/li>\n<li>and <strong>magnetometer<\/strong>.<\/li>\n<li>In addition, the ICM-20948 is equipped with a thermometer.<\/li>\n<\/ul>\n<p>Such combined sensors are often referred to as IMU for &#8220;<a href=\"https:\/\/de.wikipedia.org\/wiki\/Inertiale_Messeinheit\" target=\"_blank\" rel=\"noopener\">Inertial Measurement Unit<\/a>&#8220;.<\/p>\n<p>I have already described how gyroscopes and an accelerometers work in my <a href=\"https:\/\/wolles-elektronikkiste.de\/en\/mpu6050-accelerometer-and-gyroscope\" target=\"_blank\" rel=\"noopener\">article about the MPU6050<\/a>. The magnetometer works based on the Hall effect. You find a good explanation <a href=\"https:\/\/kompendium.infotip.de\/hall_sensor.html\" target=\"_blank\" rel=\"noopener\">here<\/a>.<\/p>\n<p>&nbsp;<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"alignright size-large is-resized\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/ICM20948_module_small-626x1024.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"626\" height=\"1024\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/ICM20948_module_small-626x1024.jpg\" alt=\"ICM-20948 Module\" class=\"wp-image-12064\" style=\"width:313px;height:512px\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/ICM20948_module_small-626x1024.jpg 626w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/ICM20948_module_small-183x300.jpg 183w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/ICM20948_module_small-768x1256.jpg 768w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/ICM20948_module_small-939x1536.jpg 939w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/ICM20948_module_small.jpg 1000w\" sizes=\"auto, (max-width: 626px) 100vw, 626px\" \/><\/a><\/figure>\n<\/div>\n<p>The main technical specifications of the ICM-20948 are:<\/p>\n<ul>\n<li><strong>Power supply (VDD)<\/strong>: 1.71 &#8211; 3.6 volts\n<ul>\n<li>most modules do not have a voltage regulator<\/li>\n<\/ul>\n<\/li>\n<li><strong>VDDIO:<\/strong> 1.71 &#8211; 1.95 volts\n<ul>\n<li>Tolerance range for I\/O pins<\/li>\n<li>On the module on the right, VDDIO is connected to VDD.<\/li>\n<\/ul>\n<\/li>\n<li><strong>Communication via I2C<\/strong>, the addresses are:\n<ul>\n<li>AD0 set to LOW: 0x68<\/li>\n<li>AD0 set to HIGH: 0x69<\/li>\n<\/ul>\n<\/li>\n<li><strong>Communication via SPI <\/strong><\/li>\n<li><strong>Gyroscope<\/strong>:\n<ul>\n<li>Ranges: +\/-250, +\/-500, +\/-1000, +\/-2000 &nbsp; \u00b0\/s<\/li>\n<li>Data rate: 4.4 Hz &#8211; 9 kHz<\/li>\n<\/ul>\n<\/li>\n<li><strong>Accelerometer<\/strong>:\n<ul>\n<li>Ranges: +\/- 2, +\/-4, +\/-8, +\/-16 g<\/li>\n<li>Data rate: 4.5 Hz &#8211; 4.5 kHz<\/li>\n<\/ul>\n<\/li>\n<li><strong>Magnetometer<\/strong> (AK09916):\n<ul>\n<li>Range: +\/- 4900 \u03bcT<\/li>\n<li>max. data rate: 100 Hz<\/li>\n<\/ul>\n<\/li>\n<li><strong>FIFO<\/strong> (first in, first out) data storage: 512 \/ 4096 bytes<\/li>\n<li><strong>Interrupts<\/strong> (the ones I implemented): FIFO overflow, data ready, FSync and &#8220;wake-on-motion&#8221;<\/li>\n<li>Integrated thermometer <\/li>\n<\/ul>\n<p>The ICM-20948 allows the control of up to five additional sensors via an auxiliary I2C interface. The measured values are stored in the registers of the ICM-20948 and read from there.<\/p>\n<p>The magnetometer is not really integrated into the ICM-20948. It has seperate registers and its own I2C address. You can only control it via the auxiliary interface just described. But don&#8217;t worry, you don&#8217;t have to deal with it because my library takes care for everything in the background.<\/p>\n<p>Further information can be found in the t<a href=\"https:\/\/invensense.tdk.com\/wp-content\/uploads\/2016\/06\/DS-000189-ICM-20948-v1.3.pdf\" target=\"_blank\" rel=\"noopener\">echnical data sheetof the ICM-20948<\/a> and in the <a href=\"https:\/\/www.y-ic.es\/datasheet\/78\/SMDSW.020-2OZ.pdf\" target=\"_blank\" rel=\"noopener\">data sheet of the magnetometer AK09916<\/a>. You can read about the differences between the MPU-9250 and the ICM-20948 <a href=\"https:\/\/invensense.tdk.com\/wp-content\/uploads\/2018\/10\/AN-000146-v2.0-TDK_Migration_MPU_9250toICM-20948.pdf\" target=\"_blank\" rel=\"noopener\">here<\/a>.<\/p>\n\n<h3 class=\"wp-block-heading\" id=\"digital-motion-processor-dmp\">Digital Motion Processor DMP<\/h3>\n\n<p>The ICM-20948 offers the possibility to process the data measured by it and other external sensors. That relieves the microcontroller. For this purpose, the ICM-20948 has the so-called Digital Motion Processor<sup>TM<\/sup>, DMP for short. However, the implementation of the DMP functions would be an effort for me that exceeds my capacities. I have already invested several dozen hours in developing the library.&nbsp;<\/p>\n\n<h2 class=\"wp-block-heading\" id=\"ansteuerung\">Controlling the ICM-20948 <\/h2>\n\n<h3 class=\"wp-block-heading\" id=\"schaltung\">Wiring<\/h3>\n\n<p>When it comes to the power supply, you must ensure that the ICM-20948 can only be operated with up to 3.6 volts. However, this only applies to VDD. The I\/O pins and VDDIO can only tolerate 1.71 &#8211; 1.95 volts. On some modules (such as the one shown above), VDDIO is implemented together with VDD on the VDD pin. In this case, you may only operate it with 1.71-1.95 volts and must use level shifters for both 5-volt and 3.3-volt boards.     <\/p>\n<p>You won&#8217;t have these problems with the more expensive boards from Adafruit, SparkFun or Pimoroni, as they are already equipped with the appropriate level shifters.<\/p>\n<p>Connect the address pin AD0 to HIGH (1.71\u20131.95 V) or GND, depending on which address you want to use. In some example sketches I also use the interrupt pin INT, which I attached to the Arduino pin 2.<\/p>\n<p>Other pins, not used by me:<\/p>\n<ul>\n<li>ADA and ACL are connections for other sensors that are controlled via the auxiliary I2C interface. I only implemented the auxiliary I2C interface for the magnetometer.<\/li>\n<li>NCS is the chip select pin for SPI communication.<\/li>\n<li>You can use FYSYNC as an external interrupt pin. I&#8217;ll have an example sketch for this later.<\/li>\n<\/ul>\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/08\/icm20948_i2c_circuit_arduino_nano-1024x521.webp\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"521\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/08\/icm20948_i2c_circuit_arduino_nano-1024x521.webp\" alt=\"\" class=\"wp-image-25556\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/08\/icm20948_i2c_circuit_arduino_nano-1024x521.webp 1024w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/08\/icm20948_i2c_circuit_arduino_nano-300x153.webp 300w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/08\/icm20948_i2c_circuit_arduino_nano-768x391.webp 768w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/08\/icm20948_i2c_circuit_arduino_nano-1320x672.webp 1320w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/08\/icm20948_i2c_circuit_arduino_nano.webp 1505w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption class=\"wp-element-caption\">ICM-20948, controlled by an Arduino Nano with 1.8 volt voltage regulator and TXS0108E level converter <\/figcaption><\/figure>\n\n<h3 class=\"wp-block-heading\" id=\"verbindung-per-spi\">Connection via SPI<\/h3>\n\n<p>I have also implemented faster control via SPI. You can find a sample sketch as part of the library. <\/p>\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/08\/icm20948_spi_circuit_arduino_nano-1024x602.webp\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"602\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/08\/icm20948_spi_circuit_arduino_nano-1024x602.webp\" alt=\"\" class=\"wp-image-25557\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/08\/icm20948_spi_circuit_arduino_nano-1024x602.webp 1024w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/08\/icm20948_spi_circuit_arduino_nano-300x176.webp 300w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/08\/icm20948_spi_circuit_arduino_nano-768x451.webp 768w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/08\/icm20948_spi_circuit_arduino_nano-1320x776.webp 1320w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/08\/icm20948_spi_circuit_arduino_nano.webp 1443w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption class=\"wp-element-caption\">SPI control of the ICM-20948 with Arduino Nano, 1.8 V voltage regulator, and TXS0108E level converter<\/figcaption><\/figure>\n\n<h3 class=\"wp-block-heading\">ICM-20948, &#8220;version 2&#8221;<\/h3>\n\n<p>There are also modules with the suffix &#8220;Version 2&#8221;, &#8220;v2&#8221; or &#8220;v2.0&#8221;. They have voltage regulators that reduce the input voltage to 1.8 volts. Unfortunately, not all of them have the necessary level shifters for the digital pins. Here are two examples:   <\/p>\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/08\/icm20948_version_2-1024x456.webp\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"456\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/08\/icm20948_version_2-1024x456.webp\" alt=\"ICM-20948, &quot;version 2&quot;\" class=\"wp-image-25312\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/08\/icm20948_version_2-1024x456.webp 1024w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/08\/icm20948_version_2-300x134.webp 300w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/08\/icm20948_version_2-768x342.webp 768w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/08\/icm20948_version_2-1536x684.webp 1536w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/08\/icm20948_version_2-1320x588.webp 1320w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/08\/icm20948_version_2.webp 1800w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption class=\"wp-element-caption\">ICM-20948, &#8220;version 2&#8221;<\/figcaption><\/figure>\n<p>The left module has four MOSFETs for the SDO, SDA, SCL and INT pins. As far as I can tell, the CS pin is unprotected. If you are using SPI, you will need to use a voltage divider. Or you can connect CS to GND if you are only operating one device with the SPI interface.   <\/p>\n<p>The right module only has two MOSFETs, which are combined in the marked 6-pin IC. The MOSFETs handle the SDA and SCL levels. This means you can only use it with I2C. However, there is still a problem with INT. Its HIGH level is 1.8 volts, which is not necessarily interpreted as HIGH by the microcontroller. The ADO pin also appears to be unprotected.      <\/p>\n\n<h2 class=\"wp-block-heading\" id=\"einfuhrung-in-die-icm20948-we-bibliothek\">Introduction to the ICM20948_WE library <\/h2>\n\n<p>I tried some libraries, but I couldn&#8217;t really get excited about any of them. That&#8217;s why I wrote my own library, which you can find <a href=\"https:\/\/github.com\/wollewald\/ICM20948_WE\" target=\"_blank\" rel=\"noopener\">here<\/a> on GitHub. Alternatively, you can install it directly using the library manager of the Arduino IDE.<\/p>\n<p>The problem with the ICM-20948 is that it has an incredible number of setting options due to its 4 sensors plus I2C auxiliary interface. And although I haven&#8217;t implemented all the functions, my library includes fifty-nine public functions. To explain the use of these functions, I have provided the library with thirteen example sketches.<\/p>\n<p>I will now walk you through the example sketches, which is a pretty dry read. Maybe just try them out and come back here if you don&#8217;t understand something.<\/p>\n\n<h2 class=\"wp-block-heading\" id=\"basisdaten-mit-dem-icm-20948-ermitteln\">Determine basic data with the ICM-20948<\/h2>\n\n<h3 class=\"wp-block-heading\" id=\"icm20948-01-acceleration-data-ino\">ICM20948_01_acceleration_data.ino<\/h3>\n\n<p>This first sketch is the one I go into most intensively. Much is repeated in the following sketches.<\/p>\n<p>Before I start, a comment about the data type &#8220;xyzFloat&#8221;. This is a structure (struct) consisting of three float values. I use xyzFloat for all data that has an x, y, and z component.<\/p>\n<\/p>\n<div class=\"scroll-paragraph\">\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-group=\"ICM20948_01_acceleration_data.ino\" data-enlighter-title=\"ICM20948_01_acceleration_data.ino\">#include &lt;Wire.h&gt;\n#include &lt;ICM20948_WE.h&gt;\n#define ICM20948_ADDR 0x68\n\n\/* There are several ways to create your ICM20948 object:\n * ICM20948_WE myIMU = ICM20948_WE()              -&gt; uses Wire \/ I2C Address = 0x68\n * ICM20948_WE myIMU = ICM20948_WE(ICM20948_ADDR) -&gt; uses Wire \/ ICM20948_ADDR\n * ICM20948_WE myIMU = ICM20948_WE(&amp;wire2)        -&gt; uses the TwoWire object wire2 \/ ICM20948_ADDR\n * ICM20948_WE myIMU = ICM20948_WE(&amp;wire2, ICM20948_ADDR) -&gt; all together\n * ICM20948_WE myIMU = ICM20948_WE(CS_PIN, spi);  -&gt; uses SPI, spi is just a flag, see SPI example\n * ICM20948_WE myIMU = ICM20948_WE(&amp;SPI, CS_PIN, spi);  -&gt; uses SPI \/ passes the SPI object, spi is just a flag, see SPI example\n *\/\nICM20948_WE myIMU = ICM20948_WE(ICM20948_ADDR);\n\nvoid setup() {\n  \/\/delay(2000); \/\/ maybe needed for some MCUs, in particular for startup after power off\n  Wire.begin();\n  Serial.begin(115200);\n  while(!Serial) {}\n  \n  if(!myIMU.init()){\n    Serial.println(\"ICM20948 does not respond\");\n  }\n  else{\n    Serial.println(\"ICM20948 is connected\");\n  }\n\n  \/*  This is a method to calibrate. You have to determine the minimum and maximum \n   *  raw acceleration values of the axes determined in the range +\/- 2 g. \n   *  You call the function as follows: setAccOffsets(xMin,xMax,yMin,yMax,zMin,zMax);\n   *  The parameters are floats. \n   *  The calibration changes the slope \/ ratio of raw acceleration vs g. The zero point \n   *  is set as (min + max)\/2.\n   *\/\n  \/\/myIMU.setAccOffsets(-16330.0, 16450.0, -16600.0, 16180.0, -16640.0, 16560.0);\n    \n  \/* The starting point, if you position the ICM20948 flat, is not necessarily 0g\/0g\/1g for x\/y\/z. \n   * The autoOffset function measures offset. It assumes your ICM20948 is positioned flat with its \n   * x,y-plane. The more you deviate from this, the less accurate will be your results.\n   * It overwrites the zero points of setAccOffsets, but keeps the correction of the slope.\n   * The function also measures the offset of the gyroscope data. The gyroscope offset does not   \n   * depend on the positioning.\n   * This function needs to be called after setAccOffsets but before other settings since \n   * it will overwrite settings!\n   * You can query the offsets with the functions:\n   * xyzFloat getAccOffsets()\n   * You can apply the offsets using:\n   * setAccOffsets(xyzFloat yourOffsets)\n   *\/\n  Serial.println(\"Position your ICM20948 flat and don't move it - calibrating...\");\n  delay(1000);\n  myIMU.autoOffsets();\n  Serial.println(\"Done!\"); \n  \n  \/* enables or disables the acceleration sensor, default: enabled *\/\n  \/\/ myIMU.enableAcc(true);\n\n  \/*  ICM20948_ACC_RANGE_2G      2 g   (default)\n   *  ICM20948_ACC_RANGE_4G      4 g\n   *  ICM20948_ACC_RANGE_8G      8 g   \n   *  ICM20948_ACC_RANGE_16G    16 g\n   *\/\n  myIMU.setAccRange(ICM20948_ACC_RANGE_2G);\n  \n  \/*  Choose a level for the Digital Low Pass Filter or switch it off.  \n   *  ICM20948_DLPF_0, ICM20948_DLPF_2, ...... ICM20948_DLPF_7, ICM20948_DLPF_OFF \n   *  \n   *  IMPORTANT: This needs to be ICM20948_DLPF_7 if DLPF is used in cycle mode!\n   *  \n   *  DLPF       3dB Bandwidth [Hz]      Output Rate [Hz]\n   *    0              246.0               1125\/(1+ASRD) (default)\n   *    1              246.0               1125\/(1+ASRD)\n   *    2              111.4               1125\/(1+ASRD)\n   *    3               50.4               1125\/(1+ASRD)\n   *    4               23.9               1125\/(1+ASRD)\n   *    5               11.5               1125\/(1+ASRD)\n   *    6                5.7               1125\/(1+ASRD) \n   *    7              473.0               1125\/(1+ASRD)\n   *    OFF           1209.0               4500\n   *    \n   *    ASRD = Accelerometer Sample Rate Divider (0...4095)\n   *    You achieve lowest noise using level 6  \n   *\/\n  myIMU.setAccDLPF(ICM20948_DLPF_6);    \n  \n  \/*  Acceleration sample rate divider divides the output rate of the accelerometer.\n   *  Sample rate = Basic sample rate \/ (1 + divider) \n   *  It can only be applied if the corresponding DLPF is not off!\n   *  Divider is a number 0...4095 (different range compared to gyroscope)\n   *  If sample rates are set for the accelerometer and the gyroscope, the gyroscope\n   *  sample rate has priority.\n   *\/\n  myIMU.setAccSampleRateDivider(10);\n}\n\nvoid loop() {\n  xyzFloat accRaw;\n  xyzFloat corrAccRaw;\n  xyzFloat gVal;\n  myIMU.readSensor();\n  myIMU.getAccRawValues(&amp;accRaw);\n  myIMU.getCorrectedAccRawValues(&amp;corrAccRaw);\n  myIMU.getGValues(&amp;gVal);\n  float resultantG = myIMU.getResultantG(&amp;gVal);\n\n   \n  Serial.println(\"Raw acceleration values (x,y,z):\");\n  Serial.print(accRaw.x);\n  Serial.print(\"   \");\n  Serial.print(accRaw.y);\n  Serial.print(\"   \");\n  Serial.println(accRaw.z);\n\n  Serial.println(\"Corrected raw acceleration values (x,y,z):\");\n  Serial.print(corrAccRaw.x);\n  Serial.print(\"   \");\n  Serial.print(corrAccRaw.y);\n  Serial.print(\"   \");\n  Serial.println(corrAccRaw.z);\n\n  Serial.println(\"g-values (x,y,z):\");\n  Serial.print(gVal.x);\n  Serial.print(\"   \");\n  Serial.print(gVal.y);\n  Serial.print(\"   \");\n  Serial.println(gVal.z);\n\n  Serial.print(\"Resultant g: \");\n  Serial.println(resultantG);\n  Serial.println(\"*************************************\");\n \n  delay(1000);\n}<\/pre>\n<p>\u00a0<\/p>\n<\/div>\n<p>\n\n<h4 class=\"wp-block-heading\" id=\"initialisierung-und-offsets\">Initialization and offsets<\/h4>\n\n<p>I have implemented several constructors. This allows you to pass the I2C address and\/or the I2C object. The latter is interesting if, for example, you want to use both I2C interfaces of an ESP32.<\/p>\n<p>The function <code>init()<\/code> first resets the ICM-20948 and writes default values to some registers. <code>init()<\/code> returns &#8220;false&#8221; if the ICM-20948 does not answer, otherwise true.<\/p>\n<p>In the motionless state, only the acceleration due to gravity acts on the ICM-20948. If it is positioned flat (i.e. with its x,y plane), the g value should be zero for the x and y axes and one for the z axis. However, these values are more or less shifted. The function <code>autoOffsets()<\/code> measures the offset values which are subtracted from future measured values. However, it does not correct the slope.<\/p>\n<p><code>autoOffsets()<\/code> works only then reliably,<\/p>\n<ul>\n<li>if the module lies flat with its x,y plane,<\/li>\n<li>is not moved, and<\/li>\n<li>the function is called as the first function in the setup (because it changes certain settings)<\/li>\n<\/ul>\n<p>Alternatively, you can use the function <code>setAccOffsets()<\/code>. It leads to less good results regarding the zero point, but it is more accurate at larger angles. In addition, it corrects the slope, and you do not have to position the module flat at program start.<\/p>\n\n<h4 class=\"wp-block-heading\" id=\"weitere-einstellungen\">Other settings <\/h4>\n\n<p>The function <code>setAccRange()<\/code> sets the range for the acceleration measurements.<\/p>\n<p>To control the data rate of the accelerometer, use the function <code>setAccSampleRateDivider(divider)<\/code>.<\/p>\n<\/p>\n<p class=\"ql-center-displayed-equation\" style=\"line-height: 41px;\"><span class=\"ql-right-eqno\"> &nbsp; <\/span><span class=\"ql-left-eqno\"> &nbsp; <\/span><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/ql-cache\/quicklatex.com-71de542e43adb4511a5f68317d41b18e_l3.png\" height=\"41\" width=\"565\" class=\"ql-img-displayed-equation quicklatex-auto-format\" alt=\"&#92;&#091; &#92;&#116;&#101;&#120;&#116;&#123;&#97;&#99;&#99;&#101;&#108;&#101;&#114;&#97;&#116;&#105;&#111;&#110;&#32;&#100;&#97;&#116;&#97;&#32;&#114;&#97;&#116;&#101;&#125;&#61;&#92;&#102;&#114;&#97;&#99;&#123;&#49;&#49;&#50;&#53;&#125;&#123;&#49;&#43;&#100;&#105;&#118;&#105;&#100;&#101;&#114;&#125;&#92;&#59;&#091;&#92;&#116;&#101;&#120;&#116;&#123;&#72;&#122;&#125;&#093;&#92;&#59;&#92;&#59;&#92;&#59;&#92;&#59;&#92;&#59;&#92;&#59;&#92;&#59;&#92;&#59;&#92;&#116;&#101;&#120;&#116;&#123;&#109;&#105;&#116;&#125;&#92;&#59;&#92;&#59;&#100;&#105;&#118;&#105;&#100;&#101;&#114;&#32;&#61;&#32;&#48;&#46;&#46;&#46;&#52;&#48;&#57;&#53; &#92;&#093;\" title=\"Rendered by QuickLaTeX.com\"\/><\/p>\n<p>\n\n<p>However, this only works if the digital low pass filter (DLPF) is activated. With <code>setAccDLPF(level)<\/code> you enable the DLPF and select the level. The parameter <code>ICM20948_DLPF_OFF<\/code> disables the DLPF. The higher the level, the lower the noise. Only level 7 does not fit in this series in this respect. The disadvantage of strong noise reduction is reduced response time. This means that when the acceleration changes, it takes a while for the MPU9250 to output the correct value.<\/p>\n<p>With <code>enableAcc(true\/false)<\/code> you can switch the accelerometer on or off.<\/p>\n\n<h4 class=\"wp-block-heading\" id=\"die-ergebnisse\">The results<\/h4>\n\n<p>You can query the measured values with the following functions:<\/p>\n<ul>\n<li><code>readSensor()<\/code> reads the data registers in burst method (i.e. &#8220;in one go&#8221;) and writes the result to a buffer array.<br><ul>\n<li>Without a previous call of <code>readSensor()<\/code>, you will not get updated values.<\/li>\n<\/ul>\n<\/li>\n<li><code>getAccRawValues()<\/code> provides the raw values of the acceleration in the ICM-20948 data register.<\/li>\n<li><code>getCorrectedAccRawValues()<\/code> reads the raw values and corrects them for the offsets.<\/li>\n<li><code>getGValues()<\/code> provides the acceleration values in g (based on the corrected raw data).<\/li>\n<li><code>getResultantG(gValue)<\/code> calculates the resulting acceleration from a g-value triple, i.e. the absolute value of the sum of the three vectors.<\/li>\n<\/ul>\n<\/p>\n<p class=\"ql-center-displayed-equation\" style=\"line-height: 23px;\"><span class=\"ql-right-eqno\"> &nbsp; <\/span><span class=\"ql-left-eqno\"> &nbsp; <\/span><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/ql-cache\/quicklatex.com-e415876d0493a2aebdb57079133d69fc_l3.png\" height=\"23\" width=\"500\" class=\"ql-img-displayed-equation quicklatex-auto-format\" alt=\"&#92;&#091; &#92;&#116;&#101;&#120;&#116;&#123;&#114;&#101;&#115;&#117;&#108;&#116;&#97;&#110;&#116;&#71;&#125;&#61;&#92;&#115;&#113;&#114;&#116;&#123;&#40;&#103;&#86;&#97;&#108;&#117;&#101;&#46;&#120;&#41;&#94;&#50;&#43;&#40;&#103;&#86;&#97;&#108;&#117;&#101;&#46;&#121;&#41;&#94;&#50;&#43;&#40;&#103;&#86;&#97;&#108;&#117;&#101;&#46;&#122;&#41;&#94;&#50;&#125;&#32;&#92;&#59;&#92;&#59;&#92;&#116;&#101;&#120;&#116;&#123;&#091;&#103;&#093;&#125; &#92;&#093;\" title=\"Rendered by QuickLaTeX.com\"\/><\/p>\n<p>\n\n<p>If only gravity acts on the ICM-20948, the resultant should always be 1. With the resultant function, you can easily measure accelerations without having to align the movement to one axis. Simply subtract 1 to compensate for gravity.<\/p>\n\n<h4 class=\"wp-block-heading\" id=\"die-ausgabe-von-icm20948-01-acceleration-data-ino\">The output of ICM20948_01_acceleration_data.ino<\/h4>\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/output_acc_data.png\"><img loading=\"lazy\" decoding=\"async\" width=\"766\" height=\"400\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/output_acc_data.png\" alt=\"ICM-20948 - Output of ICM20948_01_acceleration_data.ino\" class=\"wp-image-12083\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/output_acc_data.png 766w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/output_acc_data-300x157.png 300w\" sizes=\"auto, (max-width: 766px) 100vw, 766px\" \/><\/a><figcaption class=\"wp-element-caption\">Output of ICM20948_01_acceleration_data.ino<\/figcaption><\/figure>\n\n<h3 class=\"wp-block-heading\" id=\"icm20948-02-gyroscope-data-ino\">ICM20948_02_gyroscope_data.ino<\/h3>\n\n<p>Since you already know some functions, the explanation of the gyroscope sketch can be much shorter.<\/p>\n<\/p>\n<div class=\"scroll-paragraph\">\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-group=\"ICM20948_02_gyroscope_data.ino\" data-enlighter-title=\"ICM20948_02_gyroscope_data.ino\">#include &lt;Wire.h&gt;\n#include &lt;ICM20948_WE.h&gt;\n#define ICM20948_ADDR 0x68\n\n\/* There are several ways to create your ICM20948 object:\n * ICM20948_WE myIMU = ICM20948_WE()              -&gt; uses Wire \/ I2C Address = 0x68\n * ICM20948_WE myIMU = ICM20948_WE(ICM20948_ADDR) -&gt; uses Wire \/ ICM20948_ADDR\n * ICM20948_WE myIMU = ICM20948_WE(&amp;wire2)        -&gt; uses the TwoWire object wire2 \/ ICM20948_ADDR\n * ICM20948_WE myIMU = ICM20948_WE(&amp;wire2, ICM20948_ADDR) -&gt; all together\n * ICM20948_WE myIMU = ICM20948_WE(CS_PIN, spi);  -&gt; uses SPI, spi is just a flag, see SPI example\n * ICM20948_WE myIMU = ICM20948_WE(&amp;SPI, CS_PIN, spi);  -&gt; uses SPI \/ passes the SPI object, spi is just a flag, see SPI example\n *\/\nICM20948_WE myIMU = ICM20948_WE(ICM20948_ADDR);\n\nvoid setup() {\n  \/\/delay(2000); \/\/ maybe needed for some MCUs, in particular for startup after power off\n  Wire.begin();\n  Serial.begin(115200);\n  while(!Serial) {}\n  \n  if(!myIMU.init()){\n    Serial.println(\"ICM20948 does not respond\");\n  }\n  else{\n    Serial.println(\"ICM20948 is connected\");\n  }\n\n  Serial.println(\"Position your ICM20948 flat and don't move it - calibrating...\");\n  delay(1000);\n  myIMU.autoOffsets();\n  Serial.println(\"Done!\"); \n  \n  \/*  The gyroscope data is not zero, even if you don't move the ICM20948. \n   *  To start at zero, you can apply offset values. These are the gyroscope raw values you obtain\n   *  using the +\/- 250 degrees\/s range. \n   *  Use either autoOffsets or setGyrOffsets, not both.\n   *  You can query the offsets with the function:\n   *  xyzFloat getGyrOffsets()\n  *\/\n  \/\/myIMU.setGyrOffsets(-115.0, 130.0, 105.0);\n  \n  \/* enables or disables the gyroscope sensor, default: enabled *\/\n  \/\/ myIMU.enableGyr(false);\n\n  \/*  ICM20948_GYRO_RANGE_250       250 degrees per second (default)\n   *  ICM20948_GYRO_RANGE_500       500 degrees per second\n   *  ICM20948_GYRO_RANGE_1000     1000 degrees per second\n   *  ICM20948_GYRO_RANGE_2000     2000 degrees per second\n   *\/\n  myIMU.setGyrRange(ICM20948_GYRO_RANGE_250);\n  \n  \/*  Choose a level for the Digital Low Pass Filter or switch it off. \n   *  ICM20948_DLPF_0, ICM20948_DLPF_2, ...... ICM20948_DLPF_7, ICM20948_DLPF_OFF \n   *  \n   *  DLPF       3dB Bandwidth [Hz]      Output Rate [Hz]\n   *    0              196.6               1125\/(1+GSRD) \n   *    1              151.8               1125\/(1+GSRD)\n   *    2              119.5               1125\/(1+GSRD)\n   *    3               51.2               1125\/(1+GSRD)\n   *    4               23.9               1125\/(1+GSRD)\n   *    5               11.6               1125\/(1+GSRD)\n   *    6                5.7               1125\/(1+GSRD) \n   *    7              361.4               1125\/(1+GSRD)\n   *    OFF          12106.0               9000\n   *    \n   *    GSRD = Gyroscope Sample Rate Divider (0...255)\n   *    You achieve lowest noise using level 6  \n   *\/\n  myIMU.setGyrDLPF(ICM20948_DLPF_6);  \n  \n  \/*  Gyroscope sample rate divider divides the output rate of the gyroscope.\n   *  Sample rate = Basic sample rate \/ (1 + divider) \n   *  It can only be applied if the corresponding DLPF is not OFF!\n   *  Divider is a number 0...255\n   *  If sample rates are set for the accelerometer and the gyroscope, the gyroscope\n   *  sample rate has priority.\n   *\/\n  \/\/myIMU.setGyrSampleRateDivider(10);\n}\n\nvoid loop() {\n  xyzFloat gyrRaw; \n  xyzFloat gyr;\n  myIMU.readSensor();\n  myIMU.getCorrectedGyrRawValues(&amp;gyrRaw);\n  myIMU.getGyrValues(&amp;gyr);\n    \n  Serial.println(\"Raw gyroscope values (x,y,z):\");\n  Serial.print(gyrRaw.x);\n  Serial.print(\"   \");\n  Serial.print(gyrRaw.y);\n  Serial.print(\"   \");\n  Serial.println(gyrRaw.z);\n\n  Serial.println(\"Gyroscope values (x,y,z):\");\n  Serial.print(gyr.x);\n  Serial.print(\"   \");\n  Serial.print(gyr.y);\n  Serial.print(\"   \");\n  Serial.println(gyr.z);\n  Serial.println();\n\n  delay(500);\n}<\/pre>\n<p>\u00a0<\/p>\n<\/div>\n<p>\n\n<p>Again, you can use the <code>autoOffsets()<\/code> function. The gyroscope should indicate zero or at least fluctuate around zero for all axes in the motionless state. However, you will notice some offset that is independent of the orientation. Alternatively, apply the values determined in the measuring range +\/-250 \u00b0\/s in <code>setGyrOffsets()<\/code>. I&#8217;ll come back to that in the section of the calibration sketch.<\/p>\n<p>You activate the low-pass filter (DLPF) with <code>setGyrDLPF(value)<\/code> and set the level. Here, too, a stronger filter leads to reduced reaction speed. Level 7 is an exception in this respect. <code>ICM20948_DLPF_OFF<\/code> disables the DLPF.<\/p>\n<p>Other features:<\/p>\n<ul>\n<li><code>setGyrSampleRateDivider()<\/code> works similar to the accelerometer.<\/li>\n<li><code>setGyrRange()<\/code> defines the measuring range.<\/li>\n<li><code>enableGyr(true\/false)<\/code> enables or disables the gyroscope.<\/li>\n<li><code>getGyrRawValues()<\/code> returns the currently available raw data.<\/li>\n<li><code>getCorrectedGyrRawValues()<\/code> subtracts the offsets from the raw data and returns the corrected data.<\/li>\n<li><code>getGyrValues()<\/code> provides the gyroscope data in degrees\/second, based on the corrected raw data.<\/li>\n<\/ul>\n\n<h4 class=\"wp-block-heading\" id=\"die-ausgabe-von-icm20948-02-gyroscope-data-ino\">The output of ICM20948_02_gyroscope_data.ino<\/h4>\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/output_gyr_data.png\"><img loading=\"lazy\" decoding=\"async\" width=\"766\" height=\"349\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/output_gyr_data.png\" alt=\"ICM-20948 - Edition of ICM20948_02_gyroscope_data.ino\" class=\"wp-image-12088\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/output_gyr_data.png 766w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/output_gyr_data-300x137.png 300w\" sizes=\"auto, (max-width: 766px) 100vw, 766px\" \/><\/a><figcaption class=\"wp-element-caption\">Output of ICM20948_02_gyroscope_data.ino<\/figcaption><\/figure>\n\n<h3 class=\"wp-block-heading\" id=\"icm20948-03-magnetometer-ino\">ICM20948_03_magnetometer.ino<\/h3>\n\n<p>The magnetometer (AK09916) behaves like a separate component. It has its own I2C address, own registers and must therefore be initialized separately. If you apply an I2C scanner to the ICM-20948, you won&#8217;t detect the magnetometer. The magnetometer is not directly accessible, it is behind the ICM-20948, so to speak. You control it via the auxiliary I2C interface described above, which is provided by the ICM-20948. However, you won&#8217;t notice any of this, as the library manages everything in the background.<\/p>\n<\/p>\n<div class=\"scroll-paragraph\">\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-group=\"ICM20948_03_magnetometer.ino \" data-enlighter-title=\"ICM20948_03_magnetometer.ino \">#include &lt;Wire.h&gt;\n#include &lt;ICM20948_WE.h&gt;\n#define ICM20948_ADDR 0x68\n\n\/* There are several ways to create your ICM20948 object:\n * ICM20948_WE myIMU = ICM20948_WE()              -&gt; uses Wire \/ I2C Address = 0x68\n * ICM20948_WE myIMU = ICM20948_WE(ICM20948_ADDR) -&gt; uses Wire \/ ICM20948_ADDR\n * ICM20948_WE myIMU = ICM20948_WE(&amp;wire2)        -&gt; uses the TwoWire object wire2 \/ ICM20948_ADDR\n * ICM20948_WE myIMU = ICM20948_WE(&amp;wire2, ICM20948_ADDR) -&gt; all together\n * ICM20948_WE myIMU = ICM20948_WE(CS_PIN, spi);  -&gt; uses SPI, spi is just a flag, see SPI example\n * ICM20948_WE myIMU = ICM20948_WE(&amp;SPI, CS_PIN, spi);  -&gt; uses SPI \/ passes the SPI object, spi is just a flag, see SPI example\n *\/\nICM20948_WE myIMU = ICM20948_WE(ICM20948_ADDR);\n\nvoid setup() {\n  \/\/delay(2000); \/\/ maybe needed for some MCUs, in particular for startup after power off\n  Wire.begin();\n  Serial.begin(115200);\n  while (!Serial) {}\n\n  if (!myIMU.init()) {\n    Serial.println(\"ICM20948 does not respond\");\n  }\n  else {\n    Serial.println(\"ICM20948 is connected\");\n  }\n\n  if (!myIMU.initMagnetometer()) {\n    Serial.println(\"Magnetometer does not respond\");\n  }\n  else {\n    Serial.println(\"Magnetometer is connected\");\n  }\n\n  \/* You can set the following modes for the magnetometer:\n   * AK09916_PWR_DOWN          Power down to save energy\n   * AK09916_TRIGGER_MODE      Measurements on request, a measurement is triggered by \n   *                           calling setMagOpMode(AK09916_TRIGGER_MODE)\n   * AK09916_CONT_MODE_10HZ    Continuous measurements, 10 Hz rate\n   * AK09916_CONT_MODE_20HZ    Continuous measurements, 20 Hz rate\n   * AK09916_CONT_MODE_50HZ    Continuous measurements, 50 Hz rate\n   * AK09916_CONT_MODE_100HZ   Continuous measurements, 100 Hz rate (default)\n   *\/\n  myIMU.setMagOpMode(AK09916_CONT_MODE_20HZ);\n  \/\/ delay(50); \/\/ add a delay of 1000\/magRate to avoid first mag value being zero \n}\n\nvoid loop() {\n  xyzFloat magValue; \/\/ x\/y\/z magnetic flux density [\u00b5T] \n  myIMU.readSensor();\n  myIMU.getMagValues(&amp;magValue);\n\n  Serial.println(\"Magnetometer Data in \u00b5Tesla: \");\n  Serial.print(magValue.x);\n  Serial.print(\"   \");\n  Serial.print(magValue.y);\n  Serial.print(\"   \");\n  Serial.println(magValue.z);\n\n  delay(1000);\n}\n<\/pre>\n<p>\u00a0<\/p>\n<\/div>\n<p>\n\n<h4 class=\"wp-block-heading\" id=\"einstellungen-fur-das-magnetometer\">Magnetometer settings<\/h4>\n\n<p>The magnetometer has a power-down mode, a trigger mode and four continuous modes. The continuous modes differ in data rate, namely 10, 20, 40 or 100 Hz. The mode is set with <code>setMagOpMode()<\/code>.<\/p>\n<p>You retrieve the measured values with <code>getMagValues()<\/code>. The result is output in microtesla. The function returns the values that are currently in the data buffer. Before that, you have to call <code>readSensor()<\/code> to update the data buffer with the latest sensor data.<\/p>\n<p>In trigger mode, a measurement is initiated with <code>setMagOpMode(AK09916_TRIGGER_MODE)<\/code>. If you choose this option, you must give the magnetometer enough time to perform the measurement and transmit the data to the ICM-20948 data registers.<\/p>\n\n<h4 class=\"wp-block-heading\" id=\"die-ausgabe-von-icm20948-03-magnetometer-ino\">The output of ICM20948_03_magnetometer.ino<\/h4>\n\n<p>For the following output, I rotated the ICM-20948 flat in its x,y plane:<\/p>\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/output_mag_data.png\"><img loading=\"lazy\" decoding=\"async\" width=\"766\" height=\"349\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/output_mag_data.png\" alt=\"ICM20948 - Output of ICM20948_03_magnetometer.ino\" class=\"wp-image-12091\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/output_mag_data.png 766w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/output_mag_data-300x137.png 300w\" sizes=\"auto, (max-width: 766px) 100vw, 766px\" \/><\/a><figcaption class=\"wp-element-caption\">Output of ICM20948_03_magnetometer.ino<\/figcaption><\/figure>\n\n<p>In Central Europe, the magnetic flux density of the Earth&#8217;s magnetic field is about 20 microns in the horizontal and around 44 \u00b5T in the vertical (source: German Wikipedia). Accordingly, the difference between the maximum and minimum value for rotation in the horizontal or vertical should be 40 and 88 \u03bcT respectively. You probably won&#8217;t measure that values because:<\/p>\n<ul>\n<li>Again, there are offsets.<\/li>\n<li>You are probably measuring indoors, and depending on the construction of the building, the Earth&#8217;s magnetic field is shielded.<\/li>\n<li>When measuring on a breadboard, the jumper cables and metal inside the breadboard will influence the measurements.<\/li>\n<\/ul>\n\n<h3 class=\"wp-block-heading\" id=\"icm20948-04-calibration-ino\">ICM20948_04_calibration.ino<\/h3>\n\n<p>This sketch is designed to help you determine the offsets for the accelerometer and gyroscope. To do this, first set the lowest measuring range and the maximum low-pass filter. This ensures high resolution and low noise.<\/p>\n<p>For the offset determination of the accelerometer, turn the ICM-20948 slowly (!) around its axes and note the maximum and minimum raw values. It is best to have your elbows on the table when doing this, as any shaking will result in additional acceleration. You then use this data for the <code>setAccOffsets()<\/code> function. Internally, the offsets are determined from this. When you change the measuring range, the offsets are automatically adjusted. With this method you are no longer dependent on the level orientation of the ICM-20948 at program start. For the determination of precise small angles, however, I still recommend the <code>autoOffsets()<\/code> function.<\/p>\n<p>For the gyroscope offsets you do not need to rotate the ICM-20948 because the offset is independent of the inclination. You apply the values for the x-, y- and z-axis as parameters in <code>setGyrOffsets()<\/code>.<\/p>\n<\/p>\n<div class=\"scroll-paragraph\">\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-group=\"ICM20948_04_calibration.ino\" data-enlighter-title=\"ICM20948_04_calibration.ino\">#include &lt;Wire.h&gt;\n#include &lt;ICM20948_WE.h&gt;\n#define ICM20948_ADDR 0x68\n\n\/* There are several ways to create your ICM20948 object:\n * ICM20948_WE myIMU = ICM20948_WE()              -&gt; uses Wire \/ I2C Address = 0x68\n * ICM20948_WE myIMU = ICM20948_WE(ICM20948_ADDR) -&gt; uses Wire \/ ICM20948_ADDR\n * ICM20948_WE myIMU = ICM20948_WE(&amp;wire2)        -&gt; uses the TwoWire object wire2 \/ ICM20948_ADDR\n * ICM20948_WE myIMU = ICM20948_WE(&amp;wire2, ICM20948_ADDR) -&gt; all together\n * ICM20948_WE myIMU = ICM20948_WE(CS_PIN, spi);  -&gt; uses SPI, spi is just a flag, see SPI example\n * ICM20948_WE myIMU = ICM20948_WE(&amp;SPI, CS_PIN, spi);  -&gt; uses SPI \/ passes the SPI object, spi is just a flag, see SPI example\n *\/\nICM20948_WE myIMU = ICM20948_WE(ICM20948_ADDR);\n\nvoid setup() {\n  \/\/delay(2000); \/\/ maybe needed for some MCUs, in particular for startup after power off\n  Wire.begin();\n  Serial.begin(115200);\n  while(!Serial) {}\n  \n  if(!myIMU.init()){\n    Serial.println(\"ICM20948 does not respond\");\n  }\n  else{\n    Serial.println(\"ICM20948 is connected\");\n  }\n\n  \/*  This is a method to calibrate. You have to determine the minimum and maximum \n   *  raw acceleration values of the axes determined in the range +\/- 2 g. \n   *  You call the function as follows: setAccOffsets(xMin,xMax,yMin,yMax,zMin,zMax);\n   *  The parameters are floats. \n   *  The calibration changes the slope \/ ratio of raw accleration vs g. The zero point is \n   *  set as (min + max)\/2.\n   *\/\n  myIMU.setAccOffsets(-16330.0, 16450.0, -16600.0, 16180.0, -16520.0, 16690.0);\n    \n  \/*  The gyroscope data is not zero, even if you don't move the ICM20948. \n   *  To start at zero, you can apply offset values. These are the gyroscope raw values you obtain\n   *  using the +\/- 250 degrees\/s range. \n   *  Use either autoOffset or setGyrOffsets, not both.\n   *\/\n  myIMU.setGyrOffsets(-115.0, 130.0, 105.0);\n    \n  \/*  ICM20948_ACC_RANGE_2G      2 g   (default)\n   *  ICM20948_ACC_RANGE_4G      4 g\n   *  ICM20948_ACC_RANGE_8G      8 g   \n   *  ICM20948_ACC_RANGE_16G    16 g\n   *\/\n  myIMU.setAccRange(ICM20948_ACC_RANGE_2G); \/\/ highest res for calibration\n  \n  \/*  Choose a level for the Digital Low Pass Filter or switch it off.  \n   *  ICM20948_DLPF_0, ICM20948_DLPF_2, ...... ICM20948_DLPF_7, ICM20948_DLPF_OFF \n   *  \n   *  IMPORTANT: This needs to be ICM20948_DLPF_7 if DLPF is used in cycle mode!\n   *  \n   *  DLPF       3dB Bandwidth [Hz]      Output Rate [Hz]\n   *    0              246.0               1125\/(1+ASRD) \n   *    1              246.0               1125\/(1+ASRD)\n   *    2              111.4               1125\/(1+ASRD)\n   *    3               50.4               1125\/(1+ASRD)\n   *    4               23.9               1125\/(1+ASRD)\n   *    5               11.5               1125\/(1+ASRD)\n   *    6                5.7               1125\/(1+ASRD) \n   *    7              473.0               1125\/(1+ASRD)\n   *    OFF           1209.0               4500\n   *    \n   *    ASRD = Accelerometer Sample Rate Divider (0...4095)\n   *    You achieve lowest noise using level 6  \n   *\/\n  myIMU.setAccDLPF(ICM20948_DLPF_6); \/\/ lowest noise for calibration   \n  \n  \/*  ICM20948_GYRO_RANGE_250       250 degrees per second (default)\n   *  ICM20948_GYRO_RANGE_500       500 degrees per second\n   *  ICM20948_GYRO_RANGE_1000     1000 degrees per second\n   *  ICM20948_GYRO_RANGE_2000     2000 degrees per second\n   *\/\n  myIMU.setGyrRange(ICM20948_GYRO_RANGE_250); \/\/highest resolution for calibration\n  \n  \/*  Choose a level for the Digital Low Pass Filter or switch it off. \n   *  ICM20948_DLPF_0, ICM20948_DLPF_2, ...... ICM20948_DLPF_7, ICM20948_DLPF_OFF \n   *  \n   *  DLPF       3dB Bandwidth [Hz]      Output Rate [Hz]\n   *    0              196.6               1125\/(1+GSRD) \n   *    1              151.8               1125\/(1+GSRD)\n   *    2              119.5               1125\/(1+GSRD)\n   *    3               51.2               1125\/(1+GSRD)\n   *    4               23.9               1125\/(1+GSRD)\n   *    5               11.6               1125\/(1+GSRD)\n   *    6                5.7               1125\/(1+GSRD) \n   *    7              361.4               1125\/(1+GSRD)\n   *    OFF          12106.0               9000\n   *    \n   *    GSRD = Gyroscope Sample Rate Divider (0...255)\n   *    You achieve lowest noise using level 6  \n   *\/\n  myIMU.setGyrDLPF(ICM20948_DLPF_6); \/\/ lowest noise for calibration\n  \n  \/*  Choose a level for the Digital Low Pass Filter. \n   *  ICM20948_DLPF_0, ICM20948_DLPF_2, ...... ICM20948_DLPF_7, ICM20948_DLPF_OFF \n   *  \n   *  DLPF          Bandwidth [Hz]      Output Rate [Hz]\n   *    0             7932.0                    9\n   *    1              217.9                 1125\n   *    2              123.5                 1125\n   *    3               65.9                 1125\n   *    4               34.1                 1125\n   *    5               17.3                 1125\n   *    6                8.8                 1125\n   *    7             7932.0                    9\n   *                 \n   *    \n   *    GSRD = Gyroscope Sample Rate Divider (0...255)\n   *    You achieve lowest noise using level 6  \n   *\/\n  myIMU.setTempDLPF(ICM20948_DLPF_6); \/\/ lowest noise for calibration\n}\n\nvoid loop() {\n  xyzFloat accRaw;\n  xyzFloat gyrRaw;\n  xyzFloat corrAccRaw;\n  xyzFloat corrGyrRaw;\n  xyzFloat gVal;\n  myIMU.readSensor();\n  myIMU.getAccRawValues(&amp;accRaw);\n  myIMU.getGyrRawValues(&amp;gyrRaw);\n  myIMU.getCorrectedAccRawValues(&amp;corrAccRaw);\n  myIMU.getCorrectedGyrRawValues(&amp;corrGyrRaw);\n  myIMU.getGValues(&amp;gVal);\n  \n  Serial.println(\"Acceleration raw values without offset:\");\n  Serial.print(accRaw.x);\n  Serial.print(\"   \");\n  Serial.print(accRaw.y);\n  Serial.print(\"   \");\n  Serial.println(accRaw.z);\n\n  Serial.println(\"Gyroscope raw values without offset:\");\n  Serial.print(gyrRaw.x);\n  Serial.print(\"   \");\n  Serial.print(gyrRaw.y);\n  Serial.print(\"   \");\n  Serial.println(gyrRaw.z);\n\n  Serial.println(\"Acceleration raw values with offset:\");\n  Serial.print(corrAccRaw.x);\n  Serial.print(\"   \");\n  Serial.print(corrAccRaw.y);\n  Serial.print(\"   \");\n  Serial.println(corrAccRaw.z);\n\n  Serial.println(\"Gyroscope raw values with offset:\");\n  Serial.print(corrGyrRaw.x);\n  Serial.print(\"   \");\n  Serial.print(corrGyrRaw.y);\n  Serial.print(\"   \");\n  Serial.println(corrGyrRaw.z);\n\n  Serial.println(\"g-values, based on corrected raws (x,y,z):\");\n  Serial.print(gVal.x);\n  Serial.print(\"   \");\n  Serial.print(gVal.y);\n  Serial.print(\"   \");\n  Serial.println(gVal.z);\n\n\n  Serial.println(\"********************************************\");\n\n  delay(500);\n}<\/pre>\n<p>\u00a0<\/p>\n<\/div>\n<p>\n\n<h3 class=\"wp-block-heading\" id=\"alles-zusammen-icm20948-05-acc-gyr-temp-mag-data-ino\">All together: ICM20948_05_acc_gyr_temp_mag_data.ino<\/h3>\n\n<p>Using this sketch, you can determine the acceleration, gyroscope values, magnetometer values and temperature. You query the temperature with <code>getTemperature()<\/code>. I have already explained all other functions. You can find the sketch in the examples.<\/p>\n<p>The thermometer is not so much used to measure the ambient temperature as to track the temperature in the ICM-20948. It is higher than the room temperature and increases in operation depending on the measurement conditions.<\/p>\n\n<h4 class=\"wp-block-heading\" id=\"die-ausgabe-von-icm20948-05-acc-gyr-temp-mag-data-ino\">The output of ICM20948_05_acc_gyr_temp_mag_data.ino<\/h4>\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/output_all_data.png\"><img loading=\"lazy\" decoding=\"async\" width=\"789\" height=\"349\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/output_all_data.png\" alt=\"The output of ICM20948_05_acc_gyr_temp_mag_data.ino\" class=\"wp-image-12103\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/output_all_data.png 789w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/output_all_data-300x133.png 300w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/output_all_data-768x340.png 768w\" sizes=\"auto, (max-width: 789px) 100vw, 789px\" \/><\/a><figcaption class=\"wp-element-caption\">The output of ICM20948_05_acc_gyr_temp_mag_data.ino<\/figcaption><\/figure>\n\n<h2 class=\"wp-block-heading\" id=\"winkel-mit-dem-icm-20948-messen\">How to measure angles with the ICM-20948 <\/h2>\n\n<p>You can use the (earth) acceleration data to calculate tilt angles. You have to make sure that no additional acceleration acts on the ICM-20948. I have implemented two methods for this.<\/p>\n\n<h3 class=\"wp-block-heading\" id=\"icm20948-06-angles-and-orientation-ino\">ICM20948_06_angles_and_orientation.ino <\/h3>\n\n<p>With the method presented in this sketch, the angle \u03b1 between the axes and the horizontal is calculated quite simply from the arcussine of the acceleration value.<\/p>\n<\/p>\n<p class=\"ql-center-displayed-equation\" style=\"line-height: 19px;\"><span class=\"ql-right-eqno\"> &nbsp; <\/span><span class=\"ql-left-eqno\"> &nbsp; <\/span><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/ql-cache\/quicklatex.com-40230c45220cd74948b1272b34862579_l3.png\" height=\"19\" width=\"155\" class=\"ql-img-displayed-equation quicklatex-auto-format\" alt=\"&#92;&#091; &#92;&#97;&#108;&#112;&#104;&#97;&#61;&#92;&#97;&#114;&#99;&#115;&#105;&#110;&#40;&#92;&#116;&#101;&#120;&#116;&#123;&#103;&#45;&#87;&#101;&#114;&#116;&#125;&#41; &#92;&#093;\" title=\"Rendered by QuickLaTeX.com\"\/><\/p>\n<p>\n\n<p>For small angles this works perfectly, at larger angles the error increases. Why this is the case, I explained in my article about the <a href=\"https:\/\/wolles-elektronikkiste.de\/en\/mma7361-analog-accelerometer\" target=\"_blank\" rel=\"noopener\">MMA7361<\/a>. Up to 60\u00b0, the deviation in my experiments was less than one degree.<\/p>\n<p>For this sketch, I recommend to use <code>autoOffset()<\/code>. With this function, you start at an angle of 0\u00b0 for the x- and y-axis. For the z-axis you get a starting value around 90\u00b0. Since this is a large angle, the z-axis angle fluctuates strongly. For the tilt angles, you will only get reasonable values if you position the ICM-20948 flat for calibration.<\/p>\n<\/p>\n<div class=\"scroll-paragraph\">\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-group=\"ICM20948_06_angles_and_orientation.ino\" data-enlighter-title=\"ICM20948_06_angles_and_orientation.ino\">#include &lt;Wire.h&gt;\n#include &lt;ICM20948_WE.h&gt;\n#define ICM20948_ADDR 0x68\n\n\/* There are several ways to create your ICM20948 object:\n * ICM20948_WE myIMU = ICM20948_WE()              -&gt; uses Wire \/ I2C Address = 0x68\n * ICM20948_WE myIMU = ICM20948_WE(ICM20948_ADDR) -&gt; uses Wire \/ ICM20948_ADDR\n * ICM20948_WE myIMU = ICM20948_WE(&amp;wire2)        -&gt; uses the TwoWire object wire2 \/ ICM20948_ADDR\n * ICM20948_WE myIMU = ICM20948_WE(&amp;wire2, ICM20948_ADDR) -&gt; all together\n * ICM20948_WE myIMU = ICM20948_WE(CS_PIN, spi);  -&gt; uses SPI, spi is just a flag, see SPI example\n * ICM20948_WE myIMU = ICM20948_WE(&amp;SPI, CS_PIN, spi);  -&gt; uses SPI \/ passes the SPI object, spi is just a flag, see SPI example\n *\/\nICM20948_WE myIMU = ICM20948_WE(ICM20948_ADDR);\n\nvoid setup() {\n  \/\/delay(2000); \/\/ maybe needed for some MCUs, in particular for startup after power off\n  Wire.begin();\n  Serial.begin(115200);\n  while(!Serial) {}\n  \n  if(!myIMU.init()){\n    Serial.println(\"ICM20948 does not respond\");\n  }\n  else{\n    Serial.println(\"ICM20948 is connected\");\n  }\n\n  \/*  This is a method to calibrate. You have to determine the minimum and maximum \n   *  raw acceleration values of the axes determined in the range +\/- 2 g. \n   *  You call the function as follows: setAccOffsets(xMin,xMax,yMin,yMax,zMin,zMax);\n   *  The parameters are floats. \n   *  The calibration changes the slope \/ ratio of raw acceleration vs g. The zero point is \n   *  set as (min + max)\/2.\n   *\/\n  \/\/myIMU.setAccOffsets(-16330.0, 16450.0, -16600.0, 16180.0, -16520.0, 16690.0);\n    \n  \/* The starting point, if you position the ICM20948 flat, is not necessarily 0g\/0g\/1g for x\/y\/z. \n   * The autoOffset function measures offset. It assumes your ICM20948 is positioned flat with its \n   * x,y-plane. The more you deviate from this, the less accurate will be your results.\n   * It overwrites the zero points of setAccOffsets, but keeps the correction of the slope.\n   * The function also measures the offset of the gyroscope data. The gyroscope offset does not   \n   * depend on the positioning.\n   * This function needs to be called after setAccOffsets but before other settings since \n   * it will overwrite settings!\n   * You can query the offsets with the function:\n   * xyzFloat getAccOffsets()\n   * You can apply the offset using:\n   * setAccOffsets(xyzFloat yourOffsets)\n   *\/\n  Serial.println(\"Position your ICM20948 flat and don't move it - calibrating...\");\n  delay(1000);\n  myIMU.autoOffsets();\n  Serial.println(\"Done!\"); \n  \n  \/* enables or disables the acceleration sensor, default: enabled *\/\n  \/\/ myIMU.enableAcc(true);\n\n  \/*  ICM20948_ACC_RANGE_2G      2 g   (default)\n   *  ICM20948_ACC_RANGE_4G      4 g\n   *  ICM20948_ACC_RANGE_8G      8 g   \n   *  ICM20948_ACC_RANGE_16G    16 g\n   *\/\n  myIMU.setAccRange(ICM20948_ACC_RANGE_2G);\n  \n  \/*  Choose a level for the Digital Low Pass Filter or switch it off.  \n   *  ICM20948_DLPF_0, ICM20948_DLPF_2, ...... ICM20948_DLPF_7, ICM20948_DLPF_OFF \n   *  \n   *  IMPORTANT: This needs to be ICM20948_DLPF_7 if DLPF is used in cycle mode!\n   *  \n   *  DLPF       3dB Bandwidth [Hz]      Output Rate [Hz]\n   *    0              246.0               1125\/(1+ASRD) \n   *    1              246.0               1125\/(1+ASRD)\n   *    2              111.4               1125\/(1+ASRD)\n   *    3               50.4               1125\/(1+ASRD)\n   *    4               23.9               1125\/(1+ASRD)\n   *    5               11.5               1125\/(1+ASRD)\n   *    6                5.7               1125\/(1+ASRD) \n   *    7              473.0               1125\/(1+ASRD)\n   *    OFF           1209.0               4500\n   *    \n   *    ASRD = Accelerometer Sample Rate Divider (0...4095)\n   *    You achieve lowest noise using level 6  \n   *\/\n  myIMU.setAccDLPF(ICM20948_DLPF_6);    \n  \n  \/*  Acceleration sample rate divider divides the output rate of the accelerometer.\n   *  Sample rate = Basic sample rate \/ (1 + divider) \n   *  It can only be applied if the corresponding DLPF is not off!\n   *  Divider is a number 0...4095 (different range compared to gyroscope)\n   *  If sample rates are set for the accelerometer and the gyroscope, the gyroscope\n   *  sample rate has priority.\n   *\/\n  myIMU.setAccSampleRateDivider(10);\n}\n\nvoid loop() {\n  xyzFloat gValue;\n  xyzFloat angle;\n  myIMU.readSensor();\n  myIMU.getGValues(&amp;gValue);\n  myIMU.getAngles(&amp;angle);\n  \n\/* For g-values the corrected raws are used *\/\n  Serial.print(\"g-x      = \");\n  Serial.print(gValue.x);\n  Serial.print(\"  |  g-y      = \");\n  Serial.print(gValue.y);\n  Serial.print(\"  |  g-z      = \");\n  Serial.println(gValue.z);\n\n\/* Angles are also based on the corrected raws. Angles are simply calculated by\n   angle = arcsin(g Value) *\/\n  Serial.print(\"Angle x  = \");\n  Serial.print(angle.x);\n  Serial.print(\"  |  Angle y  = \");\n  Serial.print(angle.y);\n  Serial.print(\"  |  Angle z  = \");\n  Serial.println(angle.z);\n\n  Serial.print(\"Orientation of the module: \");\n  Serial.println(myIMU.getOrientationAsString());\n\n  delay(1000);\n}<\/pre>\n<p>\u00a0<\/p>\n<\/div>\n<p>\n\n<p>The following functions are added here:<\/p>\n<ul>\n<li><code>getAngles()<\/code> returns the angle of the x, y, and z axes to the horizontal in degrees.\n<ul>\n<li>g-values above 1 are truncated to 1 because the arc sine function is not defined for larger values.<\/li>\n<\/ul>\n<\/li>\n<li><code>getOrientationAsString()<\/code> indicates which axis has the largest positive angle.\n<ul>\n<li>Possible return values are: x up, x down, y up, y down, z up, z down.<\/li>\n<li>An alternative is <code>getOrientation()<\/code>. The return value is an enum (ICM20948_orientation). For the definition look in ICM20948_WE.h.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n<h4 class=\"wp-block-heading\" id=\"ausgabe-von-icm20948-06-angles-and-orientation-ino\">Output of ICM20948_06_angles_and_orientation.ino<\/h4>\n\n<p>For the following output I have rotated the module around the y-axis, i.e. I have erected the x-axis.<\/p>\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/output_angles_and_orientation-1024x457.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"457\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/output_angles_and_orientation-1024x457.png\" alt=\"Output of ICM20948_06_angles_and_orientation.ino\" class=\"wp-image-12107\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/output_angles_and_orientation-1024x457.png 1024w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/output_angles_and_orientation-300x134.png 300w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/output_angles_and_orientation-768x343.png 768w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/output_angles_and_orientation.png 1094w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption class=\"wp-element-caption\">Output of ICM20948_06_angles_and_orientation.ino<\/figcaption><\/figure>\n\n<h3 class=\"wp-block-heading\" id=\"icm20948-07-pitch-and-roll-ino\">ICM20948_07_pitch_and_roll.ino<\/h3>\n\n<p>This method uses multiple axes to calculate the angles. As a result, the values are more accurate at large angles than with the simple arc sine method. On the other hand, at small angles, the latter method is preferable. To delineate the method, I used the nomenclature of other libraries and referred to the x-axis tilt angle as &#8220;pitch&#8221; and the y-axis tilt angle as &#8220;roll angle&#8221;. You can find a definition <a href=\"https:\/\/en.wikipedia.org\/wiki\/Aircraft_principal_axes\" target=\"_blank\" rel=\"noopener\">here<\/a>, for example.<\/p>\n<\/p>\n<p class=\"ql-center-displayed-equation\" style=\"line-height: 71px;\"><span class=\"ql-right-eqno\"> &nbsp; <\/span><span class=\"ql-left-eqno\"> &nbsp; <\/span><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/ql-cache\/quicklatex.com-fe5dff7e366ac98e2576b38fdf36d048_l3.png\" height=\"71\" width=\"283\" class=\"ql-img-displayed-equation quicklatex-auto-format\" alt=\"&#92;&#091; &#112;&#105;&#116;&#99;&#104;&#92;&#59;&#32;&#97;&#110;&#103;&#108;&#101;&#61;&#32;&#92;&#97;&#114;&#99;&#116;&#97;&#110;&#32;&#92;&#108;&#101;&#102;&#116;&#40;&#92;&#102;&#114;&#97;&#99;&#123;&#45;&#103;&#95;&#120;&#125;&#123;&#92;&#115;&#113;&#114;&#116;&#123;&#103;&#95;&#121;&#94;&#50;&#32;&#43;&#103;&#95;&#122;&#94;&#50;&#125;&#125;&#92;&#114;&#105;&#103;&#104;&#116;&#41; &#92;&#093;\" title=\"Rendered by QuickLaTeX.com\"\/><\/p>\n<p>\n<\/p>\n<p class=\"ql-center-displayed-equation\" style=\"line-height: 45px;\"><span class=\"ql-right-eqno\"> &nbsp; <\/span><span class=\"ql-left-eqno\"> &nbsp; <\/span><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/ql-cache\/quicklatex.com-9820af5f8281ad481115acad0b2fafcb_l3.png\" height=\"45\" width=\"207\" class=\"ql-img-displayed-equation quicklatex-auto-format\" alt=\"&#92;&#091; &#114;&#111;&#108;&#108;&#92;&#59;&#97;&#110;&#103;&#108;&#101;&#32;&#61;&#32;&#92;&#97;&#114;&#99;&#116;&#97;&#110;&#92;&#108;&#101;&#102;&#116;&#40;&#32;&#92;&#102;&#114;&#97;&#99;&#123;&#103;&#95;&#121;&#125;&#123;&#103;&#95;&#122;&#125;&#32;&#92;&#114;&#105;&#103;&#104;&#116;&#41; &#92;&#093;\" title=\"Rendered by QuickLaTeX.com\"\/><\/p>\n<p>\n\n<p>For comparison, I use both methods in this sketch. Try it out and choose what suits you more.<\/p>\n<\/p>\n<div class=\"scroll-paragraph\">\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-group=\"ICM20948_07_pitch_and_roll.ino\" data-enlighter-title=\"ICM20948_07_pitch_and_roll.ino\">#include &lt;Wire.h&gt;\n#include &lt;ICM20948_WE.h&gt;\n#define ICM20948_ADDR 0x68\n\n\/* There are several ways to create your ICM20948 object:\n * ICM20948_WE myIMU = ICM20948_WE()              -&gt; uses Wire \/ I2C Address = 0x68\n * ICM20948_WE myIMU = ICM20948_WE(ICM20948_ADDR) -&gt; uses Wire \/ ICM20948_ADDR\n * ICM20948_WE myIMU = ICM20948_WE(&amp;wire2)        -&gt; uses the TwoWire object wire2 \/ ICM20948_ADDR\n * ICM20948_WE myIMU = ICM20948_WE(&amp;wire2, ICM20948_ADDR) -&gt; all together\n * ICM20948_WE myIMU = ICM20948_WE(CS_PIN, spi);  -&gt; uses SPI, spi is just a flag, see SPI example\n * ICM20948_WE myIMU = ICM20948_WE(&amp;SPI, CS_PIN, spi);  -&gt; uses SPI \/ passes the SPI object, spi is just a flag, see SPI example\n *\/\nICM20948_WE myIMU = ICM20948_WE(ICM20948_ADDR);\n\nvoid setup() {\n  \/\/delay(2000); \/\/ maybe needed for some MCUs, in particular for startup after power off\n  Wire.begin();\n  Serial.begin(115200);\n  while(!Serial) {}\n  \n  if(!myIMU.init()){\n    Serial.println(\"ICM20948 does not respond\");\n  }\n  else{\n    Serial.println(\"ICM20948 is connected\");\n  }\n\n  \/*  This is a method to calibrate. You have to determine the minimum and maximum \n   *  raw acceleration values of the axes determined in the range +\/- 2 g. \n   *  You call the function as follows: setAccOffsets(xMin,xMax,yMin,yMax,zMin,zMax);\n   *  The parameters are floats. \n   *  The calibration changes the slope \/ ratio of raw acceleration vs g. The zero point \n   *  is set as (min + max)\/2.\n   *\/\n  \/\/myIMU.setAccOffsets(-16330.0, 16450.0, -16600.0, 16180.0, -16520.0, 16690.0);\n    \n  \/* The starting point, if you position the ICM20948 flat, is not necessarily 0g\/0g\/1g for x\/y\/z. \n   * The autoOffset function measures offset. It assumes your ICM20948 is positioned flat with its \n   * x,y-plane. The more you deviate from this, the less accurate will be your results.\n   * It overwrites the zero points of setAccOffsets, but keeps the correction of the slope.\n   * The function also measures the offset of the gyroscope data. The gyroscope offset does not   \n   * depend on the positioning.\n   * This function needs to be called after setAccsOffsets but before other settings since it will \n   * overwrite settings!\n   * You can query the offsets with the functions:\n   * xyzFloat getAccOffsets() and xyzFloat getGyrOffsets()\n   * You can apply the offsets using:\n   * setAccOffsets(xyzFloat yourOffsets) and setGyrOffsets(xyzFloat yourOffsets)\n   *\/\n  Serial.println(\"Position your ICM20948 flat and don't move it - calibrating...\");\n  delay(1000);\n  myIMU.autoOffsets();\n  Serial.println(\"Done!\"); \n  \n  \/* enables or disables the acceleration sensor, default: enabled *\/\n  \/\/ myIMU.enableAcc(true);\n\n  \/*  ICM20948_ACC_RANGE_2G      2 g   (default)\n   *  ICM20948_ACC_RANGE_4G      4 g\n   *  ICM20948_ACC_RANGE_8G      8 g   \n   *  ICM20948_ACC_RANGE_16G    16 g\n   *\/\n  myIMU.setAccRange(ICM20948_ACC_RANGE_2G);\n  \n  \/*  Choose a level for the Digital Low Pass Filter or switch it off.  \n   *  ICM20948_DLPF_0, ICM20948_DLPF_2, ...... ICM20948_DLPF_7, ICM20948_DLPF_OFF \n   *  \n   *  IMPORTANT: This needs to be ICM20948_DLPF_7 if DLPF is used in cycle mode!\n   *  \n   *  DLPF       3dB Bandwidth [Hz]      Output Rate [Hz]\n   *    0              246.0               1125\/(1+ASRD) \n   *    1              246.0               1125\/(1+ASRD)\n   *    2              111.4               1125\/(1+ASRD)\n   *    3               50.4               1125\/(1+ASRD)\n   *    4               23.9               1125\/(1+ASRD)\n   *    5               11.5               1125\/(1+ASRD)\n   *    6                5.7               1125\/(1+ASRD) \n   *    7              473.0               1125\/(1+ASRD)\n   *    OFF           1209.0               4500\n   *    \n   *    ASRD = Accelerometer Sample Rate Divider (0...4095)\n   *    You achieve lowest noise using level 6  \n   *\/\n  myIMU.setAccDLPF(ICM20948_DLPF_6);    \n  \n  \/*  Acceleration sample rate divider divides the output rate of the accelerometer.\n   *  Sample rate = Basic sample rate \/ (1 + divider) \n   *  It can only be applied if the corresponding DLPF is not off!\n   *  Divider is a number 0...4095 (different range compared to gyroscope)\n   *  If sample rates are set for the accelerometer and the gyroscope, the gyroscope\n   *  sample rate has priority.\n   *\/\n  \/\/myIMU.setAccSampleRateDivider(10);\n}\n\nvoid loop() {\n  xyzFloat gValue;\n  xyzFloat angle;\n  myIMU.readSensor();\n  myIMU.getGValues(&amp;gValue);\n  myIMU.getAngles(&amp;angle);\n \n  float pitch = myIMU.getPitch();\n  float roll  = myIMU.getRoll();\n \n  Serial.println(\"G values (x,y,z):\");\n  Serial.print(gValue.x);\n  Serial.print(\"   \");\n  Serial.print(gValue.y);\n  Serial.print(\"   \");\n  Serial.println(gValue.z);\n  Serial.println(\"Angles (x,y,z):\");\n  Serial.print(angle.x);\n  Serial.print(\"   \");\n  Serial.print(angle.y);\n  Serial.print(\"   \");\n  Serial.println(angle.z);\n\n  Serial.print(\"Pitch = \"); \n  Serial.print(pitch); \n  Serial.print(\"  |  Roll = \"); \n  Serial.println(roll); \n  \n  Serial.println();\n  Serial.println();\n\n  delay(1000);\n}<\/pre>\n<p>\u00a0<\/p>\n<\/div>\n<p>\n\n<p>Two new functions are used here:<\/p>\n<ul>\n<li><code>getPitch()<\/code> returns the pitch angle (x-axis).<\/li>\n<li><code>getRoll()<\/code> returns the roll angle (y-axis).<\/li>\n<\/ul>\n\n<h4 class=\"wp-block-heading\" id=\"ausgabe-von-icm20948-07-pitch-and-roll-ino\">Output of ICM20948_07_pitch_and_roll.ino<\/h4>\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/output_pitch_and_roll.png\"><img loading=\"lazy\" decoding=\"async\" width=\"887\" height=\"349\" src=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/output_pitch_and_roll.png\" alt=\"ICM-20948 - Output of ICM20948_07_pitch_and_roll.ino\" class=\"wp-image-12110\" srcset=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/output_pitch_and_roll.png 887w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/output_pitch_and_roll-300x118.png 300w, https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/output_pitch_and_roll-768x302.png 768w\" sizes=\"auto, (max-width: 887px) 100vw, 887px\" \/><\/a><figcaption class=\"wp-element-caption\">Output of ICM20948_07_pitch_and_roll.ino<\/figcaption><\/figure>\n\n<h2 class=\"wp-block-heading\" id=\"ausblick\">Outlook<\/h2>\n\n<p>The <a href=\"https:\/\/wolles-elektronikkiste.de\/en\/icm-20948-9-axis-sensor-part-ii\" target=\"_blank\" rel=\"noopener\">second part of the article<\/a> deals with interrupts, low-power mode and the FIFO buffer.<\/p>\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>I present the ICM-20948 9-axis sensor and my associated library. The ICM-20948 is the successor to the MPU-9250. This is Part 1.<\/p>\n","protected":false},"author":1,"featured_media":12154,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[919,572],"tags":[1423,1522,1337,1524,1357,556,1351,666,1517,1519,558,1414,1503,1521],"class_list":["post-12293","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-acceleration","category-sensors","tag-9-axis-sensor","tag-accelerometer-en-4","tag-accelerometer-en-2","tag-ak09916-en","tag-angle","tag-arduino-en-2","tag-fifo-en","tag-i2c-en","tag-icm-20948-en","tag-imu-en","tag-library-en-2","tag-magnetometer-en","tag-spi-en","tag-successor-of-the-mpu-9250"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.4 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>ICM-20948 9-Axis Sensor Part I &#8226; Wolles Elektronikkiste<\/title>\n<meta name=\"description\" content=\"I present the ICM-20948 9-axis sensor and my associated library. The ICM-20948 is the successor to the MPU-9250. This is Part 1.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/wolles-elektronikkiste.de\/en\/icm-20948-9-axis-sensor-part-i\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"ICM-20948 9-Axis Sensor Part I &#8226; Wolles Elektronikkiste\" \/>\n<meta property=\"og:description\" content=\"I present the ICM-20948 9-axis sensor and my associated library. The ICM-20948 is the successor to the MPU-9250. This is Part 1.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/wolles-elektronikkiste.de\/en\/icm-20948-9-axis-sensor-part-i\" \/>\n<meta property=\"og:site_name\" content=\"Wolles Elektronikkiste\" \/>\n<meta property=\"article:published_time\" content=\"2021-08-14T09:30:16+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-02-01T20:04:42+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/ICM20948_Beitragsbild.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1100\" \/>\n\t<meta property=\"og:image:height\" content=\"1100\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Wolfgang Ewald\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Wolfgang Ewald\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"31 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/icm-20948-9-axis-sensor-part-i#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/icm-20948-9-axis-sensor-part-i\"},\"author\":{\"name\":\"Wolfgang Ewald\",\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en#\\\/schema\\\/person\\\/b774e4d64b4766889a2f7c6e5ec85b46\"},\"headline\":\"ICM-20948 9-Axis Sensor Part I\",\"datePublished\":\"2021-08-14T09:30:16+00:00\",\"dateModified\":\"2026-02-01T20:04:42+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/icm-20948-9-axis-sensor-part-i\"},\"wordCount\":2862,\"commentCount\":125,\"publisher\":{\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en#\\\/schema\\\/person\\\/b774e4d64b4766889a2f7c6e5ec85b46\"},\"image\":{\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/icm-20948-9-axis-sensor-part-i#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/wp-content\\\/uploads\\\/2021\\\/07\\\/ICM20948_Beitragsbild.png\",\"keywords\":[\"9-axis sensor\",\"Accelerometer\",\"accelerometer\",\"AK09916\",\"angle\",\"Arduino\",\"FIFO\",\"I2C\",\"ICM-20948\",\"IMU\",\"Library\",\"Magnetometer\",\"SPI\",\"Successor of the MPU-9250\"],\"articleSection\":[\"Acceleration\",\"Sensors\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/icm-20948-9-axis-sensor-part-i#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/icm-20948-9-axis-sensor-part-i\",\"url\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/icm-20948-9-axis-sensor-part-i\",\"name\":\"ICM-20948 9-Axis Sensor Part I &#8226; Wolles Elektronikkiste\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/icm-20948-9-axis-sensor-part-i#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/icm-20948-9-axis-sensor-part-i#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/wp-content\\\/uploads\\\/2021\\\/07\\\/ICM20948_Beitragsbild.png\",\"datePublished\":\"2021-08-14T09:30:16+00:00\",\"dateModified\":\"2026-02-01T20:04:42+00:00\",\"description\":\"I present the ICM-20948 9-axis sensor and my associated library. The ICM-20948 is the successor to the MPU-9250. This is Part 1.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/icm-20948-9-axis-sensor-part-i#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/icm-20948-9-axis-sensor-part-i\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/icm-20948-9-axis-sensor-part-i#primaryimage\",\"url\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/wp-content\\\/uploads\\\/2021\\\/07\\\/ICM20948_Beitragsbild.png\",\"contentUrl\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/wp-content\\\/uploads\\\/2021\\\/07\\\/ICM20948_Beitragsbild.png\",\"width\":1100,\"height\":1100},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\\\/icm-20948-9-axis-sensor-part-i#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Startseite\",\"item\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"ICM-20948 9-Axis Sensor Part I\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en#website\",\"url\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en\",\"name\":\"Wolles Elektronikkiste\",\"description\":\"Die wunderbare Welt der Elektronik\",\"publisher\":{\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en#\\\/schema\\\/person\\\/b774e4d64b4766889a2f7c6e5ec85b46\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/en#\\\/schema\\\/person\\\/b774e4d64b4766889a2f7c6e5ec85b46\",\"name\":\"Wolfgang Ewald\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/wp-content\\\/uploads\\\/2019\\\/03\\\/cropped-Logo-1.png\",\"url\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/wp-content\\\/uploads\\\/2019\\\/03\\\/cropped-Logo-1.png\",\"contentUrl\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/wp-content\\\/uploads\\\/2019\\\/03\\\/cropped-Logo-1.png\",\"width\":512,\"height\":512,\"caption\":\"Wolfgang Ewald\"},\"logo\":{\"@id\":\"https:\\\/\\\/wolles-elektronikkiste.de\\\/wp-content\\\/uploads\\\/2019\\\/03\\\/cropped-Logo-1.png\"}}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"ICM-20948 9-Axis Sensor Part I &#8226; Wolles Elektronikkiste","description":"I present the ICM-20948 9-axis sensor and my associated library. The ICM-20948 is the successor to the MPU-9250. This is Part 1.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/wolles-elektronikkiste.de\/en\/icm-20948-9-axis-sensor-part-i","og_locale":"en_US","og_type":"article","og_title":"ICM-20948 9-Axis Sensor Part I &#8226; Wolles Elektronikkiste","og_description":"I present the ICM-20948 9-axis sensor and my associated library. The ICM-20948 is the successor to the MPU-9250. This is Part 1.","og_url":"https:\/\/wolles-elektronikkiste.de\/en\/icm-20948-9-axis-sensor-part-i","og_site_name":"Wolles Elektronikkiste","article_published_time":"2021-08-14T09:30:16+00:00","article_modified_time":"2026-02-01T20:04:42+00:00","og_image":[{"width":1100,"height":1100,"url":"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/ICM20948_Beitragsbild.png","type":"image\/png"}],"author":"Wolfgang Ewald","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Wolfgang Ewald","Est. reading time":"31 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/wolles-elektronikkiste.de\/en\/icm-20948-9-axis-sensor-part-i#article","isPartOf":{"@id":"https:\/\/wolles-elektronikkiste.de\/en\/icm-20948-9-axis-sensor-part-i"},"author":{"name":"Wolfgang Ewald","@id":"https:\/\/wolles-elektronikkiste.de\/en#\/schema\/person\/b774e4d64b4766889a2f7c6e5ec85b46"},"headline":"ICM-20948 9-Axis Sensor Part I","datePublished":"2021-08-14T09:30:16+00:00","dateModified":"2026-02-01T20:04:42+00:00","mainEntityOfPage":{"@id":"https:\/\/wolles-elektronikkiste.de\/en\/icm-20948-9-axis-sensor-part-i"},"wordCount":2862,"commentCount":125,"publisher":{"@id":"https:\/\/wolles-elektronikkiste.de\/en#\/schema\/person\/b774e4d64b4766889a2f7c6e5ec85b46"},"image":{"@id":"https:\/\/wolles-elektronikkiste.de\/en\/icm-20948-9-axis-sensor-part-i#primaryimage"},"thumbnailUrl":"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/ICM20948_Beitragsbild.png","keywords":["9-axis sensor","Accelerometer","accelerometer","AK09916","angle","Arduino","FIFO","I2C","ICM-20948","IMU","Library","Magnetometer","SPI","Successor of the MPU-9250"],"articleSection":["Acceleration","Sensors"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/wolles-elektronikkiste.de\/en\/icm-20948-9-axis-sensor-part-i#respond"]}]},{"@type":"WebPage","@id":"https:\/\/wolles-elektronikkiste.de\/en\/icm-20948-9-axis-sensor-part-i","url":"https:\/\/wolles-elektronikkiste.de\/en\/icm-20948-9-axis-sensor-part-i","name":"ICM-20948 9-Axis Sensor Part I &#8226; Wolles Elektronikkiste","isPartOf":{"@id":"https:\/\/wolles-elektronikkiste.de\/en#website"},"primaryImageOfPage":{"@id":"https:\/\/wolles-elektronikkiste.de\/en\/icm-20948-9-axis-sensor-part-i#primaryimage"},"image":{"@id":"https:\/\/wolles-elektronikkiste.de\/en\/icm-20948-9-axis-sensor-part-i#primaryimage"},"thumbnailUrl":"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/ICM20948_Beitragsbild.png","datePublished":"2021-08-14T09:30:16+00:00","dateModified":"2026-02-01T20:04:42+00:00","description":"I present the ICM-20948 9-axis sensor and my associated library. The ICM-20948 is the successor to the MPU-9250. This is Part 1.","breadcrumb":{"@id":"https:\/\/wolles-elektronikkiste.de\/en\/icm-20948-9-axis-sensor-part-i#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/wolles-elektronikkiste.de\/en\/icm-20948-9-axis-sensor-part-i"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/wolles-elektronikkiste.de\/en\/icm-20948-9-axis-sensor-part-i#primaryimage","url":"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/ICM20948_Beitragsbild.png","contentUrl":"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2021\/07\/ICM20948_Beitragsbild.png","width":1100,"height":1100},{"@type":"BreadcrumbList","@id":"https:\/\/wolles-elektronikkiste.de\/en\/icm-20948-9-axis-sensor-part-i#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Startseite","item":"https:\/\/wolles-elektronikkiste.de\/en"},{"@type":"ListItem","position":2,"name":"ICM-20948 9-Axis Sensor Part I"}]},{"@type":"WebSite","@id":"https:\/\/wolles-elektronikkiste.de\/en#website","url":"https:\/\/wolles-elektronikkiste.de\/en","name":"Wolles Elektronikkiste","description":"Die wunderbare Welt der Elektronik","publisher":{"@id":"https:\/\/wolles-elektronikkiste.de\/en#\/schema\/person\/b774e4d64b4766889a2f7c6e5ec85b46"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/wolles-elektronikkiste.de\/en?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":["Person","Organization"],"@id":"https:\/\/wolles-elektronikkiste.de\/en#\/schema\/person\/b774e4d64b4766889a2f7c6e5ec85b46","name":"Wolfgang Ewald","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2019\/03\/cropped-Logo-1.png","url":"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2019\/03\/cropped-Logo-1.png","contentUrl":"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2019\/03\/cropped-Logo-1.png","width":512,"height":512,"caption":"Wolfgang Ewald"},"logo":{"@id":"https:\/\/wolles-elektronikkiste.de\/wp-content\/uploads\/2019\/03\/cropped-Logo-1.png"}}]}},"_links":{"self":[{"href":"https:\/\/wolles-elektronikkiste.de\/en\/wp-json\/wp\/v2\/posts\/12293","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wolles-elektronikkiste.de\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/wolles-elektronikkiste.de\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/wolles-elektronikkiste.de\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/wolles-elektronikkiste.de\/en\/wp-json\/wp\/v2\/comments?post=12293"}],"version-history":[{"count":10,"href":"https:\/\/wolles-elektronikkiste.de\/en\/wp-json\/wp\/v2\/posts\/12293\/revisions"}],"predecessor-version":[{"id":25563,"href":"https:\/\/wolles-elektronikkiste.de\/en\/wp-json\/wp\/v2\/posts\/12293\/revisions\/25563"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/wolles-elektronikkiste.de\/en\/wp-json\/wp\/v2\/media\/12154"}],"wp:attachment":[{"href":"https:\/\/wolles-elektronikkiste.de\/en\/wp-json\/wp\/v2\/media?parent=12293"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/wolles-elektronikkiste.de\/en\/wp-json\/wp\/v2\/categories?post=12293"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/wolles-elektronikkiste.de\/en\/wp-json\/wp\/v2\/tags?post=12293"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}