dxb_
Published © GPL3+

A precise linear magnetic position sensor using LInterp

Virtualise a non-linear sensor into a single linear function using the LInterp PROGMEM array generator

IntermediateFull instructions provided617
A precise linear magnetic position sensor using LInterp

Things used in this project

Hardware components

Arduino UNO
Arduino UNO
×1
Hall-effect magnetic sensor UGN3503
×1
Neodymium magnet, 6mm diameter x 2mm
×1

Hand tools and fabrication machines

Mastech MS8217 Autorange Digital Multimeter
Digilent Mastech MS8217 Autorange Digital Multimeter

Story

Read more

Schematics

UGN3503 Hall-effect magnetic flux sensor

A magnetic flux sensor connected to an Arduino board analog input

Code

LInMagSens.ino

Arduino
Demo Arduino script for LInMagSens.h - A linear virtualising function for a non-linear magnetic position sensor
/* Linearised magnetic position sensor example */
/* using LInterp PROGMEM array generator on    */
/* (any) Arduino board          <<c) dxb 2022  */
#include "LInMagSens.h" /* device virtualiser  */

void setup() {
Serial.begin( 9600 );
}

void loop() {
Serial.println( Position(), 1 );
delay( 500 );
}

LInMagSens.h

C Header File
LInterp function header to virtualise a non-linear magnetic position sensor as a linear function call
/* LInMagSens.h                         <<c) dxb 2022 */
#include <avr/pgmspace.h> /* declare array in PROGMEM */

/* define our particular Arduino card ADC specs:      */
#define MAG_SENS_CHAN   A0    /* (analog channel) */
#define ANALOG_RNG      5000  /* (mV) NOMINAL! */
#define ADC_LEV_RNG     1024  /* (ADC levels) */

/* analog device INPUT range definitions */
#define MAG_SENS_IN_MIN    2600L /* (mV) */
#define MAG_SENS_IN_MAX    4210L /* (mV) */

/* Analog device OUTPUT range definitions */
#define MAG_SENS_OUT_MIN   0.0   /* (degrees) */
#define MAG_SENS_OUT_MAX   12.0  /* (degrees) */
#define MAG_SENS_OUT_SCL   1.0   /* (degrees) */

/* retained LInterp array definitions */
#define MAG_SENS_INTERP    4     /* (ADC levels) */

/* temporary LInterp array definitions */
#define LI_ARR  MAG_SENS_LI_ARR  /* device array name */
#define LI_CAL  ADC_LEV_RNG
#define LI_RNG  ANALOG_RNG
#define LI_SCL  ( MAG_SENS_OUT_MAX - MAG_SENS_OUT_MIN )
#define LI_OFS  MAG_SENS_OUT_MIN
#define LI_INT  MAG_SENS_INTERP

/* device ordinate map */
#define LI_P0   2620        /* (mV) */
#define LI_P1   2640
#define LI_P2   2670
#define LI_P3   2720
#define LI_P4   2740
#define LI_P5   2900
#define LI_P6   3060
#define LI_P7   3600
#define LI_P8   3790
#define LI_P9   3950
#define LI_P10  4090
#define LI_P11  4180
#define LI_P12  4210

#include "LInterp.h"        /* declare and init array */

/* Array read macros */
#define MAG_SENS_ARRAY( i ) pgm_read_float( MAG_SENS_LI_ARR + i )

/* Linearise supplied device output */
float MAG_SENS_Linear( long level ) {
float interp_start, interp_end;
long dev_mV, index;
dev_mV = level * ANALOG_RNG / ADC_LEV_RNG;
if ( dev_mV < MAG_SENS_IN_MIN )     /* bottom end of range */
  level = MAG_SENS_IN_MIN * ADC_LEV_RNG / ANALOG_RNG;
else if ( dev_mV >= MAG_SENS_IN_MAX )  /* top end of range */
  level = MAG_SENS_IN_MAX * ADC_LEV_RNG / ANALOG_RNG;
level -= (long) MAG_SENS_IN_MIN * ADC_LEV_RNG / ANALOG_RNG;
index = level / MAG_SENS_INTERP;
interp_start = MAG_SENS_ARRAY( index );
interp_end = MAG_SENS_ARRAY( index + 1 );
return ( interp_start + ( interp_end - interp_start ) *
    ( level % MAG_SENS_INTERP ) / MAG_SENS_INTERP );
}

