/* ===================================================================
Line Following Robot - STM32F103C8T6 (Blue Pill)
WOKWI SIMULATION VERSION - Arduino framework (STM32duino core)
===================================================================
WHY THIS VERSION DIFFERS FROM main.c IN THE PROJECT REPORT:
Wokwi's part library does not currently include an IR line-sensor
module, a DC motor, or an L298N driver chip. To still simulate the
real circuit's LOGIC and PIN BEHAVIOUR (which is what actually
needs to be demonstrated/graded), this sketch uses the standard
substitution recommended in the project report itself for Proteus:
- 3 SLIDE SWITCHES replace the 3 IR sensors.
Flip toward 3V3 -> HIGH -> "white surface" under that sensor
Flip toward GND -> LOW -> "robot is on the black line"
(this is exactly the sensor behaviour described in the report:
"Sensors output HIGH on white surface, LOW on black line")
- 6 LEDs (+ resistors) replace the L298N + two DC motors:
LED_IN1 / LED_IN2 -> Left motor direction (from IN1/IN2)
LED_IN3 / LED_IN4 -> Right motor direction (from IN3/IN4)
LED_ENA / LED_ENB -> Left/Right motor SPEED, shown as LED
brightness via PWM (from ENA/ENB)
When LED_IN1 is ON and LED_IN2 is OFF, the left motor would be
spinning forward on the real robot (and vice-versa).
- HC-SR04 is a REAL Wokwi part, so obstacle detection is
simulated exactly as it would be on the physical robot. You
can drag its on-screen slider while the simulation is running
to bring a virtual "obstacle" closer and watch the robot stop.
- The onboard PC13 LED + a buzzer on PB6 reproduce the "status
indicator (LED/buzzer)" mentioned in the abstract.
PIN MAPPING (identical to the wiring guide / main.c in the report):
IR Sensor Left -> PA0 (Input) [slide switch sw_left]
IR Sensor Middle -> PA1 (Input) [slide switch sw_mid]
IR Sensor Right -> PA2 (Input) [slide switch sw_right]
L298N IN1 -> PB0 (Left motor direction) [LED]
L298N IN2 -> PB1 (Left motor direction) [LED]
L298N IN3 -> PB2 (Right motor direction) [LED]
L298N IN4 -> PB3 (Right motor direction) [LED]
L298N ENA (PWM) -> PA6 (Left motor speed) [LED brightness]
L298N ENB (PWM) -> PA7 (Right motor speed) [LED brightness]
HC-SR04 TRIG -> PB4
HC-SR04 ECHO -> PB5
Buzzer -> PB6
Onboard LED -> PC13 (active LOW, no wiring needed)
Logic: Sensors read HIGH (1) on white surface, LOW (0) on the
black line - identical to the physical IR sensor behaviour used
in the original main.c.
=================================================================== */
#define IR_LEFT PA0
#define IR_MID PA1
#define IR_RIGHT PA2
#define IN1 PB0 // Left motor direction
#define IN2 PB1 // Left motor direction
#define IN3 PB2 // Right motor direction
#define IN4 PB3 // Right motor direction
#define ENA PA6 // Left motor speed (PWM, TIM3_CH1)
#define ENB PA7 // Right motor speed (PWM, TIM3_CH2)
#define TRIG_PIN PB4
#define ECHO_PIN PB5
#define BUZZER_PIN PB6
#define STATUS_LED PC13 // onboard LED, active LOW
#define BASE_SPEED 200 // PWM duty (0-255) for normal forward speed
#define TURN_SPEED 110 // PWM duty during a turn correction
#define OBSTACLE_CM 15 // stop the robot if something is this close
/* ---- Motor control helper functions (same behaviour as main.c) ---- */
void Motor_Forward(int speedL, int speedR) {
digitalWrite(IN1, HIGH);
digitalWrite(IN2, LOW);
digitalWrite(IN3, HIGH);
digitalWrite(IN4, LOW);
analogWrite(ENA, speedL);
analogWrite(ENB, speedR);
}
void Motor_Stop(void) {
digitalWrite(IN1, LOW);
digitalWrite(IN2, LOW);
digitalWrite(IN3, LOW);
digitalWrite(IN4, LOW);
analogWrite(ENA, 0);
analogWrite(ENB, 0);
}
/* ---- HC-SR04 distance read ---- */
long readDistanceCM(void) {
digitalWrite(TRIG_PIN, LOW);
delayMicroseconds(2);
digitalWrite(TRIG_PIN, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG_PIN, LOW);
long duration = pulseIn(ECHO_PIN, HIGH, 30000UL); // 30 ms timeout
if (duration == 0) return 999; // no echo -> treat path as clear
return duration / 58; // convert microseconds -> cm
}
void setup() {
Serial.begin(115200);
Serial.println("STM32 Line Following Robot - Wokwi Simulation");
Serial.println("Flip the 3 switches to simulate the IR sensors.");
pinMode(IR_LEFT, INPUT);
pinMode(IR_MID, INPUT);
pinMode(IR_RIGHT, INPUT);
pinMode(IN1, OUTPUT);
pinMode(IN2, OUTPUT);
pinMode(IN3, OUTPUT);
pinMode(IN4, OUTPUT);
pinMode(ENA, OUTPUT);
pinMode(ENB, OUTPUT);
pinMode(TRIG_PIN, OUTPUT);
pinMode(ECHO_PIN, INPUT);
pinMode(BUZZER_PIN, OUTPUT);
pinMode(STATUS_LED, OUTPUT);
digitalWrite(STATUS_LED, HIGH); // OFF (onboard LED is active-LOW)
Motor_Stop();
}
void loop() {
long distance = readDistanceCM();
if (distance < OBSTACLE_CM) {
/* ---- Obstacle detected: halt regardless of line sensors ---- */
Motor_Stop();
digitalWrite(STATUS_LED, LOW); // onboard LED ON
tone(BUZZER_PIN, 1000); // buzzer ON
Serial.print("Obstacle at ");
Serial.print(distance);
Serial.println(" cm -> motors stopped");
} else {
digitalWrite(STATUS_LED, HIGH); // onboard LED OFF
noTone(BUZZER_PIN); // buzzer OFF
uint8_t left = digitalRead(IR_LEFT);
uint8_t middle = digitalRead(IR_MID);
uint8_t right = digitalRead(IR_RIGHT);
if (middle == LOW && left == HIGH && right == HIGH) {
/* Line under centre sensor -> go straight */
Motor_Forward(BASE_SPEED, BASE_SPEED);
Serial.println("Line centred -> straight");
}
else if (left == LOW && middle == HIGH && right == HIGH) {
/* Line drifted left -> turn left */
Motor_Forward(TURN_SPEED, BASE_SPEED);
Serial.println("Line drifted left -> turning left");
}
else if (right == LOW && middle == HIGH && left == HIGH) {
/* Line drifted right -> turn right */
Motor_Forward(BASE_SPEED, TURN_SPEED);
Serial.println("Line drifted right -> turning right");
}
else if (left == LOW && middle == LOW && right == HIGH) {
/* Sharp left turn */
Motor_Forward(0, BASE_SPEED);
Serial.println("Sharp left turn");
}
else if (right == LOW && middle == LOW && left == HIGH) {
/* Sharp right turn */
Motor_Forward(BASE_SPEED, 0);
Serial.println("Sharp right turn");
}
else if (left == HIGH && middle == HIGH && right == HIGH) {
/* Line lost (all white) -> stop */
Motor_Stop();
Serial.println("Line lost (all white) -> stop");
}
else {
/* All sensors on black (junction / end of track) -> stop */
Motor_Stop();
Serial.println("Junction / end of track -> stop");
}
}
delay(150); // loop delay, slowed down for readability in simulation
}
Loading
stm32-bluepill
stm32-bluepill
IR L / M / R (line sim)
L298N IN1-IN4 (motor direction)
ENA/ENB PWM speed (brightness)