FG Sensors
Published © GPL3+

Traffic Detection and Counter Using FG-3+ and Arduino UNO R4

Create a low-cost, traffic monitoring system by deploying the FG-3+ fluxgate magnetometer near roads to detect magnetic disturbances caused

BeginnerFull instructions provided1 hour4
Traffic Detection and Counter Using FG-3+ and Arduino UNO R4

Things used in this project

Hardware components

UNO R4 WiFi
Arduino UNO R4 WiFi
×1
FG-3+ Sensor
×1
Arduino 40 colored male-female jumper wires
×1

Software apps and online services

Arduino IDE
Arduino IDE

Story

Read more

Code

Code

Arduino
#include <Arduino_LED_Matrix.h>

const int sensorDig = 2;  // Digital pin 2 for sensor input (interrupt pin)

unsigned int updateRate = 100;    // Sensor update rate in ms
unsigned int measureTime = 100;   // Sensor measure time in ms

volatile unsigned int intEnable = 0;      // Interrupt counter enable flag
volatile unsigned long sensorDigCnt = 0;  // Count of sensor signal changes
unsigned long prevMillis = 0;              // For timing updates

float base_line = 0.0;                // Moving average baseline
const float alpha = 0.1;              // Smoothing factor for baseline
const float base_line_change = 10.0; // Threshold for significant change
const int N = 10;                     // Number of samples for peak event duration

int peakSamplesCount = 0;     // Samples counted during peak event
bool inPeakEvent = false;     // Flag: tracking a peak event?
float peakValue = 0.0;        // Maximum deviation recorded during peak event

int state = 0;  // State machine variable

// LED matrix setup
ArduinoLEDMatrix matrix;

const int matrixWidth = 12;
const int matrixHeight = 8;

// Car bitmap 7x5 pixels
const uint8_t carWidth = 7;
const uint8_t carHeight = 5;
const uint8_t carBitmap[carHeight] = {
  0b011110,  // roof shape
  0b1111111,  // upper body
  0b1111111,  // lower body
  0b0110110,  // wheels
  0b0000000   // chassis detail
};

uint8_t frame[matrixHeight][matrixWidth];

void clearFrame() {
  for (int y = 0; y < matrixHeight; y++) {
    for (int x = 0; x < matrixWidth; x++) {
      frame[y][x] = 0;
    }
  }
}

void drawCar(int xPos) {
  clearFrame();
  for (int row = 0; row < carHeight; row++) {
    for (int col = 0; col < carWidth; col++) {
      bool pixelOn = carBitmap[row] & (1 << (carWidth - 1 - col));
      int x = xPos + col;
      int y = (matrixHeight - carHeight) + row; // bottom aligned
      if (pixelOn && x >= 0 && x < matrixWidth && y >= 0 && y < matrixHeight) {
        frame[y][x] = 1;
      }
    }
  }
  matrix.renderBitmap(frame, matrixHeight, matrixWidth);
}

void playCarAnimation() {
  // Animate car moving from right to left
  for (int x = matrixWidth; x >= -carWidth; x--) {
    drawCar(x);
    delay(150);  // Simple blocking delay; consider millis() for non-blocking
  }
  matrix.clear();
}

void setup() {
  Serial.begin(115200);
  pinMode(sensorDig, INPUT);
  attachInterrupt(digitalPinToInterrupt(sensorDig), sensorDigHandler, RISING);
  
  matrix.begin();
  matrix.clear();

  // Initialize baseline with first measurement
  sensorDigCnt = 0;
  intEnable = 1;
  delay(measureTime);
  intEnable = 0;
  base_line = sensorDigCnt;
  Serial.print("Initial baseline: ");
  Serial.println(base_line);

  prevMillis = millis();
}

void loop() {
  unsigned long currMillis = millis();

  switch (state) {
    case 1:
      // Update baseline (moving average)
      base_line = alpha * sensorDigCnt + (1.0 - alpha) * base_line;

      // Calculate deviation from baseline
      float diff = sensorDigCnt - base_line;

      if (!inPeakEvent) {
        // Not currently tracking a peak event
        if (abs(diff) > base_line_change) {
          inPeakEvent = true;
          peakSamplesCount = 1;
          peakValue = diff;
        }
      } else {
        // Tracking peak event
        peakSamplesCount++;
        if (abs(diff) > abs(peakValue)) {
          peakValue = diff;
        }

        // End peak detection when signal returns near baseline or max samples reached
        if (abs(diff) <= base_line_change || peakSamplesCount > N) {
          Serial.print("Peak detected: ");
          Serial.println(peakValue);
          inPeakEvent = false;
          peakSamplesCount = 0;
          peakValue = 0.0;

          // Trigger car animation on new peak detected
          playCarAnimation();
        }
      }

      Serial.print("Sensor= ");
      Serial.print(sensorDigCnt);
      Serial.print(" Baseline= ");
      Serial.println(base_line);

      state = 0;
      break;
  }

  if (currMillis - prevMillis >= updateRate) {
    sensorDigCnt = 0;
    prevMillis = currMillis;
    intEnable = 1;
    delay(measureTime);
    intEnable = 0;
    state = 1;
  }
}

// Interrupt handler increments counter on rising edge
void sensorDigHandler() {
  if (intEnable == 1) {
    sensorDigCnt++;
  }
}

Credits

FG Sensors
3 projects • 7 followers
At FG Sensors our main focus are fluxgate magnetometers, custom hardware, software solutions & research.

Comments