/* read analog device and linearise output */
float MAG_SENS_Read() {
return( MAG_SENS_Linear( analogRead( MAG_SENS_CHAN ) ) );
}

/* read averaged analog device and linearise output */
float MAG_SENS_ReadAvg() {
int samps;
long ADClevel = 0;
/* take an average of several analog channel readings */
for ( samps = 0; samps < 20; samps++ ) {
  ADClevel += analogRead( MAG_SENS_CHAN );
  delay( 5 );
  }
return ( MAG_SENS_Linear( ADClevel / samps ) );
}

/* virtalise selected device function */
#define Position MAG_SENS_ReadAvg

LInterp.h

C Header File
Arduino C-compiler pre-processor script to generate interpolation / translation / lookup arrays in PROGMEM
/* LInterp.h   Linear interpolation array generator     */
/* <<c) dxb 1982 - 2022                                 */

#if defined( LI_ELT )           /* generate array elt   */
#if LI_LEV < LI_BND && !defined( LI_EOI )
  #if ( LI_ELT <= LI_S( LI_LEV, LI_NXT ) + ( LI_LEV == LI_BND - 1 ) )
    ,(LI_TYP) ( LI_RND + LI_OFS + LI_SCL * ( LI_LEV +
      ( LI_ELT - LI_R( 0, LI_LEV ) + LI_P( 0, LI_LEV ) ) /
        LI_R( LI_LEV, LI_NXT ) ) / LI_BND )
  #else
    #define LI_EOI
  #endif
#endif
#undef LI_ELT

#elif defined( LI_LEV )         /* process intervals    */
#define LI_ELT 1
#include "LInterp.h"
#define LI_ELT 2
#include "LInterp.h"
#define LI_ELT 3
#include "LInterp.h"
#define LI_ELT 4
#include "LInterp.h"
#define LI_ELT 5
#include "LInterp.h"
#define LI_ELT 6
#include "LInterp.h"
#define LI_ELT 7
#include "LInterp.h"
#define LI_ELT 8
#include "LInterp.h"
#define LI_ELT 9
#include "LInterp.h"
#define LI_ELT 10
#include "LInterp.h"
#define LI_ELT 11
#include "LInterp.h"
#define LI_ELT 12
#include "LInterp.h"
#define LI_ELT 13
#include "LInterp.h"
#define LI_ELT 14
#include "LInterp.h"
#define LI_ELT 15
#include "LInterp.h"
#define LI_ELT 16
#include "LInterp.h"
#define LI_ELT 17
#include "LInterp.h"
#define LI_ELT 18
#include "LInterp.h"
#define LI_ELT 19
#include "LInterp.h"
#define LI_ELT 20
#include "LInterp.h"
#define LI_ELT 21
#include "LInterp.h"
#define LI_ELT 22
#include "LInterp.h"
#define LI_ELT 23
#include "LInterp.h"
#define LI_ELT 24
#include "LInterp.h"
#define LI_ELT 25
#include "LInterp.h"
#define LI_ELT 26
#include "LInterp.h"
#define LI_ELT 27
#include "LInterp.h"
#define LI_ELT 28
#include "LInterp.h"
#define LI_ELT 29
#include "LInterp.h"
#define LI_ELT 30
#include "LInterp.h"
#define LI_ELT 31
#include "LInterp.h"
#define LI_ELT 32     /* <- repeat these lines for more */
#include "LInterp.h"  /* <- interps, with inc elt idxs  */
/* ... */
#if LI_LEV < LI_BND && !defined( LI_EOI )
#error LInterp: Too many interps in one interval. Add mapping pts or decrease LI_INT
#endif
#undef LI_EOI
#undef LI_LEV
#undef LI_NXT

