Police LIDAR gun simulator – trigger your laser detector

I always wondered how can I find out if my Beltronics V975R radar detector works properly. A LIDAR gun is very expensive and in my country, the police use LIDAR guns rarely.
So I needed a device that can simulate Police Laser Gun.

Each laser gun operates at a 904nM wavelength with short pulse bursts.

I found on the internet the Arduino code that can simulate multiple radar guns.
You can access that instructable HERE.

Project description

There are twelve simulated laser guns. The current laser detector is shown on a display. You can switch between radar guns by pressing a button. The name of the laser gun will scroll through the display.
There is another button that will generate a specific infrared signal.

Parts required

  • 128×32 I2C Display
  • Arduino board
  • 2 x 10kOhm resistor
  • 2 x momentary(push) button
  • 940nm infrared emitter LED (it is close enough to 904nm)
  • 1 x resistor for LED – resistance depends on the LED technical specs

My LED is a VISHAY TSAL6200 (940nm, 1.35V, 100mA) so if you will use Arduino UNO, you will need a 36 Ohm resistor.
If you will use an Arduino Pro Mini 3.3V 8Mhz, you will need a 20 Ohm resistor.
If you have another LED, you can use THIS OHM’s LAW CALCULATOR to calculate resistor value.

I used an Arduino Pro Mini 3.3V 8Mhz in examples, but for the final project, I used an ATmega328P DIP that I programmed to work at 3.3V with 8Mhz internal clock.
The display I bought from China and it is compatible with Adafruit SSD1306 and GFX libraries. Probably the display is a replica of “Monochrome 128×32 I2C OLED graphic display” from Adafruit, which is ten times more expensive :).

The libraries and the wiring info can be found HERE

 

Test on a breadboard first

For the 128×32 I2C Display :

  • GND goes to ground
  • Vin goes to 5V
  • SDA to I2C Data (on the Uno, this is A4 on the Mega it is 20 and on the Leonardo digital 2)
  • SCL to I2C Clock(on the Uno, this is A5 on the Mega it is 21 and on the Leonardo digital 3)

Connect the LED’s anode to the ground and the cathode to the D13 through a 20 Ohm resistor
Connect the two buttons to pins D12 and D11.

Arduino code

Here is the Arduino code for the police LIDAR gun simulator.

#include 
#include 
#include 
#include 

#define OLED_RESET 4
Adafruit_SSD1306 display(OLED_RESET);

#if (SSD1306_LCDHEIGHT != 32)
#error("Height incorrect, please fix Adafruit_SSD1306.h!");
#endif
int  displayLength, minX;
#define BUFFDSIZE 200
char message[BUFFDSIZE];

int pulse = 1; // pulse size length in microseconds
int choice = 0;  // select laser gun model type
int lastchoice = 0; // recall last selection choice
int fire; // trigger fire button
int LIDAR_EMITTER = 13;
int TRIGGER_BUTTON = 11;
int CHANGE_MODE_BUTTON = 12;
int CHANGE_MODE_BUTTON_PRESSED = 0;


void setup() {
  Serial.begin(9600);
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  // initialize with the I2C addr 0x3C (for the 128x32)

  pinMode(LIDAR_EMITTER, OUTPUT);  // 940nM LED output (mimic 904nM laser diode)
  pinMode(CHANGE_MODE_BUTTON, INPUT);
  pinMode(TRIGGER_BUTTON, INPUT);
  Serial.println("start");




  setLaserName("Power On");
  displayLength = display.width();
  minX = -12 * strlen(message);
  displayData();
}

