ABS sensor scooter & arduino

Hello,

I am trying to acquire ABS sensor data but I have no idea about how to proceed.

I have visited maybe 5 forums asking the service manual of the yamaha X max ABS but it seems nobody has it or want give it. So I have no information about ABS sensor and wiring diagram.

All what I know is summurized in the attached image. It is a 2 wires sensor, one of the wire is supplied with a 12 V voltage and the other one is the signal by deduction.

I am thinking to deconnect the connector that you can see on the picture, identify the 12 V pin of the sensor and wire it to the battery 12 V with a fuse. Then I am totally lost..... I guess I have to wire the pin signal to an analog input of the arduino but the GND ????

I hope someone could help me.

Thank you in advance,
Pm

Hello,

Nobody has an idea?

I found this about magnetoresistive sensor for wheel speed:

The sensor produces a square wave output when the wheel is rotating. However, it is not switched to ground or to battery voltage as you would expect. What you will see using a scope or multimeter is the voltage drop across a single resistor or a pair of resistors in parallel, depending on the position of the reluctor/tone ring, just by moving the wheel a small amount you should be able to detect this change. Try that with a passive sensor.

The output should be around 1.2V and 0.6V or, if you are using a micro amps clamp, in the region of 14mA and 7mA. Only the frequency should change as the wheel accelerates and decelerates – unlike analogue AC sensors where the amplitude and frequency of the signal changes proportional to wheel speed. It is also possible to detect physical faults with the reluctor/tone wheel using an oscilloscope.

Have a good day,
Pm

It is probably a hall effect sensor. A regular shop manual should tell you how to test the sensor.
After you do a little research, come back and I will try to help you.
One question, what is your electronics experience.
Another thing, don't just go randomly hooking things to an Arduino input until you know what the voltage is or you will be buying a new one.

Hello,

I know more about the sensor. I have removed it from the scooter to test it today at the laboratory. I connected one of the wire to a 12 V alimentation and the other to the the GND via a serial resistance of 120 Ohm. Then I have connected the oscilloscope in parallel with the resistance and moving the sensor with hand around the ABS disc I have seen the output voltage moving from 0.8 V to 1.6 V. But it is a little bit strange because the signal is not regular and there is a king of memory of the last state!

I guess there is a better solution to wire the sensor output but I have no more idea. Maybe reduce the value of the resistance but I am scared of breaking the sensor.

Even if this this solution seems to be uncertain I have designed an operational amplifier to make the signal usable by the Arduino so almost 0 V at low state and 5 V when state is high. I will try it this weekend.

I would appreciate some help.

Another question. I was thinking about the sample rate and the way to determine it:
Considering a maximum forward speed,
V max=110 km/h=30.56 m/s

Rear wheel : 140/70 R14 -> RfrontWheel=(140.72+2.5414)/2=27.58 cm
Front wheel: 120/70 R15-> RfrontWheel=(12
0.72+2.5415)/2=27.45 cm

Considering rolling without slipping at 110 km/h,
wrearWheel = 30.56/0.2758 = 110.80 rad/s
wfrontWheel = 30.56/0.2745 = 111.33 rad/s

After convertion,
wrearWheel = 17.63 tr/s
wfrontWheel = 17.71 tr/s

It is clear that the front wheel is faster and we will focus on this one.
The ABS disc is divided with 40 marks,
1/ wfrontWheel= 0.0565 s/tr

To conclude between to marks there is 0.0565/40=0.0014 s
So 1 kHz it seems to be too much for the Arduino mega?

Thank you very much,
Pm

I can't help you if you don't answer my questions.
Did you research hall sensor ?
What kind of scooter is this ?
What are you intending to do with the output of the sensor when you get it to work?
Did you look at a shop manual to find out how to test the sensor?
Don't hook up the sensor until you know what the correct wiring is.
You need to take this one step at a time. First find out what kind of sensor this is ands the correct wiring before you worry about the math.

Hello,

I didn’t answer to your question because I am a little bit lost.
I have the repair manual of the Yamaha X max 125 ABS 2012 in French but there is just few words about how the ABS sensors work (For business point of view it is better to change it). The output wiring diagram is include in the ECU it is the secret of each motorcycle maker. If you are familiar with French I can share the manual with you in MP. I have looking for it in English language but impossible to find for ABS version.

