{"id":661,"date":"2026-04-29T19:11:02","date_gmt":"2026-04-30T03:11:02","guid":{"rendered":"https:\/\/salemdata.net\/johnpress\/?p=661"},"modified":"2026-05-01T08:03:25","modified_gmt":"2026-05-01T16:03:25","slug":"t-beam-magnetometer-investigation","status":"publish","type":"post","link":"https:\/\/salemdata.net\/johnpress\/?p=661","title":{"rendered":"T-Beam Magnetometer Investigation"},"content":{"rendered":"\n<p>5\/1\/2026 &#8211; <strong>Update<\/strong>: over 100k hits on my Forgejo server, presumably bots, so I now require sign-in to explore.\u00a0 Contact me if you want an account.<\/p>\n<h1>Introduction<\/h1>\n<p>This is a <em>deep technical<\/em> dive, possibly only of interest to people programming the LilyGO T-Beam SUPREME.\u00a0 Much of the working below are snippets taken from Wikipedia.\u00a0 What&#8217;s important is that if you want the T-Beam to serve as a compass and compute bearings, you need to have an accurate heading (like a compass would give you).<\/p>\n<h2>Executive Summary<\/h2>\n<p>Calibration must be performed per device if you plan to using bearings derived from the magnetometer. In testing across seven T-Beam units, inter-device variation far exceeded environmental variation, demonstrating that factory or shared calibration constants are not viable.<\/p>\n<h1>T-Beam&#8217;s Magnetometer<\/h1>\n<p>The LilyGO T-Beam SUPREME <a href=\"https:\/\/wiki.lilygo.cc\/get_started\/en\/LoRa_GPS\/T-Beam-SUPREME\/T-Beam-SUPREME.html\">Specifications<\/a> states that there is a &#8220;Magnetometer: QMC6310&#8221; sensor.\u00a0 &#8220;A <b>magnetometer<\/b> is a device that measures <a title=\"Magnetic field\" href=\"https:\/\/en.wikipedia.org\/wiki\/Magnetic_field\">magnetic field<\/a> (<span class=\"texhtml\"><b>B<\/b><\/span>) [see below &#8220;The B Field&#8221;] or <a class=\"mw-redirect\" title=\"Magnetic dipole moment\" href=\"https:\/\/en.wikipedia.org\/wiki\/Magnetic_dipole_moment\">magnetic dipole moment<\/a>. Different types of magnetometers measure the direction, strength, or relative change of the magnetic <span class=\"texhtml\"><b>B<\/b><\/span>-field at a particular location. &#8230;A <a title=\"Compass\" href=\"https:\/\/en.wikipedia.org\/wiki\/Compass\">compass<\/a> is one such device, one that measures the direction of an ambient magnetic field, in this case, the <a title=\"Earth's magnetic field\" href=\"https:\/\/en.wikipedia.org\/wiki\/Earth%27s_magnetic_field\">Earth&#8217;s magnetic field<\/a>.&#8221;\u00a0 QMC&#8217;s data sheet states that the 6310 measures gauss units (Symbol <strong>G<\/strong> for gauss) which is a unit of measurement of <a title=\"Magnetic field\" href=\"https:\/\/en.wikipedia.org\/wiki\/Magnetic_field#The_B-field\">magnetic flux density<\/a>, \u00a0 Gauss units are the older system of measurement which was superseded in 1961 by the <a title=\"International System of Units\" href=\"https:\/\/en.wikipedia.org\/wiki\/International_System_of_Units\">International System of Units<\/a> (SI), the use of the gauss has been deprecated by the standards bodies, but is still regularly used in various subfields of science, and preferred in <a title=\"Astrophysics\" href=\"https:\/\/en.wikipedia.org\/wiki\/Astrophysics\">astrophysics<\/a>.<sup id=\"cite_ref-3\" class=\"reference\"><a href=\"https:\/\/en.wikipedia.org\/wiki\/Gauss_(unit)#cite_note-3\"><span class=\"cite-bracket\">[<\/span>1<span class=\"cite-bracket\">]<\/span><\/a><\/sup>\u00a0 \u00a0Case in point: the QMC6310 uses gauss (<strong>G<\/strong>) units.\u00a0 The SI unit for magnetic flux density is the <a title=\"Tesla (unit)\" href=\"https:\/\/en.wikipedia.org\/wiki\/Tesla_(unit)\">tesla<\/a> (symbol T),<sup id=\"cite_ref-4\" class=\"reference\"><a href=\"https:\/\/en.wikipedia.org\/wiki\/Gauss_(unit)#cite_note-4\"><span class=\"cite-bracket\">[<\/span>2<span class=\"cite-bracket\">]<\/span><\/a><\/sup> which corresponds to 10,000gauss.<\/p>\n<p>Therefore, one must bear in mind that there are two kinds of units, gauss, <strong>B<\/strong>,\u00a0 and tesla, <strong>T<\/strong>, used in this arena.<\/p>\n<h2>The B Field<\/h2>\n<p>The magnetic <span class=\"texhtml\"><b>B<\/b><\/span> field is the &#8220;magnetic field&#8221; responsible for magnetic forces, magnetic torques and electromagnetic induction; it is also known as <b>magnetic flux density.\u00a0 <\/b>The <a class=\"mw-redirect\" title=\"SI\" href=\"https:\/\/en.wikipedia.org\/wiki\/SI\">SI<\/a> unit of <span class=\"texhtml\">B<\/span> is <a title=\"Tesla (unit)\" href=\"https:\/\/en.wikipedia.org\/wiki\/Tesla_(unit)\">tesla<\/a> (symbol: T).<sup id=\"cite_ref-11\" class=\"reference\"><a href=\"https:\/\/en.wikipedia.org\/wiki\/Magnetic_field#cite_note-11\"><span class=\"cite-bracket\">[<\/span>note 4<span class=\"cite-bracket\">]<\/span><\/a><\/sup> The <a title=\"Gaussian units\" href=\"https:\/\/en.wikipedia.org\/wiki\/Gaussian_units\">Gaussian-cgs unit<\/a> of <span class=\"texhtml\">B<\/span> is the <a title=\"Gauss (unit)\" href=\"https:\/\/en.wikipedia.org\/wiki\/Gauss_(unit)\">gauss<\/a> (symbol: G).<sup id=\"cite_ref-12\" class=\"reference\"><a href=\"https:\/\/en.wikipedia.org\/wiki\/Magnetic_field#cite_note-12\"><span class=\"cite-bracket\">[<\/span>8<span class=\"cite-bracket\">]<\/span><\/a><\/sup> (The conversion is 1\u00a0T \u2258 10000\u00a0G.<sup id=\"cite_ref-BIPMTab9_13-0\" class=\"reference\"><a href=\"https:\/\/en.wikipedia.org\/wiki\/Magnetic_field#cite_note-BIPMTab9-13\"><span class=\"cite-bracket\">[<\/span>9<span class=\"cite-bracket\">]<\/span><\/a><\/sup><sup id=\"cite_ref-KLang_14-0\" class=\"reference\"><a href=\"https:\/\/en.wikipedia.org\/wiki\/Magnetic_field#cite_note-KLang-14\"><span class=\"cite-bracket\">[<\/span>10<span class=\"cite-bracket\">]<\/span><\/a><\/sup>)<\/p>\n<h1>The QMC6310<\/h1>\n<p>The QMC6310 has a required &#8220;mode&#8221; setting that sets the limits of its ability to determine gauss counts.\u00a0 There are several, but only two modes are pertinent to the T-Beam.\u00a0 The first mode is 8G which encompasses measuring +8 to -8 G [gauss]\u00a0 QMC&#8217;s data sheet specifies that for 8G mode, it has a sensitivity of 3,750.\u00a0 For 2G, the sensitivity is 15,000.<\/p>\n<figure id=\"attachment_662\" aria-describedby=\"caption-attachment-662\" style=\"width: 935px\" class=\"wp-caption alignnone\"><img loading=\"lazy\" decoding=\"async\" class=\"size-full wp-image-662\" src=\"https:\/\/salemdata.net\/johnpress\/wp-content\/uploads\/2026\/04\/20260429_135325_Wed.png\" alt=\"A manufacturers table.\" width=\"935\" height=\"536\" srcset=\"https:\/\/salemdata.net\/johnpress\/wp-content\/uploads\/2026\/04\/20260429_135325_Wed.png 935w, https:\/\/salemdata.net\/johnpress\/wp-content\/uploads\/2026\/04\/20260429_135325_Wed-300x172.png 300w, https:\/\/salemdata.net\/johnpress\/wp-content\/uploads\/2026\/04\/20260429_135325_Wed-768x440.png 768w\" sizes=\"auto, (max-width: 935px) 100vw, 935px\" \/><figcaption id=\"caption-attachment-662\" class=\"wp-caption-text\">QMC630 Data Sheet, Table 2. Specifications<\/figcaption><\/figure>\n<p>Note: &#8220;Typ&#8221; = &#8220;Typical&#8221;<\/p>\n<p>So, to determine the gauss, for a specified mode, e.g. 8G, you take the &#8220;raw&#8221; count a particular axis, i.e. &#8220;X&#8221;, reports and divide 3,750.\u00a0 So:<\/p>\n<p>\\[<br \/>\nB_{\\text{Gauss}} = \\frac{N_{\\text{counts}}}{S_{\\text{LSB\/G}}}<br \/>\n\\]<\/p>\n<p data-start=\"777\" data-end=\"783\">Where:<\/p>\n<ul data-start=\"785\" data-end=\"862\">\n<li data-start=\"785\" data-end=\"811\"><strong><span class=\"katex\"><span class=\"katex-mathml\">B<\/span><\/span><\/strong>\u00a0= magnetic field<\/li>\n<li data-start=\"812\" data-end=\"838\"><strong><span class=\"katex\"><span class=\"katex-mathml\">N<\/span><\/span>\u00a0<\/strong>= raw ADC counts<\/li>\n<li data-start=\"839\" data-end=\"862\"><strong><span class=\"katex\"><span class=\"katex-mathml\">S<\/span><\/span><\/strong>\u00a0= sensitivity<\/li>\n<\/ul>\n<p>Example in 2G mode, where X produces a value of 580:<\/p>\n<p><span class=\"base\"><span class=\"mord\"><span class=\"mfrac\"><span class=\"vlist-t vlist-t2\"><span class=\"vlist-r\"><span class=\"vlist-s\">\\[<br \/>\n.03866666_{\\text{Gauss}} = \\frac{580_{\\text{counts}}}{15,000_{\\text{Sensitivity}}}<br \/>\n\\]<\/span><\/span><\/span><\/span><\/span><\/span><\/p>\n<p>This conversion yields uncalibrated field strength; offset and soft-iron corrections must be applied for accurate results.<\/p>\n<h1>Raw Readings From 7 T-Beams<\/h1>\n<p>I was concerned about possible distortions of the magnetic field in my office where I have lots of metal and electronic equipment, so I performed a test measuring in my office on my workstation, jp, and then on my laptop, eos, on the kitchen table.\u00a0 The results show very little difference on readings between locations.\u00a0 There are significant differences between the units themselves, however.<\/p>\n<table>\n<thead>\n<tr>\n<th>Unit<\/th>\n<th>Office (jp)<\/th>\n<th>Kitchen (eos)<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>AMY<\/td>\n<td><img decoding=\"async\" src=\"https:\/\/salemdata.net\/johnpress\/wp-content\/uploads\/2026\/04\/img\/20260428_142435_Tue_office_AMY.png\" width=\"500\" \/><\/td>\n<td><img decoding=\"async\" src=\"https:\/\/salemdata.net\/johnpress\/wp-content\/uploads\/2026\/04\/img\/2026-04-28_14-56_kitchen_AMY.png\" width=\"500\" \/><\/td>\n<\/tr>\n<tr>\n<td>BOB<\/td>\n<td><img decoding=\"async\" src=\"https:\/\/salemdata.net\/johnpress\/wp-content\/uploads\/2026\/04\/img\/20260428_145218_Tue_office_BOB.png\" width=\"500\" \/><\/td>\n<td><img decoding=\"async\" src=\"https:\/\/salemdata.net\/johnpress\/wp-content\/uploads\/2026\/04\/img\/2026-04-28_14-58_kitchen_BOB.png\" width=\"500\" \/><\/td>\n<\/tr>\n<tr>\n<td>CY<\/td>\n<td><img decoding=\"async\" src=\"https:\/\/salemdata.net\/johnpress\/wp-content\/uploads\/2026\/04\/img\/20260428_135827_Tue_office_CY.png\" width=\"500\" \/><\/td>\n<td><img decoding=\"async\" src=\"https:\/\/salemdata.net\/johnpress\/wp-content\/uploads\/2026\/04\/img\/2026-04-28_14-12_kitchen_CY.png\" width=\"500\" \/><\/td>\n<\/tr>\n<tr>\n<td>DAN<\/td>\n<td><img decoding=\"async\" src=\"https:\/\/salemdata.net\/johnpress\/wp-content\/uploads\/2026\/04\/img\/20260428_141000_Tue_office_DAN.png \" width=\"500\" \/><\/td>\n<td><img decoding=\"async\" src=\"https:\/\/salemdata.net\/johnpress\/wp-content\/uploads\/2026\/04\/img\/2026-04-28_14-07_kitchen_DAN.png\" width=\"500\" \/><\/td>\n<\/tr>\n<tr>\n<td>ED<\/td>\n<td><img decoding=\"async\" src=\"https:\/\/salemdata.net\/johnpress\/wp-content\/uploads\/2026\/04\/img\/20260428_144204_Tue_office_ED.png\" width=\"500\" \/><\/td>\n<td><img decoding=\"async\" src=\"https:\/\/salemdata.net\/johnpress\/wp-content\/uploads\/2026\/04\/img\/2026-04-28_15-06_kitchen_ED.png\" width=\"500\" \/><\/td>\n<\/tr>\n<tr>\n<td>FLO<\/td>\n<td><img decoding=\"async\" src=\"https:\/\/salemdata.net\/johnpress\/wp-content\/uploads\/2026\/04\/img\/20260428_144937_Tue_office_FLO.png\" width=\"500\" \/><\/td>\n<td><img decoding=\"async\" src=\"https:\/\/salemdata.net\/johnpress\/wp-content\/uploads\/2026\/04\/img\/2026-04-28_15-00_kitchen_FLO.png\" width=\"500\" \/><\/td>\n<\/tr>\n<tr>\n<td>GUY<\/td>\n<td><img decoding=\"async\" src=\"https:\/\/salemdata.net\/johnpress\/wp-content\/uploads\/2026\/04\/img\/20260428_144619_Tue_office_GUY.png\" width=\"500\" \/><\/td>\n<td><img decoding=\"async\" src=\"https:\/\/salemdata.net\/johnpress\/wp-content\/uploads\/2026\/04\/img\/2026-04-28_15-02_kitchen_GUY.png\" width=\"500\" \/><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>The Jupyter notebook and a concurrent stand-alone Python script mimicking the notebook are posted at: https:\/\/salemdata.net\/repo\/jlpoole\/Magnetometer_Calibration<br \/>\n<strong><em>Caveat<\/em><\/strong>: What I post on my Forgejo repository is not polished code and explanations.\u00a0 I feel I am working at a rapid rate and I doubt many people would take interest, so I do not spend a lot of time making the code and project neat and tidy.\u00a0 What is posted works for me and lets me move forward with my research and validation and preserves what I need so when I return to this project after completely forgetting its nuances, there&#8217;s enough for me to resume work, if needed.<\/p>\n<h2>MotionCal<\/h2>\n<p>A superior calibration tool in <a href=\"https:\/\/salemdata.net\/repo\/jlpoole\/MotionCal\">MotionCal<\/a>.<\/p>\n<p>Note on taking readings.\u00a0 You do not have to carefully rotate the unit slowly.\u00a0 The important thing to do is keep the top of the unit in the same spherical realm as you rotate so that you are measuring the same field surrounding it.\u00a0 When you have a sphere which has many samples in all of its quadrants, you should have enough.<\/p>\n<p>I created a custom firmware to be loaded into the T-Beam just for purposes of testing and calibrating the magnetometer.\u00a0 This project is E<a href=\"https:\/\/salemdata.net\/repo\/jlpoole\/microReticulumTbeam\/src\/branch\/feature\/fieldtest-beacon-sd-provision\/exercises\/25_motioncal_tbeam\">xercise 25 MotionCal TBeam<\/a>.\u00a0 As of April 29, 2026, the project is in my <strong>branch<\/strong>: fieldtest-beacon-sd-provision.\u00a0 You must load the T-Beam with the Exercise 25 firmware before you can use MotionCal.<\/p>\n<p>Here are the results of calibrating each unit.\u00a0 A perfectly calibrated magnetometer produces a centered sphere.<br data-start=\"3399\" data-end=\"3402\" \/>Off-center spheres indicate hard-iron bias.\u00a0 Elliptical distortion indicates soft-iron effects. Not all units are equally calibratable; some exhibit significant distortion even after calibration.<\/p>\n<table>\n<thead>\n<tr>\n<th>Unit<\/th>\n<th>MotionCal<\/th>\n<th>Calibrations<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>AMY<\/td>\n<td><img decoding=\"async\" src=\"https:\/\/salemdata.net\/johnpress\/wp-content\/uploads\/2026\/04\/img\/20260429_190123_Wed_AMY.png\" width=\"500\" \/><\/td>\n<td>\n<pre>MotionCal magnetic calibration settings\r\nsaved_local_time=2026-04-29 19:01:33\r\nvalid_points=650\r\nfit_error_percent=1.954331\r\nsurface_gap_error_percent=6.660000\r\nmagnitude_variance_error_percent=6.289725\r\nwobble_error_percent=2.118480\r\n\r\nmagnetic_offset_uT=38.0446205,15.5483704,-36.5659103\r\nmagnetic_field_uT=47.0147285\r\nmagnetic_mapping_matrix=\r\n  0.942833066 0.0306609273 0.0751264095\r\n  0.0306609273 1.05493665 -0.0529854298\r\n  0.0751264095 -0.0529854298 1.01525247\r\n<\/pre>\n<\/td>\n<\/tr>\n<tr>\n<td>BOB<\/td>\n<td><img decoding=\"async\" src=\"https:\/\/salemdata.net\/johnpress\/wp-content\/uploads\/2026\/04\/img\/20260429_190415_Wed_BOB.png\" width=\"500\" \/><\/td>\n<td>\n<pre>MotionCal magnetic calibration settings\r\nsaved_local_time=2026-04-29 19:04:29\r\nvalid_points=650\r\nfit_error_percent=1.688673\r\nsurface_gap_error_percent=4.040000\r\nmagnitude_variance_error_percent=4.089704\r\nwobble_error_percent=0.480344\r\n\r\nmagnetic_offset_uT=-113.187836,30.1211472,34.6742783\r\nmagnetic_field_uT=46.1403847\r\nmagnetic_mapping_matrix=\r\n  0.950518668 0.0357225537 0.071059376\r\n  0.0357225537 1.05537307 -0.0355574489\r\n  0.071059376 -0.0355574489 1.00482666\r\n<\/pre>\n<\/td>\n<\/tr>\n<tr>\n<td>CY<\/td>\n<td><img decoding=\"async\" src=\"https:\/\/salemdata.net\/johnpress\/wp-content\/uploads\/2026\/04\/img\/20260429_190748_Wed_CY.png\" width=\"500\" \/><\/td>\n<td>\n<pre>MotionCal magnetic calibration settings\r\nsaved_local_time=2026-04-29 19:07:45\r\nvalid_points=650\r\nfit_error_percent=2.589669\r\nsurface_gap_error_percent=57.410004\r\nmagnitude_variance_error_percent=7.070223\r\nwobble_error_percent=5.633270\r\n\r\nmagnetic_offset_uT=-199.562531,107.011795,94.7919998\r\nmagnetic_field_uT=46.0281258\r\nmagnetic_mapping_matrix=\r\n  0.922755837 0.0477279425 0.0638417602\r\n  0.0477279425 1.05570126 -0.03140679\r\n  0.0638417602 -0.03140679 1.03449798\r\n<\/pre>\n<\/td>\n<\/tr>\n<tr>\n<td>DAN<\/td>\n<td><img decoding=\"async\" src=\"https:\/\/salemdata.net\/johnpress\/wp-content\/uploads\/2026\/04\/img\/20260429_191009_Wed_DAN.png\" width=\"500\" \/><\/td>\n<td>\n<pre>MotionCal magnetic calibration settings\r\nsaved_local_time=2026-04-29 19:10:17\r\nvalid_points=650\r\nfit_error_percent=1.891944\r\nsurface_gap_error_percent=20.080002\r\nmagnitude_variance_error_percent=7.532951\r\nwobble_error_percent=1.719216\r\n\r\nmagnetic_offset_uT=-15.968605,8.26969051,-1.2073102\r\nmagnetic_field_uT=46.4549446\r\nmagnetic_mapping_matrix=\r\n  0.955098867 0.0472385511 0.0669671297\r\n  0.0472385511 1.06611001 -0.0453635007\r\n  0.0669671297 -0.0453635007 0.991166353\r\n<\/pre>\n<\/td>\n<\/tr>\n<tr>\n<td>ED<\/td>\n<td><img decoding=\"async\" src=\"https:\/\/salemdata.net\/johnpress\/wp-content\/uploads\/2026\/04\/img\/2026-04-29_18-55_ED.png\" width=\"500\" \/><\/td>\n<td>\n<pre>MotionCal magnetic calibration settings\r\nsaved_local_time=2026-04-29 18:55:57\r\nvalid_points=650\r\nfit_error_percent=1.538095\r\nsurface_gap_error_percent=15.660001\r\nmagnitude_variance_error_percent=1.532305\r\nwobble_error_percent=2.341300\r\n\r\nmagnetic_offset_uT=117.21711,-44.1901093,-82.8643723\r\nmagnetic_field_uT=52.0245972\r\nmagnetic_mapping_matrix=\r\n  0.952153444 0.0437445045 0.111379355\r\n  0.0437445045 1.07807684 -0.0304355621\r\n  0.111379355 -0.0304355621 0.990212023\r\n<\/pre>\n<\/td>\n<\/tr>\n<tr>\n<td>FLO<\/td>\n<td><img decoding=\"async\" src=\"https:\/\/salemdata.net\/johnpress\/wp-content\/uploads\/2026\/04\/img\/20260429_191220_Wed_FLO.png\" width=\"500\" \/><\/td>\n<td>\n<pre>MotionCal magnetic calibration settings\r\nsaved_local_time=2026-04-29 19:12:16\r\nvalid_points=650\r\nfit_error_percent=3.273206\r\nsurface_gap_error_percent=28.100002\r\nmagnitude_variance_error_percent=3.075784\r\nwobble_error_percent=4.869506\r\n\r\nmagnetic_offset_uT=103.806641,-24.567482,-84.2488556\r\nmagnetic_field_uT=45.9784737\r\nmagnetic_mapping_matrix=\r\n  0.965178549 0.0238724053 0.0916736871\r\n  0.0238724053 1.05761039 -0.0596620739\r\n  0.0916736871 -0.0596620739 0.992523193\r\n<\/pre>\n<\/td>\n<\/tr>\n<tr>\n<td>GUY<\/td>\n<td><img decoding=\"async\" src=\"https:\/\/salemdata.net\/johnpress\/wp-content\/uploads\/2026\/04\/img\/20260429_191447_Wed_GUY.png\" width=\"500\" \/><\/td>\n<td>\n<pre>MotionCal magnetic calibration settings\r\nsaved_local_time=2026-04-29 19:14:44\r\nvalid_points=650\r\nfit_error_percent=3.055690\r\nsurface_gap_error_percent=9.860001\r\nmagnitude_variance_error_percent=5.574696\r\nwobble_error_percent=1.545430\r\n\r\nmagnetic_offset_uT=-21.6121769,36.7250824,-12.2471542\r\nmagnetic_field_uT=46.2770653\r\nmagnetic_mapping_matrix=\r\n  0.949235439 0.0333992094 0.0756401643\r\n  0.0333992094 1.0552783 -0.0628371835\r\n  0.0756401643 -0.0628371835 1.00950599\r\n<\/pre>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h1>Meshtastic &amp; the QMC6310.<\/h1>\n<p>I wondered if and how Meshtastic utilizes the T-Beam&#8217;s QMC6310.\u00a0 It appears Meshtastic does not utilize this component.<\/p>\n<h2>Prompt to CODEX (ChatGPT)<\/h2>\n<div class=\"codex-block codex-prompt\">\n<div class=\"codex-label\">Prompt<\/div>\n<div class=\"codex-content\"><!-- your prompt HTML here -->I\u2019ve been studying the QMC6310 magnetometer and determined that among<br \/>\n7 different LilyGO T-Beams, the readings can vary from 600 unit to 1800+<br \/>\nunits for each axis. I\u2019d like to know how the meshtastic software<br \/>\ncalibrates the QMC6310, if at all. Perhaps current bearing is not<br \/>\nsomething meshtastic cares about? I have the meshtastic firmware staged<br \/>\nat: \/usr\/local\/src\/meshtastic\/firmware\/. Can you search and determine if<br \/>\nmeshastic calibrates the QMC1630 or even uses its readings?<\/div>\n<\/div>\n<h2>Response<\/h2>\n<div class=\"codex-block codex-response\">\n<div class=\"codex-label\">Response<\/div>\n<div class=\"codex-content\"><!-- your pandoc-generated HTML here -->I searched <code>\/usr\/local\/src\/meshtastic\/firmware\/<\/code>. Short<br \/>\nanswer: Meshtastic detects the QMC6310, but I don\u2019t see it reading or<br \/>\ncalibrating it for heading.What I found:<\/p>\n<ul>\n<li>QMC6310U is only mapped into <code>nodeTelemetrySensorsMap<\/code> as<br \/>\na detected telemetry sensor in <a href=\"\/usr\/local\/src\/meshtastic\/firmware\/src\/main.cpp:673\">main.cpp<\/a>.<br \/>\nThe nearby comment says these are sensors with \u201cno further logic than to<br \/>\nbe found and stuffed into\u201d that map.<\/li>\n<li>QMC6310N is detected in the I2C scanner, but is not even mapped to<br \/>\ntelemetry yet; there is a TODO for adding its telemetry type in <a href=\"\/usr\/local\/src\/meshtastic\/firmware\/src\/main.cpp:674\">main.cpp<\/a>.<\/li>\n<li>QMC6310U detection is a simple address match at <code>0x1C<\/code> in<br \/>\n<a href=\"\/usr\/local\/src\/meshtastic\/firmware\/src\/detect\/ScanI2CTwoWire.cpp:420\">ScanI2CTwoWire.cpp<\/a>.<br \/>\nQMC6310N detection is a screen-probe special case in <a href=\"\/usr\/local\/src\/meshtastic\/firmware\/src\/detect\/ScanI2CTwoWire.cpp:67\">ScanI2CTwoWire.cpp<\/a>.<\/li>\n<li><code>firstAccelerometer()<\/code> does not include QMC6310 or<br \/>\nQMC5883L. It only considers<br \/>\n<code>MPU6050, LIS3DH, BMA423, LSM6DS3, BMX160, STK8BAXX, ICM20948, QMA6100P, BMM150<\/code><br \/>\nin <a href=\"\/usr\/local\/src\/meshtastic\/firmware\/src\/detect\/ScanI2C.cpp:38\">ScanI2C.cpp<\/a>.<\/li>\n<li>The <code>AccelerometerThread<\/code> switch has no QMC6310 or<br \/>\nQMC5883L case, so no runtime motion\/heading object is created for it in<br \/>\n<a href=\"\/usr\/local\/src\/meshtastic\/firmware\/src\/motion\/AccelerometerThread.h:84\">AccelerometerThread.h<\/a>.<\/li>\n<\/ul>\n<p>The actual compass heading path appears to be:<\/p>\n<ul>\n<li><code>BMX160Sensor<\/code> reads magnetometer + accelerometer data,<br \/>\napplies a basic hard-iron offset from min\/max values gathered during a<br \/>\n30-second calibration, then calls<br \/>\n<code>FusionCompassCalculateHeading()<\/code> and<br \/>\n<code>screen-&gt;setHeading()<\/code> in <a href=\"\/usr\/local\/src\/meshtastic\/firmware\/src\/motion\/BMX160Sensor.cpp:26\">BMX160Sensor.cpp<\/a>.<\/li>\n<li><code>ICM20948Sensor<\/code> does the same style of min\/max hard-iron<br \/>\ncalibration and heading calculation in <a href=\"\/usr\/local\/src\/meshtastic\/firmware\/src\/motion\/ICM20948Sensor.cpp:47\">ICM20948Sensor.cpp<\/a>.<\/li>\n<li><code>BMM150Sensor<\/code> uses the DFRobot driver\u2019s<br \/>\n<code>getCompassDegree()<\/code> and sets the screen heading in <a href=\"\/usr\/local\/src\/meshtastic\/firmware\/src\/motion\/BMM150Sensor.cpp:22\">BMM150Sensor.cpp<\/a>.<\/li>\n<\/ul>\n<p>The UI exposes \u201cCompass Calibrate\u201d only when<br \/>\n<code>accelerometerThread<\/code> exists, and it just calls<br \/>\n<code>accelerometerThread-&gt;calibrate(30)<\/code> in <a href=\"\/usr\/local\/src\/meshtastic\/firmware\/src\/graphics\/draw\/MenuHandler.cpp:1253\">MenuHandler.cpp<\/a>.<br \/>\nSince QMC6310 never becomes an <code>AccelerometerThread<\/code> sensor,<br \/>\nthat calibration path won\u2019t touch it.<\/p>\n<p>So for LilyGO T-Beams with a QMC6310: Meshtastic seems to acknowledge<br \/>\nthe chip exists, but it does not currently use its raw magnetic readings<br \/>\nfor current bearing, nor does it calibrate them. Current bearing in the<br \/>\nUI falls back to supported compass IMUs when present, or estimated<br \/>\nmovement heading from GPS positions via <a href=\"\/usr\/local\/src\/meshtastic\/firmware\/src\/graphics\/Screen.cpp:271\">Screen.cpp<\/a>.<\/p>\n<\/div>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>5\/1\/2026 &#8211; Update: over 100k hits on my Forgejo server, presumably bots, so I now require sign-in to explore.\u00a0 Contact me if you want an account. Introduction This is a deep technical dive, possibly only of interest to people programming the LilyGO T-Beam SUPREME.\u00a0 Much of the working below are snippets taken from Wikipedia.\u00a0 What&#8217;s [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":684,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[80,121,1],"tags":[81,123,124,122],"class_list":["post-661","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-meshtastic","category-t-beam","category-uncategorized","tag-lilygo","tag-magnetometer","tag-qmc6310","tag-t-beam"],"_links":{"self":[{"href":"https:\/\/salemdata.net\/johnpress\/index.php?rest_route=\/wp\/v2\/posts\/661","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/salemdata.net\/johnpress\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/salemdata.net\/johnpress\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/salemdata.net\/johnpress\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/salemdata.net\/johnpress\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=661"}],"version-history":[{"count":20,"href":"https:\/\/salemdata.net\/johnpress\/index.php?rest_route=\/wp\/v2\/posts\/661\/revisions"}],"predecessor-version":[{"id":685,"href":"https:\/\/salemdata.net\/johnpress\/index.php?rest_route=\/wp\/v2\/posts\/661\/revisions\/685"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/salemdata.net\/johnpress\/index.php?rest_route=\/wp\/v2\/media\/684"}],"wp:attachment":[{"href":"https:\/\/salemdata.net\/johnpress\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=661"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/salemdata.net\/johnpress\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=661"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/salemdata.net\/johnpress\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=661"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}