ANTI-THEFT BICYCLE SYSTEM
Group Name: Measurementors
Ayush Singh-ME23B022
Jay Adesara-ME23B002
Arnav Sarda-ME23B019
Arnav Gautam-ME23B018
Batta Karthik-ME23B024
Devdutt Sitapara-ME23B026
AIM
The anti-theft bicycle security system is a smart protection mechanism
designed to safeguard bicycles from theft. It uses motion sensors, GPS
tracking, a buzzer, and SMS alerts to detect unauthorized movement
and alert the owner in real time. The system operates in multiple
stages, from passive monitoring to the confirmation and sending
location updates. This ensures a reliable and automated security
system.
OBJECTIVES
➢Detect unauthorized movement and provide an initial warning
using a buzzer.
➢Send a theft alert to the owner via SMS if continuous movement is
detected.
➢Enable real-time GPS tracking and send location updates during
an ongoing theft attempt.
➢To unlock the bicycle one will receive OTP (one time password)
on the registered mobile number, by typing that in the keypad he
will be able to unlock the bicycle.
1
WORKING PRINCIPLE AND FUNCTIONALITY
1.GPS Data Collection
● A GPS sensor continuously captures location data (latitude and
longitude).
● This data is sent to the ESP32 microcontroller in real time.
2.Data Upload to Supabase
● The ESP32 uploads GPS coordinates along with timestamps to a
Supabase database.
● The ESPSupabase library is used for simplified communication
between ESP32 and Supabase.
● A WiFi dongle enables internet connectivity for the ESP32.
3.Data Retrieval from Supabase (Local System)
● A Python script uses the Supabase Python client to retrieve GPS
data from the database.
● The script filters records by the latest timestamp to get the most
recent location.
4.Flask API for Real-Time Access
● A Flask server is set up locally to serve the latest GPS data.
● The API responds with real-time location data in JSON format for
front-end consumption.
2
5.Visualization using JavaScript and Mapbox
● JavaScript fetches the live GPS data from the Flask API.
● The Mapbox API is used to plot the coordinates and update a
position marker dynamically on the map.
6.Web Interface (HTML + Mapbox)
● An HTML file integrates the JavaScript and Mapbox components.
● The webpage displays the live map with continuously updating
location markers.
3
7 .OTP-Based Cycle Locking Mechanism
● Each time the cycle is to be unlocked, a one-time password (OTP)
is generated.
● The OTP is sent to the owner's registered mobile number via
SMS.
● Friends wishing to access the cycle must request the OTP from
the owner.
8.SMS Alerts via Twilio
● Twilio's web service APIs are used to send SMS messages
containing OTPs.
● The ESP32-S3 microcontroller must remain connected to a Wi-Fi
network (provided by a Wi-Fi dongle) to use Twilio services.
9 .User Interaction through Keypad and OLED Display
● A 4x4 membrane keypad is used for OTP entry.
● A 1.3-inch OLED display (SPI interface) shows the cycle's status
(Locked/Unlocked) and provides user instructions.
10. Motion Detection with IMU Sensor
● An IMU sensor continuously monitors for unauthorized movement
when the cycle is locked.
● Upon detecting suspicious motion, an SMS alert is sent to the
owner.
4
● To avoid message spamming, a cooldown period of 2 minutes is
implemented between alerts.
11. Locking Mechanism Design
➢A combination of mechanical and electrical actuation is used for
securing the cycle:
○ A main servo motor drives a small gear (driving gear).
○ The small gear meshes with a larger gear that wraps around
the cycle to lock it.
○ A micro servo motor controls a mechanical hook to hold the
large gear securely in position, preventing any person from
manually opening the lock.
12. Custom 3D-Printed Components
● Lock setup components, including both gears, the hook, and the
lock casing, were custom-designed using Fusion 360.
● All parts were 3D printed to achieve precise fitting and
lightweight construction.
5
CONTROL BLOCK DIAGRAM
6
PRODUCT SPECIFICATIONS
1. ADXL335
2. NEO-6M GPS
3. OT5116M-Servo Motor
4. Lithium Polymer Battery
5. OLED Display Screen
6. AC1255-CLDZ
7. 12 keys Membrane Switch Keypad
8. LM2596S
9. 8MM DIP LED
7
1. ADXL335
Parameter Value Unit
Measurement Range ±3.6 g
Nonlinearity ±0.3 % of full scale
Sensitivity at Xout,Yout,Zout 300 mV/g
Sensitivity change due to ±0.01 %/℃
temperature
Operating voltage range 1.8 to 3.6 V
Supply current 350 µA
Turn-On time 1 ms
Operating temperature -40 to +85 ℃
range
2.NEO-6M GPS
Parameter Value Unit
Time-to-first-fix(cold start) 27 s
Sensitivity(cold start) -147 dBm
Horizontal position 2.5 m
accuracy(GPS)
Velocity accuracy 0.1 m/s
Dynamic operational limit ≤4 g
Altitude operational limit 50000 m
Velocity operational limit 500 m/s
8
3.OT5116M -servo motor
Parameter Value Unit
Operating voltage 4 to 8.4 V
Stall torque 15.5 kg-cm
Rated torque(@6V) 5 kg-cm
Stall current(@6V) 1.7 A
Operating temperature -15 to +70 ℃
Rotation direction(CCW) 280 °
4.Lithium Polymer Battery
Model No: Pro range 1000/ 2S- 30C
Parameter Value Unit
Nominal Voltage 7.4 V
Nominal Capacity 990 mAh
Weight 65 g
Maximum Continuous 30 A
Discharge Current
Open circuit voltage 8.45 ~ 8.60 - 4.15 ~ 4.22 V
(per cell)
Max Burst Discharge 60 C
9
5.OLED Display Screen
Parameter Value Unit
Resolution 128x64 PPI(pixels per inch)
Visual Angle >160 °
Input Voltage 3.3V ~ 6 V
Pixel Colour Blue -
Display Size 1.3 inch
Operating Temperatures -30 to 60 ℃
6.AC1255-CLDZ
Parameter Value Unit
Voltage Rating(V) 1 to 25 V
Diameter 12 mm
Operating Temperature -20 to 70 ℃
Height 5.5 mm
10
7.12 keys Membrane Switch Keypad
Parameter Value Unit
Operating Voltage 35 V
Operating Current 100 mA
Contact Resistance 500 Ohm
Insulation Resistance 100 MOhm
Ribbon Cable Length 90 mm
Dielectric Strength 250 VRms
8.LM2596S
Parameter Value Unit
Output Voltage 1.5 to 35 V
Output Current 2(max. Rated Current) A
Switching Frequency 150 KHz
Conversion Efficiency 92 %
Load Regulation ±0.5 %
Voltage Regulation(U) ±0.5 %
Operating Temperature -40 to +85 ℃
Dynamic Response Speed 5% 200uS m/s
11
9.8MM DIP LED ORANGE
Parameter Value Unit
No. of pins 2
Lens Appearance Transparent -
Head Shape Round -
LED size 8 mm
Shipping Weight 0.008 kg
12
MICROCONTROLLER SPECIFICATIONS - ESP32-S3
Features
Wi-Fi
• IEEE 802.11b/g/n-compliant
• Supports 20 MHz and 40 MHz bandwidth in 2.4 GHz band
• 1T1R mode with data rate up to 150 Mbps
• Wi-Fi Multimedia (WMM)
• TX/RX A-MPDU, TX/RX A-MSDU
• Immediate Block ACK
• Fragmentation and defragmentation
• Automatic Beacon monitoring (hardware TSF)
• Four virtual Wi-Fi interfaces
• Simultaneous support for Infrastructure BSS in Station, SoftAP, or Station +
SoftAP modes
Note that when ESP32-S3 scans in Station mode, the SoftAP channel will change along with the Station channel
• Antenna diversity
• 802.11mc FTM
Bluetooth
• Bluetooth LE: Bluetooth 5, Bluetooth mesh
• High power mode (20 dBm)
• Speed: 125 Kbps, 500 Kbps, 1 Mbps, 2 Mbps
• Advertising extensions
• Multiple advertisement sets
• Channel selection algorithm #2
• Internal co-existence mechanism between Wi-Fi and Bluetooth to share
the same antenna
CPU and Memory
• Xtensa® dual-core 32-bit LX7 microprocessor
• Clock speed: up to 240 MHz
• CoreMark® score:
– One core at 240 MHz: 613.86 CoreMark; 2.56 CoreMark/MHz
– Two cores at 240 MHz: 1181.60 CoreMark; 4.92 CoreMark/MHz
• Five-stage pipeline
• 128-bit data bus and dedicated SIMD instructions
13
• Single precision floating point unit (FPU)
• L1 cache
• ROM: 384 KB
• SRAM: 512 KB
• SRAM in RTC: 16 KB
• Supported SPI protocols: SPI, Dual SPI, Quad SPI, Octal SPI, QPI and OPI
interfaces that allow
connection to flash, external RAM, and other SPI devices
• Flash controller with cache is supported
• Flash in-Circuit Programming (ICP) is supported
Advanced Peripheral Interfaces
• 45 programmable GPIOs
– 4 strapping GPIOs
– 6 or 7 GPIOs needed for in-package flash or PSRAM
* ESP32-S3FN8、ESP32-S3R2、ESP32-S3R8、ESP32-S3R8V、ESP32-S3R16V: 6 GPIOs needed
* ESP32-S3FH4R2: 7 GPIOs needed
• Digital interfaces:
– Two SPI ports for communication with flash and RAM
– Two general-purpose SPI ports
– LCD interface (8-bit ~ 16-bit parallel RGB, I8080 and MOTO6800),
supporting conversion between
RGB565, YUV422, YUV420 and YUV411
– DVP 8-bit ~ 16-bit camera interface
– Three UARTs
– Two I2Cs
– Two I2Ss
– RMT (TX/RX)
– Pulse counter
– LED PWM controller, up to 8 channels
– Full-speed USB OTG
– USB Serial/JTAG controller
– Two Motor Control PWMs (MCPWM)
– SD/MMC host controller with 2 slots
– General DMA controller (GDMA), with 5 transmit channels and 5
receive channels
– TWAI® controller, compatible with ISO
11898-1 (CAN Specification 2.0)
14
– On-chip debug functionality via JTAG
• Analog interfaces:
– Two 12-bit SAR ADCs, up to 20 channels
– Temperature sensor
– 14 touch sensing IOs
• Timers:
– Four 54-bit general-purpose timers
– 52-bit system timer
– Three watchdog timers
15
CODE DETAILS
#include <Keypad.h>
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SH110X.h>
#include <math.h>
#include <WiFi.h>
#include <HTTPClient.h>
#include <base64.h>
#include <ESP32Servo.h>
#include <TinyGPS++.h>
#include <ESPSupabase.h>
#define OLED_MOSI 13
#define OLED_CLK 14
#define OLED_DC 11
#define OLED_CS 10
#define OLED_RST 12
#define RXD1 18 // connect to TX pin of GPS module
#define TXD1 17
#define S1 35 // Main Servo
#define S2 36 // Micro Servo
#define BUZZ 21
#define RLED 47
#define GLED 48
#define GPS_BAUD 115200
// Supabase credentials
const char* supabaseUrl = "https://xtjvcasaxiaunasbfhra.supabase.co";
const char* supabaseKey =
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Inh0anZjYXNheGlhd
W5hc2JmaHJhIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NDQ4OTQ0ODEsImV4cCI6MjA2MDQ3MDQ4MX0.KBW-GDDh
328Vu6J-pRJ8QhfWl6y5weL2fMaHM9aBIYM";
Supabase supabase;
String tableName = "gps";
TinyGPSPlus gps;
Servo servo1;
Servo servo2;
16
double lat;
double lon;
// Create an instance of the HardwareSerial class for Serial 1
HardwareSerial gpsSerial(1);
// Helper to pad numbers with zero
String padStart(int num) {
return num < 10 ? "0" + String(num) : String(num);
}
const int x_out = 1;
const int y_out = 2;
const int z_out = 9;
int x_adc_value, y_adc_value, z_adc_value;
double x_g_value, y_g_value, z_g_value;
unsigned long lastIMUAlertTime = 0; // Time in millis
const unsigned long imuCooldown = 5 * 60 * 1000; // 2 minutes in milliseconds
int otp;
String otpStr;
const char* ssid = "measurementors";
const char* password = "measurementors123";
// Twilio credentials
const char* accountSID = "AC8cd2aa89f5f5afd8e69210f45a8d1e54";
const char* authToken = "9d16c994e077facba9bb47dfc6f3b39e";
const char* messagingServiceSid = "MG19d19b2a55af75bcccc20651f40664d6";
const char* toPhoneNumber = "+919104387321";
char messageBody[30];
const char* warningMsg = "Aapki cycle ko hila gaya hai krupya savdhan rahe satark
rahe";
// Create the OLED display
Adafruit_SH1106G display = Adafruit_SH1106G(128, 64, OLED_MOSI, OLED_CLK, OLED_DC,
OLED_RST, OLED_CS);
const byte ROWS = 4;
const byte COLS = 3;
char keys[ROWS][COLS] = {
{'1','2','3'},
{'4','5','6'},
{'7','8','9'},
{'*','0','#'}
};
byte rowPins[ROWS] = {8, 16, 15, 7};
17
byte colPins[COLS] = {6, 5, 4};
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);
char keyBuffer[4];
int keyCount = 0;
void sendSMS(String msg) {
HTTPClient http;
String url = "https://api.twilio.com/2010-04-01/Accounts/" + String(accountSID) +
"/Messages.json";
http.begin(url);
String auth = base64::encode(String(accountSID) + ":" + String(authToken));
http.addHeader("Authorization", "Basic " + auth);
http.addHeader("Content-Type", "application/x-www-form-urlencoded");
String body = "To=" + String(toPhoneNumber) +
"&MessagingServiceSid=" + String(messagingServiceSid) +
"&Body=" + msg;
int httpResponseCode = http.POST(body);
Serial.print("HTTP Response code: ");
Serial.println(httpResponseCode);
if (httpResponseCode > 0) {
String response = http.getString();
Serial.println(response);
}
http.end();
}
void setup() {
Serial.begin(115200);
Serial.println("Start");
pinMode(BUZZ, OUTPUT);
pinMode(RLED, OUTPUT);
pinMode(GLED, OUTPUT);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting to WiFi...");
}
Serial.println("Connected!");
gpsSerial.begin(GPS_BAUD, SERIAL_8N1, RXD1, TXD1);
supabase.begin(supabaseUrl, supabaseKey);
18
servo1.setPeriodHertz(50);
servo2.setPeriodHertz(50);
servo1.attach(S1, 500, 2400);
servo2.attach(S2, 500, 2400);
// Start OLED
display.begin(0, true); // we dont use the i2c address but we will reset!
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SH110X_WHITE);
display.setCursor(0, 32);
display.println("Press * to generate OTP");
display.display();
xTaskCreatePinnedToCore(gps_control,"GPS",4096,NULL,3,NULL,0);
xTaskCreatePinnedToCore(keypad_control,"Keypad",6144,NULL,3,NULL,1);
}
void keypad_control(void *pvParameters) {
while (1) {
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SH110X_WHITE);
display.setCursor(0, 32);
display.println("Press * to generate OTP");
display.display();
digitalWrite(GLED, LOW);
digitalWrite(RLED, HIGH);
char key = keypad.getKey();
x_adc_value = analogRead(x_out); /* Digital value of voltage on x_out pin */
y_adc_value = analogRead(y_out); /* Digital value of voltage on y_out pin */
z_adc_value = analogRead(z_out); /* Digital value of voltage on z_out pin */
x_g_value = ( ( ( (double)(x_adc_value * 3.3)/4096) - 1.65 ) / 0.330 ); /*
Acceleration in x-direction in g units */
y_g_value = ( ( ( (double)(y_adc_value * 3.3)/4096) - 1.65 ) / 0.330 ); /*
Acceleration in y-direction in g units */
z_g_value = ( ( ( (double)(z_adc_value * 3.3)/4096) - 1.80 ) / 0.330 ); /*
Acceleration in z-direction in g units */
if ((fabs(x_g_value) + fabs(y_g_value) + fabs(z_g_value) > 10) && (millis() -
lastIMUAlertTime > imuCooldown)) {
sendSMS(warningMsg);
digitalWrite(BUZZ, HIGH);
vTaskDelay(2000/portTICK_PERIOD_MS);
19
digitalWrite(BUZZ, LOW);
lastIMUAlertTime = millis(); // Update the timestamp of last alert
}
if (key == '*'){
otp = random(1000,10000);
otpStr = String(otp);
sendSMS("Your OTP is: " + otpStr);
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SH110X_WHITE);
display.setCursor(0, 32);
display.println("Enter OTP : ");
display.display();
for(;;){
char enteredKey = keypad.getKey();
if (enteredKey != NO_KEY) {
Serial.print("Key Pressed: ");
Serial.println(enteredKey);
display.setTextSize(1);
display.setTextColor(SH110X_WHITE);
display.setCursor(70 + 7*keyCount, 32);
display.println(enteredKey);
display.display();
//vTaskDelay(200/portTICK_PERIOD_MS);
if (keyCount < 4) {
keyBuffer[keyCount] = enteredKey;
keyCount++;
}
if (keyCount == 4) {
Serial.print("Sequence: ");
for (int i = 0; i < 4; i++) {
Serial.print(keyBuffer[i]);
}
Serial.println();
if (keyBuffer[0] == otpStr[0] && keyBuffer[1] == otpStr[1] && keyBuffer[2] ==
otpStr[2] && keyBuffer[3] == otpStr[3]) {
vTaskDelay(1000/portTICK_PERIOD_MS);
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SH110X_WHITE);
display.setCursor(0, 32);
20
display.println("Access Granted");
display.display();
vTaskDelay(2000/portTICK_PERIOD_MS);
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SH110X_WHITE);
display.setCursor(0, 32);
display.println("Cycle Unlocked, Press '#' to lock cycle");
display.display();
vTaskDelay(100/portTICK_PERIOD_MS);
servo2.write(90);
vTaskDelay(2000/portTICK_PERIOD_MS);
servo1.write(90);
vTaskDelay(2000/portTICK_PERIOD_MS);
digitalWrite(GLED, HIGH);
digitalWrite(RLED, LOW);
for(;;){
char keySec = keypad.getKey();
if (keySec == '#'){
servo1.write(0);
vTaskDelay(2000/portTICK_PERIOD_MS);
servo2.write(0);
vTaskDelay(2000/portTICK_PERIOD_MS);
break;
}
vTaskDelay(10 / portTICK_PERIOD_MS);
}
break;
}
else{
vTaskDelay(1000/portTICK_PERIOD_MS);
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SH110X_WHITE);
display.setCursor(0, 32);
display.println("Permission Denied");
display.display();
vTaskDelay(2000 / portTICK_PERIOD_MS);
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SH110X_WHITE);
display.setCursor(0, 32);
display.println("Enter OTP : ");
display.display();
}
// Reset buffer
keyCount = 0;
for (int i = 0; i < 4; i++) {
21
keyBuffer[i] = '0';
}
}
}
vTaskDelay(10 / portTICK_PERIOD_MS); // Prevent WDT reset
}
}
vTaskDelay(10 / portTICK_PERIOD_MS); // Prevent CPU hogging
}
}
void gps_control(void *pvParameters){
while (1){
unsigned long start = millis();
while (millis() - start < 1000) {
while (gpsSerial.available() > 0) {
gps.encode(gpsSerial.read());
}
if (gps.location.isUpdated()) {
Serial.println("------ GPS Update ------");
Serial.print("LAT: ");
Serial.println(gps.location.lat(), 6);
Serial.print("LONG: ");
Serial.println(gps.location.lng(), 6);
Serial.print("SPEED (km/h): ");
Serial.println(gps.speed.kmph());
Serial.print("ALT (m): ");
Serial.println(gps.altitude.meters());
Serial.print("HDOP: ");
Serial.println(gps.hdop.value() / 100.0);
Serial.print("Satellites: ");
Serial.println(gps.satellites.value());
Serial.print("Time UTC: ");
Serial.println(String(gps.date.year()) + "-" + String(gps.date.month()) + "-" +
String(gps.date.day()) + " " +
String(gps.time.hour()) + ":" + String(gps.time.minute()) + ":" +
String(gps.time.second()));
Serial.println("------------------------");
}
}
if (gps.location.isValid() && gps.date.isValid() && gps.time.isValid()) {
lat = gps.location.lat();
lon = gps.location.lng();
// Format timestamp in ISO 8601 (UTC)
String timestamp = String(gps.date.year()) + "-" +
22
padStart(gps.date.month()) + "-" +
padStart(gps.date.day()) + "T" +
padStart(gps.time.hour()) + ":" +
padStart(gps.time.minute()) + ":" +
padStart(gps.time.second()) + "Z";
// Create JSON payload
String jsonData = "{";
jsonData += "\"timestamp\": \"" + timestamp + "\", ";
jsonData += "\"latitude\": " + String(lat, 6) + ", ";
jsonData += "\"longitude\": " + String(lon, 6);
jsonData += "}";
// Send to Supabase
int response = supabase.insert(tableName, jsonData, false);
if (response == 201) {
Serial.println("Data inserted successfully!");
} else {
Serial.print("Failed to insert data. HTTP response: ");
Serial.println(response);
}
} else {
Serial.println("Waiting for valid GPS fix and time...");
}
vTaskDelay(1000/portTICK_PERIOD_MS);
}
}
void loop() {}
23
DATA ACQUISITION SYSTEM BLOCK DIAGRAM
24
CONCLUSION
25
INDIVIDUAL CONTRIBUTION
ROLL NO NAME PERCENTAGE SIGNATURE
CONTRIBUTION
ME23B002 Jay Adesera
ME23B018 Arnav Gautam
ME23B019 Arnav Sarda
ME23B022 Ayush Singh
ME23B024 B Karthik
ME23B026 Devdutt
26