All what I know is that it is a two wire sensor. One wire is supplied with 12 V and the other is the signal. With a 120 Ohms resistance in serial with the output, the measured voltage on the resistance moves between 0.8 to 1.6 V and so the current between 7 mA to 14 mA.

I have seen different kind of magnetic sensors to measure wheel speed in the literature but the two mains are:
-Hall effect
-Magnetoresistive

Take a look to this data sheet that I found yesterday on the net (DATASHEET). So it seems to be a magnetoresistive technology.

I would like acquire the signal on an Arduino to get wheel speed during a testing scenario.

It is not easy to find the correct wire diagram because I didnt have any information about it. Of course no manufacturer written on the sensor and no more information on internet.

I appreciate your help.

Thank you very much,
Pm

With the ABS sensor on the scooter and plugged in , hook your scope to the signal wire , spin the front wheel and see what the output is.

Hello,

I have spend time to work on ABS sensor and I think I am working in the good direction. I have used an operational amplifier to transform the sensor output in logical state for the arduino.

Now I am trying to compute speed with rear ABS sensor measurement in order to compare with speedometer.

To compute speed I am thinking to create a routine function which compute the number of rising edge during a fixed period.

Considering the following assumptions,

PPR=50; // pulse/revolution on ABS disck

T=0.01; // Periode of the routine function

The wheel rpm is given by,

wheelrpm= (rpmcount/PPR)10060;

Are you agree?

Thank you,
Pm

Re,

I did a short sketch to compute rotational wheel speed, vehicle velocity and travel distance. But I have some problem when I reduced the fixed period during which I count the pulse or when I increase the number of pulse per revolution.

I would like compute rpm, speed and distance every 10 ms but it doesn't work. And I didn't understand why.

I would appreciate some help.

You can find my code below,

// Program to compute rotational wheel speed, vehicle velocity and travel distance from the measure of a hall effect sensor
// It uses a fixed period to count the number of rising edge and compute the wheel speed in rpm, the vehicle velocity in km/h and the travel distance in m

// Libraries:
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

// Display SSD1906 settings:
#define OLED_MOSI   9
#define OLED_CLK   10
#define OLED_DC    11
#define OLED_CS    12
#define OLED_RESET 13

Adafruit_SSD1306 display(OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS);

// Variables:
volatile byte rpmCounter=0;             // pulse counter
unsigned int  counter=0;                // total number of counting pulses since begining only for debugging 
unsigned int  rpm=0;                    // rotational wheel speed in rpm
unsigned long timeOld=0;                // end time of the last period in ms
const int period=10;                    // time period for pulse counting in ms
const int ppr=48;                       // pulse per revolution
const float radiusRearWheell=0.2758;    // radius of the wheel in m
const float pi = 3.14159;               // pi constant
float Speed=0;                          // vehicle speed in km/h
float distance=0;                       // travel distance in m

//------------------------------------------------------------------------------------------------//
//------------------------------------------------------------------------------------------------//

void disp(float SpeedToDisp, int rpmToDisp, float DistanceToDisp, int counterToDisp)   // display function for SSD1906
{
  // vehicle speed displaying:
  display.setTextSize(1);  
  display.setCursor(0,3);        
  display.println("Speed");     
  display.setCursor(46,0); 
  display.setTextSize(2);          
  display.println(SpeedToDisp);
  display.setCursor(95,3);
  display.setTextSize(1);        
  display.println(" km/h"); 
  
  // wheel rpm displaying:
  display.setTextSize(1);  
  display.setCursor(0,18);        
  display.println("RPM");     
  display.setCursor(46,15); 
  display.setTextSize(2);          
  display.println(rpmToDisp);
  display.setCursor(95,18);
  display.setTextSize(1);        
  display.println(" rpm"); 

  // travel distance displaying:
  display.setTextSize(1);  
  display.setCursor(0,33);        
  display.println("Dist."); 
  display.setCursor(46,30); 
  display.setTextSize(2);          
  display.println(DistanceToDisp);
  display.setCursor(95,33);
  display.setTextSize(1);        
  display.println(" m");

  // global pulse counter displaying:
  display.setTextSize(1);  
  display.setCursor(0,48);        
  display.println("Counter"); 
  display.setCursor(46,45); 
  display.setTextSize(2);          
  display.println(counterToDisp);
 
  display.display();
  display.clearDisplay();
  }
  
//------------------------------------------------------------------------------------------------//