#else                           /* define array params  */
#if !defined( LI_P0 ) || !defined( LI_P1 ) || !defined( LI_P2 ) || !defined( LI_P3 )
#error LIinterp: define at least 4 mapping values LI_P0 to LI_Pnn (nn < 32)
#endif
#if !defined( LI_TYP )
#define LI_TYP  float           /* default array type   */
#define LI_RND  0               /* no rounding          */
#else                           /* all integer types!   */
#define LI_RND  0.5             /* for float-int convs  */
#endif
#if !defined( LI_ARR )
#define LI_ARR  LInterp         /* default array name   */
#endif
#if !defined ( LI_RNG )         /* input ordinate range */
#error LInterp: Define an ordinate mapping scale LI_RNG
#endif
#if !defined( LI_CAL )          /* array indexing scale */
#error LInterp: Define an array-base indexing scale LI_CAL
#endif
#if !defined( LI_INT )
#define LI_INT  1               /* interp interval      */
#endif
#if !defined( LI_SCL )
#define LI_SCL  1               /* array value scale    */
#endif
#if !defined( LI_OFS )
#define LI_OFS  0               /* array value offset   */
#endif
#if !defined( LI_VAR )
#define LI_VAR  const           /* array value offset   */
#endif

#if !defined( LI_P4 )
#define LI_BND  3
#elif !defined( LI_P5 )
#define LI_BND  4
#elif !defined( LI_P6 )
#define LI_BND  5
#elif !defined( LI_P7 )
#define LI_BND  6
#elif !defined( LI_P8 )
#define LI_BND  7
#elif !defined( LI_P9 )
#define LI_BND  8
#elif !defined( LI_P10 )
#define LI_BND  9
#elif !defined( LI_P11 )
#define LI_BND  10
#elif !defined( LI_P12 )
#define LI_BND  11
#elif !defined( LI_P13 )
#define LI_BND  12
#elif !defined( LI_P14 )
#define LI_BND  13
#elif !defined( LI_P15 )
#define LI_BND  14
#elif !defined( LI_P16 )
#define LI_BND  15
#elif !defined( LI_P17 )
#define LI_BND  16
#elif !defined( LI_P18 )
#define LI_BND  17
#elif !defined( LI_P19 )
#define LI_BND  18
#elif !defined( LI_P20 )
#define LI_BND  19
#elif !defined( LI_P21 )
#define LI_BND  20
#elif !defined( LI_P22 )
#define LI_BND  21
#elif !defined( LI_P23 )
#define LI_BND  22
#elif !defined( LI_P24 )
#define LI_BND  23
#elif !defined( LI_P25 )
#define LI_BND  24
#elif !defined( LI_P26 )
#define LI_BND  25
#elif !defined( LI_P27 )
#define LI_BND  26
#elif !defined( LI_P28 )
#define LI_BND  27
#elif !defined( LI_P29 )
#define LI_BND  28
#elif !defined( LI_P30 )
#define LI_BND  29
#elif !defined( LI_P31 )
#define LI_BND  30
/* repeat following defn block for more mapping points  */
/* increasing iterators as per sequence above           */
/* also add matching interval inits at end of file      */
#elif !defined( LI_P32 )
#define LI_BND  31
/* ... */
#else
#error LInterp: Too many mapping points defined. Add extra point defs to LInterp.h
#endif

#define LI_V( i ) ( LI_P##i )           /* compile pass */
#define LI_Q( i ) ( LI_V( i ) * 1L * LI_CAL )
#define LI_P( i, j ) ( ( LI_Q( j ) - LI_Q( i ) ) / ( 1L * LI_INT * LI_RNG ) )
#define LI_R( i, j ) ( (float) ( LI_Q( j ) - LI_Q( i ) ) / ( LI_INT * LI_RNG ) )
#define LI_S( i, j ) ( LI_P( 0, j ) - LI_P( 0, i ) )