void loop() {

  if (digitalRead(CHANGE_MODE_BUTTON) == 1) {
    CHANGE_MODE_BUTTON_PRESSED = 0;
  }
  if (digitalRead(CHANGE_MODE_BUTTON) == 0 && CHANGE_MODE_BUTTON_PRESSED == 0) {
    if (choice < 12) {
      choice ++ ;
    } else {
      choice = 0;
    }
    CHANGE_MODE_BUTTON_PRESSED = 1;
    Serial.print("choice ");
    Serial.println(choice);
  }


  if (choice != lastchoice) {
    // clear display only if it's different
    displayLength = display.width();
  }
  lastchoice = choice;



  fire = digitalRead(TRIGGER_BUTTON);
  if (fire == 0) {
    Serial.print("fired ");
    Serial.println(choice);
  }
  switch (choice) {
    case 0:
      setLaserName("Ultralyte Non-LR"); // 100 pulses per second

      if (fire == 0) {
        for (int a = 1; a <= 3; a++) {
          digitalWrite(LIDAR_EMITTER, HIGH);
          delayMicroseconds(pulse);
          digitalWrite(LIDAR_EMITTER, LOW);
          delayMicroseconds(9999); // 10ms
        }
      }
      break;
    case 1:
      setLaserName("Ultralyte Rev.1"); // 100pps
      if (fire == 0) {
        for (int a = 1; a <= 3; a++) {
          digitalWrite(LIDAR_EMITTER, HIGH);
          delayMicroseconds(pulse);
          digitalWrite(LIDAR_EMITTER, LOW);
          delayMicroseconds(9999); // 10ms
        }
      }
      break;
    case 2:
      setLaserName("Jenoptik LaserPL");// 100pps
      if (fire == 0) {
        for (int a = 1; a <= 3; a++) {
          digitalWrite(LIDAR_EMITTER, HIGH);
          delayMicroseconds(pulse);
          digitalWrite(LIDAR_EMITTER, LOW);
          delayMicroseconds(9999); // 10ms
        }
      }
      break;
    case 3:
      setLaserName("Kustom Prolaser3");// 200 pps
      if (fire == 0) {
        for (int a = 1; a <= 3; a++) {
          digitalWrite(LIDAR_EMITTER, HIGH);
          delayMicroseconds(pulse);
          digitalWrite(LIDAR_EMITTER, LOW);
          delayMicroseconds(4999); // 5ms
        }
      }
      break;
    case 4:
      setLaserName("Jenoptik Laveg"); // 600pps
      if (fire == 0) {
        for (int a = 1; a <= 3; a++) {
          digitalWrite(LIDAR_EMITTER, HIGH);
          delayMicroseconds(pulse);
          digitalWrite(LIDAR_EMITTER, LOW);
          delayMicroseconds(1666);
        }
      }
      break;
    case 5:
      setLaserName("Kustom Prolaser1"); // 380pps
      if (fire == 0) {
        for (int a = 1; a <= 3; a++) {
          digitalWrite(LIDAR_EMITTER, HIGH);
          delayMicroseconds(pulse);
          digitalWrite(LIDAR_EMITTER, LOW);
          delayMicroseconds(2631);
        }
      }
      break;
    case 6:
      setLaserName("Ultralyte Rev.2");  // 125 pps
      if (fire == 0) {
        for (int a = 1; a <= 3; a++) {
          digitalWrite(LIDAR_EMITTER, HIGH);
          delayMicroseconds(pulse);
          digitalWrite(LIDAR_EMITTER, LOW);
          delayMicroseconds(8000);
        }
      }
      break;
    case 7:
      setLaserName("Stalker LZ-1");  // 130pps
      if (fire == 0) {
        for (int a = 1; a <= 3; a++) {
          digitalWrite(LIDAR_EMITTER, HIGH);
          delayMicroseconds(pulse);
          digitalWrite(LIDAR_EMITTER, LOW);
          delayMicroseconds(7691);
        }
      }
      break;
    case 8:
      setLaserName("Kustom Prolaser2");  // 238pps
      if (fire == 0) {
        for (int a = 1; a <= 3; a++) {
          digitalWrite(LIDAR_EMITTER, HIGH);
          delayMicroseconds(pulse);
          digitalWrite(LIDAR_EMITTER, LOW);
          delayMicroseconds(4201);
        }
      }
      break;
    case 9:
      setLaserName("Laser Atlanta");  // 238pps
      if (fire == 0) {
        for (int a = 1; a <= 3; a++) {
          digitalWrite(LIDAR_EMITTER, HIGH);
          delayMicroseconds(pulse);
          digitalWrite(LIDAR_EMITTER, LOW);
          delayMicroseconds(4201);
        }
      }
      break;
    case 10:
      setLaserName("Laser Atlanta Stealth Mode");  // 238pps  // 2 pulses fire followed by 5 missing pulses
      if (fire == 0) {
        for (int a = 1; a <= 2; a++) {
          digitalWrite(LIDAR_EMITTER, HIGH);
          delayMicroseconds(pulse);
          digitalWrite(LIDAR_EMITTER, LOW);
          delayMicroseconds(4201);
          digitalWrite(LIDAR_EMITTER, HIGH);
          delayMicroseconds(pulse);
          digitalWrite(LIDAR_EMITTER, LOW);
          delayMicroseconds(12603);  // need 6 delays units (4201*3)
          delayMicroseconds(12603);  // (4201*3)
        }
      }
      break;
    case 11:
      setLaserName("Kustom ProLite");  // 200 pps
      if (fire == 0) {
        for (int a = 1; a <= 3; a++) {
          digitalWrite(LIDAR_EMITTER, HIGH);
          delayMicroseconds(pulse);
          digitalWrite(LIDAR_EMITTER, LOW);
          delayMicroseconds(4999); // 5ms
        }
      }
      break;
  }

  displayData();

}


void setLaserName(char* name) {

  sprintf(message, "%s", name);
  //displayLength = display.width();
}
void clearBUFFD() { //just clear the data buffer
  memset(message, 0x00, BUFFDSIZE);
}
void displayData() {
  display.clearDisplay();
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.setTextWrap(false);
  display.setCursor(displayLength, 00);
  display.println(message);

  if (fire == 0) {
    display.setTextSize(1.5);
    display.println("      ...FIRE...");
  }

  display.display();

  if (--displayLength < minX) displayLength = display.width();
}


 

 

Final project

I wanted to make my police LIDAR gun simulator portable, so I added a LiPo battery and a charger board for it.
I had a broken glue gun, so I used it as an enclosure for my electronic project.

I replaced the Arduino Pro MINI 3.3V with a custom Ardunio 3.3V 8Mhz internal clock. If you want to make your own, read HERE the instructions.

Here you can see the final result.