void rpm_fun() // function for attachInterrupt
 {
      rpmCounter++ ;   // Update rpm counter
      counter++;       // Update global counter just for debugging
 }
 
//------------------------------------------------------------------------------------------------//

void setup()   {                
  Serial.begin(115200);
  
  //init SSD1906 display:
  display.clearDisplay();
  display.begin(SSD1306_SWITCHCAPVCC);
  display.clearDisplay();
  display.setTextColor(WHITE);
  display.setTextSize(1);

  attachInterrupt(0, rpm_fun, RISING);
}

//------------------------------------------------------------------------------------------------//
void loop() {
  
  if (millis() - timeOld == period){ 
    detachInterrupt(0);                                                     // disable interrupt when calculating
    
    rpm = (rpmCounter / ppr) * (60000/ period) ;                            // convert frecuency to RPM be carefull period is in ms and need to be multiplied by 60000 to be converted in min
    Speed = 3.6 * radiusRearWheell * rpm * 2 * pi / 60;                     // speed calculation v=3.6*r*w with w in rad/s
    distance = distance + (rpmCounter / ppr) * 2 * pi * radiusRearWheell;   // distance calculation

    rpmCounter = 0;       // restart the RPM counter
    timeOld = millis();   // uptade lasmillis

    attachInterrupt(0, rpm_fun, RISING); //enable interrupt
    
    disp(Speed, rpm, distance, counter ); //display results on the screen

    Serial.print("RPM =\t"); 
    Serial.print(rpm);
    Serial.print("\t speed=\t"); 
    Serial.print(Speed); 
    Serial.print("\t distance=\t");
    Serial.print(distance);
    Serial.print("\t global counter=\t");
    Serial.print(counter); 
    Serial.print("\t Time=\t");
    Serial.println(timeOld/1000);
  }

}

Thank you,
Pm