#if defined( PROGMEM ) && !defined( LI_RAM )
const LI_TYP LI_ARR[] PROGMEM = { LI_OFS
#else
LI_VAR LI_TYP LI_ARR[] = { LI_OFS
#endif
#define LI_LEV  0
#define LI_NXT  1
#include "LInterp.h"
#define LI_LEV  1
#define LI_NXT  2
#include "LInterp.h"
#undef  LI_P1
#define LI_LEV  2
#define LI_NXT  3
#include "LInterp.h"
#undef  LI_P2
#define LI_LEV  3
#define LI_NXT  4
#include "LInterp.h"
#undef  LI_P3
#define LI_LEV  4
#define LI_NXT  5
#include "LInterp.h"
#undef  LI_P4
#define LI_LEV  5
#define LI_NXT  6
#include "LInterp.h"
#undef  LI_P5
#define LI_LEV  6
#define LI_NXT  7
#include "LInterp.h"
#undef  LI_P6
#define LI_LEV  7
#define LI_NXT  8
#include "LInterp.h"
#undef  LI_P7
#define LI_LEV  8
#define LI_NXT  9
#include "LInterp.h"
#undef  LI_P8
#define LI_LEV  9
#define LI_NXT  10
#include "LInterp.h"
#undef  LI_P9
#define LI_LEV  10
#define LI_NXT  11
#include "LInterp.h"
#undef  LI_P10
#define LI_LEV  11
#define LI_NXT  12
#include "LInterp.h"
#undef  LI_P11
#define LI_LEV  12
#define LI_NXT  13
#include "LInterp.h"
#undef  LI_P12
#define LI_LEV  13
#define LI_NXT  14
#include "LInterp.h"
#undef  LI_P13
#define LI_LEV  14
#define LI_NXT  15
#include "LInterp.h"
#undef  LI_P14
#define LI_LEV  15
#define LI_NXT  16
#include "LInterp.h"
#undef  LI_P15
#define LI_LEV  16
#define LI_NXT  17
#include "LInterp.h"
#undef  LI_P16
#define LI_LEV  17
#define LI_NXT  18
#include "LInterp.h"
#undef  LI_P17
#define LI_LEV  18
#define LI_NXT  19
#include "LInterp.h"
#undef  LI_P18
#define LI_LEV  19
#define LI_NXT  20
#include "LInterp.h"
#undef  LI_P19
#define LI_LEV  20
#define LI_NXT  21
#include "LInterp.h"
#undef  LI_P20
#define LI_LEV  21
#define LI_NXT  22
#include "LInterp.h"
#undef  LI_P21
#define LI_LEV  22
#define LI_NXT  23
#include "LInterp.h"
#undef  LI_P22
#define LI_LEV  23
#define LI_NXT  24
#include "LInterp.h"
#undef  LI_P23
#define LI_LEV  24
#define LI_NXT  25
#include "LInterp.h"
#undef  LI_P24
#define LI_LEV  25
#define LI_NXT  26
#include "LInterp.h"
#undef  LI_P25
#define LI_LEV  26
#define LI_NXT  27
#include "LInterp.h"
#undef  LI_P26
#define LI_LEV  27
#define LI_NXT  28
#include "LInterp.h"
#undef  LI_P27
#define LI_LEV  28
#define LI_NXT  29
#include "LInterp.h"
#undef  LI_P28
#define LI_LEV  29
#define LI_NXT  30
#include "LInterp.h"
#undef  LI_P29
#define LI_LEV  30      /* <- repeat this set of defs   */
#define LI_NXT  31      /* <- with increasing indices   */
#include "LInterp.h"    /* <- for further map defn pts  */
#undef  LI_P30          /* <- */
/* ... */
#undef  LI_P31          /* change to match LI_BND defn  */
};

#undef LI_P0
#undef LI_ARR
#undef LI_SCL
#undef LI_TYP
#undef LI_RND
#undef LI_RNG
#undef LI_CAL
#undef LI_INT
#undef LI_SCL
#undef LI_OFS
#undef LI_BND
#undef LI_RAM
#undef LI_VAR
#undef LI_V
#undef LI_Q
#undef LI_P
#undef LI_R
#undef LI_S
#undef LI_N
#undef LI_W
#endif

/* EOF LInterp.h */

Credits

dxb_

dxb_

0 projects • 0 followers

Comments