Speed measurement with reed contact - problem when using DC motor

Hello community,

I am seeking your advice on a project I am currently working on. I love riding the road bike and I have a simple indoor trainer for training in winter or when the weather is bad. To measure the wheel speed, I wrote a python program that communicates with an Arduino via elements of the Pyduino library (GitHub - lekum/pyduino: Python library to interface with Arduino via serial connection). The wheel speed is measured using a reed contact connected to digital input 2 and ground of the arduino. The input is set on INPUT_PULLUP to prevent the pin from floating. The arduino is powered by the USB connection.
The speed measurement works perfectly fine.
Now, I want to add a fan that cools me during workout. To make things realistic, the fan is supposed to speed up with increasing wheel speed. For the fan control, I use a L298N board. The L298N is powered by a 14V DC power supply. The arduino PWM is used to control the speed of the fan.
For testing, I used a 20V DC motor of an old cordless screwdriver. After connecting everything togheter, the test worked nicely. With increasing measured wheel speed, the fan rotated faster, as intended.
Since I want to cool myself during training, I bought a small 12V DC fan. I replaced the old motor with the new fan and kept the remaining setup as it was.
Now comes the problem. From a given fan speed on, the speed measurement results in random nonsense values like 10000km/h followed by 300 km/h and again 20000km/h. When I unplug the power supply of the L298N, everything works fine again. Again, all this did not happen with the old test motor.
I have no clue where this comes from. For your information, I added the sketch of the Arduino. Please note that parts of the processing are in the python code which is not printed in my post.
I suppose that the motor current somehow influences the digital input, but I don't know how. I already use 2 separate power supplies for Arduino and L298N which I thought would prevent this kind of problem.

/*
 * Sketch to control the pins of Arduino via serial interface
 *
 * Commands implemented with examples:
 *
 * - RD13 -> Reads the Digital input at pin 13
 * - RA4 - > Reads the Analog input at pin 4
 * - WD13:1 -> Writes 1 (HIGH) to digital output pin 13
 * - WA6:125 -> Writes 125 to analog output pin 6 (PWM)
 */

char operation; // Holds operation (R, W, ...)
char mode; // Holds the mode (D, A)
int pin_number; // Holds the pin number
int speed_val; // Holds the pin number
int digital_value; // Holds the digital value
int analog_value; // Holds the analog value
int value_to_write; // Holds the value that we want to write
int wait_for_transmission = 15; // Delay in ms in order to receive the serial data

void set_pin_mode(int pin_number, char mode){
    /*
     * Performs a pinMode() operation depending on the value of the parameter
     * mode :
     * - I: Sets the mode to INPUT
     * - O: Sets the mode to OUTPUT
     * - P: Sets the mode to INPUT_PULLUP
     */

    switch (mode){
        case 'I':
            pinMode(pin_number, INPUT);
            break;
        case 'O':
            pinMode(pin_number, OUTPUT);
            break;
        case 'P':
            pinMode(pin_number, INPUT_PULLUP);
            break;
    }
}


void digital_write(int pin_number, int digital_value){
    /*
     * Performs a digital write on pin_number with the digital_value
     * The value must be 1 or 0
     */
  digitalWrite(pin_number, digital_value);
}

void analog_write(int pin_number, int analog_value){
    /*
   * Performs an analog write on pin_number with the analog_value
   * The value must be range from 0 to 255
     */
  analogWrite(pin_number, analog_value);
}

void write_signal()  // signalizes an interrupt to the serial connection
{
  Serial.print(2); 
}

void setup() {
    Serial.begin(250000); // Serial Port at 250k baud
    Serial.setTimeout(1); // Instead of the default 1000ms, in order
                            // to speed up the Serial.parseInt()   digitalWrite(in1, LOW);  
    pinMode(2, INPUT_PULLUP);
    attachInterrupt(digitalPinToInterrupt(2), write_signal, FALLING);  // rais interrupt when pin goes down
    
    digital_write(8,0);
    digital_write(5,1);
    analog_write(9, 0);    
}

void loop() {
    // Check if characters available in the buffer
    if (Serial.available() > 0) {
         
        delay(wait_for_transmission); // If not delayed, second character is not correctly read
        
        speed_val = Serial.parseInt(); // Waits for an int to be transmitted
        digital_write(4,0);
        digital_write(8,1);
        analog_write(9, speed_val);

        // Switch off if Value < 20
        if (speed_val < 20){
            digital_write(4,0);
            digital_write(8,0);
            analog_write(9, 1);
        }
    }
}

You are blindly parsing whatever is arriving trough the serial port. When this gets out of sync you can get value made out of numbers from previous and current values. How do you know what values where send?

100230201102

You should collect the characters send trough the Serial and parse them when you know the data is correct. A first fix would be to add a stop character e.g. %, $ ...

Have a look at the NMEA 0183 protocol and the TinyGPS library.

This is a standardized serial protocol used by GPS receivers. Its very easy to understand and you could make up your own and extend your application over time with new data to be send. It even supports a simple checksum.
TinyGPS is a simple parser that does not need any hardware. It just decodes the GPS messages, you could build something like this yourself.

There are other serial protocols and libraries available. Just google a bit in the forum and you will find other options as well.

Dear Klaus,

thanks a lot for your reply.
I suppose you are referencing to the part in the void loop where I am parsing the input from the python program.
I read the wikipedia page and I am currently working on an implementation of this.
However, I am not sure if this can cause my problem since this mechanism of data transfer is used regardless of whether I use the motor or not. My problem, however, only occurs when the motor is used, and more precisely, if the fan motor is used, the old screwdriver motor works perfectly fine. When unplugging the motor power supply, the problem disappears.

Sincerely yours,

Kaisel

And......It is worth noting that the inbuilt pull up resistor is a fairly high value making your input sensitive to noise . Add a 10k resistor as an external pull-up resistor to your reed switch input .
Also put some signal debounce into your code to reduce the effect of noise spikes , maybe a small Capacitor ( 0.1uF) across that resistor too.

Dear Hammy,

thanks for your answer. This is indeed what I was thinking about as well. The motor seems to introduce some kind of noise which affects the measurement. What did you mean with signal debounce? And the capacitor is supposed to work as a low pass with the resistor if I get you right?

Kaisel

kaisel:
Dear Hammy,

thanks for your answer. This is indeed what I was thinking about as well. The motor seems to introduce some kind of noise which affects the measurement. What did you mean with signal debounce? And the capacitor is supposed to work as a low pass with the resistor if I get you right?

Kaisel

Unless your magnet is a bar magnet and passes parallel to the reed switch, the leaves in the reed switch will bounce closed/open at least one time as your magnet approaches the switch. Debounce means you are using either electronic components or software to ignore the bouncing contacts. This will be true of almost all switches you will ever encounter.

Paul

Hi again,

I followed Hammys advice and added a 10kOhm resistor to the reed switch and set the input to INPUT instead of INPUT_PULLUP as before. Unfortunately, the problem persists. With the fan motor, the speed measurement goes crazy while it works nicely with the old screwdriver motor.

Regarding the debouncing, does anyone has an idea about why the rebounce might be a problem with one motor but not with the other?

Best regards,

Kaisel