You can't count on "seeing" the exact millis() value that you want:

  if (millis() - timeOld == period){

Instead, test for greater-than-or-equal-to:

   uint32_t deltaT = millis() - timeOld;
   if (deltaT >= period){

Then use the delta in your calculation:

    rpm = (rpmCounter / ppr) * (60000/ deltaT) ;

You should also be careful about how long it takes to update the display (?) and print some things to Serial (~4.5ms). By the time that is finished, the period may have already elapsed.

For better resolution, you may want to use micros() instead of millis().

Cheers,
/dev

Hello dev/,

Thank you for the code it works but I don't understand something. According to the simple following code:

unsigned long previousTime=0;           // end time of the last period in microsecond
unsigned long currentTime=0;
unsigned long executionTime=0;
unsigned long deltaTime=0;
const long period=1000000;              // time period for pulse counting in microsecond


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

//------------------------------------------------------------------------------------------------//
void loop() {
  currentTime = micros();
  deltaTime = currentTime-(previousTime-executionTime);
  
  if (deltaTime >= period){ 
       Serial.print("\t currentTime=\t");
       Serial.println(currentTime);
       previousTime = micros();
       executionTime = previousTime-currentTime;   
  }

}

In the main loop the printed current time is supposed to be updated each second ( 1 000 000 microsecond) and regarding the obtained serial monitor

         currentTime=	1000000
	 currentTime=	2000004
	 currentTime=	3000008
	 currentTime=	4000012
	 currentTime=	5000016
	 currentTime=	6000020
	 currentTime=	7000020
	 currentTime=	8000024
	 currentTime=	9000028
	 currentTime=	10000028
	 currentTime=	11000028
	 currentTime=	12000032
	 currentTime=	13000032
	 currentTime=	14000036
	 currentTime=	15000036

There is a kind of random delay around 4 microseconds. For sure during short simulation it is not a problem but if the simulation lasts several hours it could introduce error?

Thanks,
Pm

I have found a solution:

unsigned long previousTime=0;           // end time of the last period in microsecond
unsigned long currentTime=0;
unsigned long executionTime=0;
unsigned long deltaTime=0;
const long period=10000;              // time period for pulse counting in microsecond


void setup()   {                
  Serial.begin(115200);
  Serial.println("Start");
  
}

//------------------------------------------------------------------------------------------------//
void loop() {
  currentTime = micros();
  deltaTime = currentTime-previousTime; 
  
  if (deltaTime >= period){ 
       Serial.print("\t currentTime=\t");
       Serial.println(currentTime); 
       previousTime +=period;
  }

}

Thanks,
Pm

Perfect! Adding the period is the correct way to keep the intervals evenly-spaced, even when the loop takes a little extra time.

BTW, the micros() timer has a resolution of 4us, so everything is measured in multiples of that.

Cheers,
/dev

Hello,

I have another question. The main objective of the sketch above is to realize a speedometer computing vehicle velocity, travel distance and wheel rpm. It is based on ABS sensor measures.
I would like acquire hall effect sensor data every 10 ms (for sure your now my project) and plot them of a small OLED screen (SSD1906). Regarding watching confort and the constraints on screen refresh rate 300ms seems to be a good compromise.

The following sketch works but it takes a little bit more than 10ms to initialize the screen with the command:
display.begin(SSD1306_SWITCHCAPVCC);

// Program to compute rotational wheel speed, vehicle velocity and travel distance from the measure of a hall effect sensor
// The program used a fixed period to count the number of rising edge and compute the wheel speed in rpm

// Libraries:
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <NeoHWSerial.h>

// Serial communication:
#define DEBUG_PORT_TYPE NeoHWSerial
#define DEBUG_PORT NeoSerial

// Display SSD1906 settings:
#define OLED_MOSI   9
#define OLED_CLK   10
#define OLED_DC    11
#define OLED_CS    12
#define OLED_RESET 13

Adafruit_SSD1306 display(OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS);

// Variables:
volatile byte rpmCounter=0;             // pulse counter
unsigned long  counter=0;                // total number of counting pulses since begining only for debugging 
unsigned int  rpm=0;                    // rotational wheel speed in rpm
unsigned long previousTimeSensor=0;     // end time of the last sensor period in micros
unsigned long previousTimeScreen=0;     // end time of the last screen period in micros
unsigned long currentTime=0;            // actual time in micros
unsigned long deltaTimeSensor=0;
const long periodSensor=10000;          // time period for pulse counting in micros
const long periodScreen=300000;        // time period for refresch the screen in micros
const int ppr=40;                       // pulse per revolution
const float radiusRearWheell=0.2758;    // radius of the wheel in m
const float pi = 3.14159;               // pi constant
float Speed=0;                          // vehicle speed in km/h
float distance=0;                       // travel distance in m

//------------------------------------------------------------------------------------------------//
//------------------------------------------------------------------------------------------------//
void disp(float SpeedToDisp, int rpmToDisp, float DistanceToDisp, int counterToDisp)   // display function for SSD1906
{
  // vehicle speed displaying:
  display.setTextSize(1);  
  display.setCursor(0,3);        
  display.print("Speed");     
  display.setCursor(38,0); 
  display.setTextSize(2);          
  display.print(SpeedToDisp);
  display.setCursor(95,3);
  display.setTextSize(1);        
  display.print(" km/h"); 
  
  // wheel rpm displaying:
  display.setTextSize(1);  
  display.setCursor(0,18);        
  display.print("RPM");     
  display.setCursor(38,15); 
  display.setTextSize(2);          
  display.print(rpmToDisp);
  display.setCursor(98,18);
  display.setTextSize(1);        
  display.print(" rpm"); 

  // travel distance displaying:
  display.setTextSize(1);  
  display.setCursor(0,33);        
  display.print("Dist."); 
  display.setCursor(38,30); 
  display.setTextSize(2);          
  display.print(DistanceToDisp,1);
  display.setCursor(110,33);
  display.setTextSize(1);        
  display.print(" m");

  // global pulse counter displaying:
  display.setTextSize(1);  
  display.setCursor(0,48);        
  display.print("Coun."); 
  display.setCursor(38,45); 
  display.setTextSize(2);          
  display.print(counterToDisp);
 
  display.display();
  display.clearDisplay();
  
 }
  
//------------------------------------------------------------------------------------------------//
void rpmCountFun() // function for attachInterrupt
 {
      rpmCounter++ ;   // Update rpm counter
      counter++;       // Update global counter just for debugging
 }

//------------------------------------------------------------------------------------------------//
void updateSensor() // function for attachInterrupt
{
   deltaTimeSensor = currentTime - previousTimeSensor;
   if (deltaTimeSensor >= periodSensor){ 
    detachInterrupt(0);                                             // disable interrupt when calculating
    rpm = rpmCounter*6000000/(ppr*deltaTimeSensor );                // convert frecuency to RPM be carefull period is in micros and need to be multiplied by 6000000 to be converted in min
    Speed = 3.6*radiusRearWheell*rpm*2*pi/ 60;                      // speed calculation v=3.6*r*w with w in rad/s
    distance = distance + rpmCounter*2*pi*radiusRearWheell/ppr;     // distance calculation
    rpmCounter = 0;                                                 // restart the RPM counter
   
    DEBUG_PORT.print(currentTime);
    DEBUG_PORT.print("\t \t \t "); 
    DEBUG_PORT.print(rpm);
    DEBUG_PORT.print("\t \t "); 
    DEBUG_PORT.print(Speed); 
    DEBUG_PORT.print("\t \t ");
    DEBUG_PORT.print(distance);
    DEBUG_PORT.print("\t \t \t ");
    DEBUG_PORT.println(counter); 
    
    previousTimeSensor += periodSensor;       // uptade previousTimeSensor
    attachInterrupt(0, rpmCountFun, RISING);  //enable interrupt
   }
   
}

//------------------------------------------------------------------------------------------------//
void updateScreen() // function for attachInterrupt
{
  if (currentTime - previousTimeScreen >= periodScreen){ 
        disp(Speed, rpm, distance, counter );           // display results on the screen
        previousTimeScreen += periodScreen;             // uptade previousTimeScreen
  }
  
}

//------------------------------------------------------------------------------------------------//
void setup()   {            
    DEBUG_PORT.begin(115200);
    
    //init SSD1906 display:
    display.clearDisplay();
    display.begin(SSD1306_SWITCHCAPVCC);
    display.clearDisplay();
    display.setTextColor(WHITE);

    attachInterrupt(0, rpmCountFun, RISING);
    
    DEBUG_PORT.print("currentTime\t");
    DEBUG_PORT.print("\t RPM \t"); 
    DEBUG_PORT.print("\t speed\t"); 
    DEBUG_PORT.print("\t distance\t");
    DEBUG_PORT.println("\t global counter\t");
}

//------------------------------------------------------------------------------------------------//
void loop() {
  currentTime = micros();
  updateSensor();
  updateScreen();
 
}

So the first currentTime value is 13032 microsecond.

currentTime		 RPM 		 speed		 distance		 global counter	
13032	 	 	 11	 	 1.14	 	 0.04	 	 	 1
20000	 	 	 0	 	 0.00	 	 0.04	 	 	 1
30004	 	 	 74	 	 7.69	 	 0.26	 	 	 6
40000	 	 	 15	 	 1.56	 	 0.30	 	 	 7
50000	 	 	 30	 	 3.12	 	 0.39	 	 	 9
60004	 	 	 29	 	 3.02	 	 0.48	 	 	 11
70004	 	 	 14	 	 1.46	 	 0.52	 	 	 12
80004	 	 	 44	 	 4.57	 	 0.65	 	 	 15
90000	 	 	 15	 	 1.56	 	 0.69	 	 	 16
100004	 	 	 59	 	 6.13	 	 0.87	 	 	 20
110004	 	 	 14	 	 1.46	 	 0.91	 	 	 21
120000	 	 	 60	 	 6.24	 	 1.08	 	 	 25
130004	 	 	 14	 	 1.46	 	 1.13	 	 	 26
140004	 	 	 89	 	 9.25	 	 1.39	 	 	 32
150000	 	 	 15	 	 1.56	 	 1.43	 	 	 33
160000	 	 	 105	 	 10.92	 	 1.73	 	 	 40
170004	 	 	 14	 	 1.46	 	 1.78	 	 	 41
180004	 	 	 29	 	 3.02	 	 1.86	 	 	 43
190004	 	 	 14	 	 1.46	 	 1.91	 	 	 44

Is there another way to do screen initialisation or a tip to avoid the first little delay?

Thanks,
Pm

Sure, at the end of setup, just set the previous time variables to the current micros():

void setup()
{
   ...

  DEBUG_PORT.flush(); // wait for header line to go out

  // Start timing from NOW
  previousTimeScreen = 
  previousTimeSensor = micros();
}

If you don't like seeing

currentTime	 RPM
13032		 ...
23032		 ...
33032		 ...

... you could subtract the initial value before writing it:

   DEBUG_PORT.print( currentTime - initialTime );
  .
  .
  .

void setup()
{
    ...

  DEBUG_PORT.flush(); // wait for header line to go out

  // Start timing from NOW
  initialTime = micros();
  previousTimeScreen =
  previousTimeSensor = initialTime;

  attachInterrupt( 0, rpmCountFun, RISING ); // start counting NOW

}

BTW, I think you're missing some pulses by detaching the interrupt handler. Just disable interrupts for a short period of time to get the rpmCounter value and reset it to 0:

void updateSensor() // function for attachInterrupt
{
   deltaTimeSensor = currentTime - previousTimeSensor;
   if (deltaTimeSensor >= periodSensor){ 
    cli();                                             // disable interrupts
      uint8_t localRPMcounter = rpmCounter;
      rpmCounter = 0;
    sei();                                            // enable interrupts
    rpm = localRPMcounter*6000000/(ppr*deltaTimeSensor );
        ...
    DEBUG_PORT.println(counter); 
    
    previousTimeSensor += periodSensor;       // uptade previousTimeSensor
   }
   
} // updateSensor

Missing pulses will affect the speed calculation.

And because counter is a multi-byte variable, you should grab a copy while interrupts are disabled:

     cli();                                             // disable interrupts
      uint8_t localRPMcounter = rpmCounter;
      rpmCounter = 0;
      uint32_t localCounter = counter;
    sei();                                            // enable interrupts

... and print that variable instead:

    DEBUG_PORT.println( localCounter );

Cheers,
/dev

One time again thanks. For timing issue it is perfect. But one problem solved means two new ones.

I used SSD1906 LCD screen and it take too long to refresh (display period is 300ms and sensor acquisition period is 10 ms). Even if I comment every serial printed values without the current time, I obtain:

currentTime RPM speed distance global counter 
…
270004
280004
290000
300000
336932
337328
337764
340004
350000
....
580000
590000
600000
636932
637328
637768
640000
650004
660000
….

36.932 ms to refresch and print time on serial monitor!

So I have looked for a way to keep legend as fixed and just refresh the value but I didn’t find a method to do it. So I have comment everything on the screen without speed value it comes:

…
260000
270000
280000
290000
300000
327604
328004
330000
340004
350000
360000
…

27.604 ms to refresh speed value without any legend and print time on serial monitor!

Is there a way to accelerate the refresh time or to manage timing?

The other problem is a little bit curious. When I launch the program (with Digital 2 empty) the value are properly initialized, the screen display zero for each one.
But just moving a little bit the screen, the counter is incremented without any connection on the D2 input. If I connect a simple wire (just a wire) the counter becomes crazy:

currentTime RPM speed distance global counter 
10004 29 3.02 0.09 2
20004 14 1.46 0.13 3
30000 60 6.24 0.30 7
40004 14 1.46 0.35 8
50004 44 4.57 0.48 11
60004 0 0.00 0.48 11
70000 60 6.24 0.65 15
80004 0 0.00 0.65 15
90000 60 6.24 0.82 19
100004 14 1.46 0.87 20
110004 44 4.57 1.00 23
120000 30 3.12 1.08 25
130000 15 1.56 1.13 26
140000 0 0.00 1.13 26
150004 14 1.46 1.17 27
160004 14 1.46 1.21 28
170004 29 3.02 1.30 30
180000 30 3.12 1.39 32

I don’t understand.

Have a good day,
Pm

The second issue was a problem with the gnd connection.

But my wiring scheme seems to be false. I have used:


with a LM293 instead of the LM393.

Is there someone experienced with magnetic sensor for speedometer?

Thank you,
Pm

...it takes too long to refresh (display period is 300ms and sensor acquisition period is 10 ms). Even if I comment every serial printed values without the current time, I obtain... 36.932 ms to refresh and print time on serial monitor!

There are a few things you can do:

  • Draw the labels in setup, then draw just the changing numbers in loop. This will save time in creating the display bitmap, and you won't have to call clearDisplay at the beginning of a refresh.

  • Draw things in a series of small steps, using a state variable to keep track of what has been updated so far. The last step is to call display.display(), which transfers the entire bitmap to the LCD. Perhaps something like this:

uint8_t displayStep = 0;

bool disp( float SpeedToDisp, int rpmToDisp, float DistanceToDisp, int counterToDisp)   // display function for SSD1906
{
  switch (displayStep++) {

    case 1:
      display.clearDisplay(); // could eliminate this if labels drawn in setup
      break;

    case 2:
      // vehicle speed displaying:
      display.setTextSize(1);  \
      display.setCursor(0,3);   |  This could go in setup
      display.print("Speed");  / 
      display.setCursor(38,0); 
      display.setTextSize(2);          
      display.print(SpeedToDisp);
      display.setCursor(95,3); \
      display.setTextSize(1);   |  This could go in setup
      display.print(" km/h");  /
      break;

    case 3:
      // wheel rpm displaying:
      display.setTextSize(1);  
      display.setCursor(0,18);        
      display.print("RPM");     
      display.setCursor(38,15); 
      display.setTextSize(2);          
      display.print(rpmToDisp);
      display.setCursor(98,18);
      display.setTextSize(1);        
      display.print(" rpm");
      break;

    case 4:
      // travel distance displaying:
      display.setTextSize(1);  
      display.setCursor(0,33);        
      display.print("Dist."); 
      display.setCursor(38,30); 
      display.setTextSize(2);          
      display.print(DistanceToDisp,1);
      display.setCursor(110,33);
      display.setTextSize(1);        
      display.print(" m");
      break;

    case 5:
      // global pulse counter displaying:
      display.setTextSize(1);  
      display.setCursor(0,48);        
      display.print("Coun."); 
      display.setCursor(38,45); 
      display.setTextSize(2);          
      display.print(counterToDisp);
      break;

    case 6:     
      display.display();
      displayStep = 0; // all done!
      break;
  }

} // disp

//-------------------

void updateScreen()
{
  if ((currentTime - previousTimeScreen >= periodScreen) {
        previousTimeScreen += periodScreen;             // update previousTimeScreen
        displayStep = 1; // start the refresh
  }

  if (displayStep > 0) { 
        disp(Speed, rpm, distance, counter );           // display results on the screen
  }  
}

If the last step, display.display() still takes too long, you should switch to the u8g2 library. It uses less RAM than the AdaFruit library because the display is rewritten in sections (i.e., "pages"). You have to redraw everything on each page, but the transfer of one page will be much quicker. I think there 8 pages for your size display, so the RAM requirement is 1/8th, and the bitmap transfer time will be 1/8th the time. It's the old speed-vs-RAM tradeoff.

You could add a second state variable, pageNumber, to make sure you draw each page in steps. With 8 pages and 6 steps per page, you can spread the screen refresh across 48 GPS intervals (480ms). Still pretty fast, but you can probably tweak the steps to get back to a 300ms refresh time.

Cheers,
/dev

Hello dev/,

Thank you for your complete answer. I have tried the method to display in series, it is very smart and faster but not enough to reach the 10 ms. So as you suggest I think I should use the u8g2 library. I will study the library today.
However before solve display problem I would like find a solution for the sensor issue…
Dividing counter by 2 and setting attachInterrupt() on falling edges the result seems more realist. I am going to perform some static tests on the scooter.

Have a good day,
Pm

not [fast enough to] enough to reach the 10 ms.

Can you increase the SPI clock speed? The display can probably go much faster than the default speed, if the wires aren't too long. If it's a shield, it should be no problem going faster.

Remember, these are time windows, not a hard 10ms deadline. The display update does not disable interrupts, so the sensor should keep counting. And the GPS queue can hold off for 40ms.

To service the IMU, you might be able to drop a call to yield inside the LCD library. In Adafruit_SSD1306.cpp, near line 450 in the ::display method:

   for (uint16_t i=0; i<(SSD1306_LCDWIDTH*SSD1306_LCDHEIGHT/8); i++) {
      fastSPIwrite(buffer[i]);

      // yield once every 1024 bytes (or try other numbers)
      if ((i & 0x3FF) == 0)
        yield();
    }

This will poll the IMU periodically through your yield function.

You could also enable an IMU interrupt before calling display.display() (and disable it afterwards). The ISR could buffer the new IMU reading in a queue. This is just like NeoGPS does with fixes and Serial does with characters.

I would like find a solution for the sensor issue…

But my wiring scheme seems to be false.

I'm not sure what problem you are having with the sensor. I would suggest a new post in the Electronics section, with your schematic and oscilloscope traces. You could also try an EE forum: eevblog, allaboutcircuits, electro-tech-online, etc.

FWIW, I don't see any capacitive decoupling between the sensor and the input to the op amp. The Zener will lock down spikes from V+ to GND, but there's an opportunity for high-frequency noise to sneak through. I think. :slight_smile: Ask the EEs.

Cheers,
/dev