If-then logic in robotics programming creates autonomous decision-making by evaluating sensor conditions and executing different actions based on those evaluations—if a distance sensor detects an obstacle within 20 centimeters, then turn right; if a line sensor sees black, then adjust steering. This conditional logic transforms robots from machines that blindly follow predetermined sequences into intelligent systems that adapt their behavior based on environmental conditions they encounter.
Your robot sits motionless on the floor, sensors reading the environment perfectly, motors functioning flawlessly, code executing without errors—yet it does nothing useful. It reads that an obstacle is 10 centimeters ahead but continues driving forward into it. It detects the edge of a line but doesn’t adjust steering to stay on track. It senses that battery voltage has dropped dangerously low but keeps running until shutdown. The hardware works perfectly, the sensors provide accurate data, but your robot lacks the one crucial capability that separates autonomous machines from preprogrammed automata: the ability to make decisions based on what it perceives.
Decision-making through if-then logic is what transforms sensor readings into intelligent actions. Without conditional logic, your robot can only execute fixed sequences: move forward for three seconds, turn right for one second, repeat forever. With if-then statements, your robot becomes adaptive: IF an obstacle appears ahead, THEN turn away from it; IF the line moves left, THEN steer right; IF battery is low, THEN return to charging station. Every autonomous behavior—from the simplest obstacle avoidance to the most sophisticated navigation—fundamentally relies on conditional logic that connects perception to action.
This article teaches you how to implement effective decision-making in robots using if-then logic, from basic single conditions through complex multi-sensor decision trees. You’ll learn how to structure conditions clearly, combine multiple tests with boolean operators, avoid common logic errors, and create sophisticated behaviors that respond intelligently to complex situations. Whether you’re programming your first line-following robot or designing advanced autonomous systems, mastering conditional logic represents the essential skill that brings robot intelligence to life.
Understanding Conditional Logic: The Foundation of Decisions
Before writing complex decision-making code, understanding how conditional statements work at a fundamental level helps you think clearly about robot behavior.
The Basic If Statement
The simplest decision structure evaluates one condition and executes code only if that condition is true:
if (condition) {
// Code here executes only if condition is true
}
// Code here always executes (after the if block)Real robotics example:
int distance = measureDistance();
if (distance < 20) {
// Obstacle detected within 20cm
stopMotors();
Serial.println("Obstacle! Stopping.");
}
// Continue with rest of programThe condition distance < 20 evaluates to either true or false. If true, the code block executes (motors stop). If false, the code block is skipped entirely.
If-Else: Choosing Between Two Actions
When you need different actions for true and false conditions, use if-else:
if (condition) {
// Executes if condition is true
} else {
// Executes if condition is false
}Real robotics example:
int lightLevel = analogRead(lightSensorPin);
if (lightLevel > 500) {
// Bright environment
setMotorSpeed(200); // Move fast
Serial.println("Bright - full speed");
} else {
// Dark environment
setMotorSpeed(100); // Move slowly
Serial.println("Dark - reduced speed");
}Exactly one of the two code blocks always executes—never both, never neither.
If-Else-If: Multiple Exclusive Conditions
For more than two options, chain multiple conditions with else-if:
if (condition1) {
// Executes if condition1 is true
} else if (condition2) {
// Executes if condition1 is false AND condition2 is true
} else if (condition3) {
// Executes if condition1 and condition2 are false AND condition3 is true
} else {
// Executes if all conditions are false
}Real robotics example:
float distance = measureDistance();
if (distance < 15) {
// Very close - back up
setMotors(-150, -150);
Serial.println("TOO CLOSE - Backing up");
} else if (distance < 30) {
// Close - turn
setMotors(100, 200);
Serial.println("Close - Turning");
} else if (distance < 60) {
// Moderate distance - slow approach
setMotors(120, 120);
Serial.println("Approaching carefully");
} else {
// Far away - full speed ahead
setMotors(200, 200);
Serial.println("Path clear - full speed");
}Only one block executes—the first condition that evaluates to true. Remaining conditions are not even checked once a true condition is found.
Nested If Statements: Decisions Within Decisions
You can place if statements inside other if statements for complex logic:
if (outerCondition) {
// Executes if outerCondition is true
if (innerCondition) {
// Executes if BOTH outerCondition AND innerCondition are true
}
}Real robotics example:
bool obstacleAhead = (frontDistance < 30);
bool pathClearLeft = (leftDistance > 50);
bool pathClearRight = (rightDistance > 50);
if (obstacleAhead) {
// Obstacle detected - need to turn
Serial.println("Obstacle ahead!");
if (pathClearRight) {
// Right is clear - turn right
turnRight();
Serial.println("Turning RIGHT");
} else if (pathClearLeft) {
// Left is clear - turn left
turnLeft();
Serial.println("Turning LEFT");
} else {
// Both sides blocked - back up
backUp();
Serial.println("BLOCKED - Backing up");
}
} else {
// No obstacle - continue forward
moveForward();
}Nested if statements create decision trees where each branch leads to progressively specific actions.
Comparison Operators: Building Conditions
Conditions in if statements use comparison operators to test relationships between values.
Basic Comparison Operators
Equal to: ==
if (sensorValue == 512) {
// Executes if sensorValue is exactly 512
}Warning: Use == (double equals) for comparison, not = (single equals for assignment). This is an extremely common error:
if (x = 5) { } // WRONG - assigns 5 to x, always true!
if (x == 5) { } // CORRECT - compares x to 5Not equal to: !=
if (motorState != STOPPED) {
// Executes if motorState is anything except STOPPED
}Greater than: >
if (temperature > 25) {
// Executes if temperature exceeds 25
}Less than: <
if (distance < 20) {
// Executes if distance is less than 20
}Greater than or equal: >=
if (batteryVoltage >= 11.0) {
// Executes if voltage is 11.0 or higher
}Less than or equal: <=
if (speed <= maxSpeed) {
// Executes if speed is maxSpeed or lower
}Practical Comparison Examples
Range testing:
// Check if value is within acceptable range
if (sensorValue >= 300 && sensorValue <= 700) {
Serial.println("Value in normal range");
}Threshold with hysteresis:
if (temperature > 30) {
fanOn = true;
} else if (temperature < 25) {
fanOn = false;
}
// Between 25-30: fan stays in current stateMultiple sensor agreement:
if (leftSensor > 500 && rightSensor > 500) {
// Both sensors agree - high confidence
Serial.println("Line detected by both sensors");
}Boolean Operators: Combining Multiple Conditions
Complex robot behaviors require testing multiple conditions simultaneously. Boolean operators combine simple conditions into compound conditions.
AND Operator: &&
Both conditions must be true for the overall expression to be true:
if (condition1 && condition2) {
// Executes only if BOTH conditions are true
}Truth table:
true && true→truetrue && false→falsefalse && true→falsefalse && false→false
Robotics example:
float frontDist = measureFrontDistance();
int lightLevel = analogRead(lightSensor);
// Only proceed if path is clear AND there's enough light
if (frontDist > 50 && lightLevel > 300) {
moveForward();
Serial.println("Conditions good - moving");
} else {
stopMotors();
Serial.println("Waiting for better conditions");
}Multiple AND conditions:
if (batteryOK && noObstacle && lineDetected && buttonPressed) {
// All four conditions must be true
startMission();
}OR Operator: ||
At least one condition must be true for the overall expression to be true:
if (condition1 || condition2) {
// Executes if EITHER condition is true (or both)
}Truth table:
true || true→truetrue || false→truefalse || true→truefalse || false→false
Robotics example:
// Stop if obstacle ahead OR battery low
if (frontDistance < 15 || batteryVoltage < 10.5) {
emergencyStop();
Serial.println("Emergency stop triggered!");
if (frontDistance < 15) {
Serial.println("Reason: Obstacle");
}
if (batteryVoltage < 10.5) {
Serial.println("Reason: Low battery");
}
}Multiple OR conditions:
// Turn if obstacle detected by any sensor
if (frontSensor || leftSensor || rightSensor || rearSensor) {
executeTurnSequence();
}NOT Operator: !
Inverts a boolean value (true becomes false, false becomes true):
if (!condition) {
// Executes if condition is FALSE
}Truth table:
!true→false!false→true
Robotics example:
bool lineDetected = checkLineSensor();
if (!lineDetected) {
// Line NOT detected - robot wandered off
Serial.println("LINE LOST - Searching...");
searchForLine();
}Double negative (avoid for clarity):
// Confusing
if (!(!motorRunning)) { }
// Clear equivalent
if (motorRunning) { }Combining Boolean Operators
You can combine AND, OR, and NOT for complex logic:
// Complex condition
if ((distance > 30 && speed < 100) || emergencyStop) {
// Executes if:
// - Distance is safe AND speed is moderate, OR
// - Emergency stop is activated
}Use parentheses for clarity:
// Ambiguous - what executes first?
if (a && b || c && d) { }
// Clear - parentheses show intent
if ((a && b) || (c && d)) { }Robotics example – navigation decision:
bool pathClearAhead = (frontDistance > 40);
bool obstacleLeft = (leftDistance < 20);
bool obstacleRight = (rightDistance < 20);
bool lowBattery = (batteryVoltage < 11.0);
// Complex navigation logic
if (pathClearAhead && !lowBattery) {
// Path clear and battery OK - continue forward
moveForward();
} else if (!pathClearAhead && !obstacleRight && !lowBattery) {
// Obstacle ahead, right is clear, battery OK - turn right
turnRight();
} else if (!pathClearAhead && !obstacleLeft && !lowBattery) {
// Obstacle ahead, left is clear, battery OK - turn left
turnLeft();
} else {
// Complicated situation or low battery - stop and assess
stopAndAssess();
}Practical Decision-Making Patterns
Certain decision-making patterns appear repeatedly in robotics. Understanding these patterns accelerates development.
Pattern 1: Threshold Detection
Simple comparison to determine if a value crosses a meaningful boundary:
// Single threshold
const int obstacleThreshold = 300;
int distanceReading = analogRead(distanceSensor);
if (distanceReading > obstacleThreshold) {
Serial.println("Obstacle detected!");
avoidObstacle();
}Multiple thresholds for graduated response:
const int nearThreshold = 200;
const int mediumThreshold = 400;
const int farThreshold = 600;
int distance = analogRead(distanceSensor);
if (distance < nearThreshold) {
Serial.println("DANGER - Very close");
setSpeed(0); // Stop
} else if (distance < mediumThreshold) {
Serial.println("Warning - Obstacle nearby");
setSpeed(100); // Slow
} else if (distance < farThreshold) {
Serial.println("Caution - Object detected");
setSpeed(150); // Medium
} else {
Serial.println("All clear");
setSpeed(200); // Full speed
}Pattern 2: Range Checking
Determining if a value falls within acceptable bounds:
// Check if sensor reading is valid/reasonable
int reading = analogRead(sensorPin);
const int minValid = 50;
const int maxValid = 950;
if (reading >= minValid && reading <= maxValid) {
// Reading is within expected range - use it
processValidReading(reading);
} else {
// Reading is out of range - likely sensor error
Serial.println("Sensor reading out of range - ignoring");
useDefaultValue();
}Inverted range check (outside bounds):
// Detect anomalous values
if (temperature < -10 || temperature > 50) {
Serial.println("Temperature sensor malfunction!");
triggerError();
}Pattern 3: State-Based Decisions
Different actions based on current operational state:
enum RobotState {
SEARCHING,
APPROACHING,
AVOIDING,
STOPPED
};
RobotState currentState = SEARCHING;
void loop() {
float distance = measureDistance();
if (currentState == SEARCHING) {
// Looking for target
if (distance < 100) {
currentState = APPROACHING;
Serial.println("Target found - approaching");
}
scanArea();
} else if (currentState == APPROACHING) {
// Moving toward target
if (distance < 20) {
currentState = STOPPED;
Serial.println("Reached target");
} else if (distance > 150) {
currentState = SEARCHING;
Serial.println("Lost target - searching");
}
moveTowardTarget();
} else if (currentState == AVOIDING) {
// Avoiding obstacle
if (obstacleCleared()) {
currentState = SEARCHING;
Serial.println("Obstacle cleared");
}
executeAvoidance();
} else if (currentState == STOPPED) {
// At target
stopMotors();
}
// Check for obstacles in any state
if (distance < 10 && currentState != STOPPED) {
currentState = AVOIDING;
Serial.println("OBSTACLE - Avoiding");
}
}Pattern 4: Priority-Based Decisions
Handling multiple conditions with different importance levels:
void makeDecision() {
// Check conditions in priority order (most important first)
// Priority 1: Emergency conditions
if (batteryVoltage < 10.0) {
emergencyShutdown();
return; // Exit immediately
}
if (frontDistance < 10) {
emergencyStop();
return;
}
// Priority 2: Warning conditions
if (batteryVoltage < 11.0) {
returnToBase();
return;
}
if (frontDistance < 25) {
avoidObstacle();
return;
}
// Priority 3: Normal operations
if (lineDetected) {
followLine();
return;
}
// Default: Nothing special detected
searchPattern();
}Using return exits the function immediately after executing high-priority actions, preventing lower-priority code from running.
Pattern 5: Debounced Digital Input
Preventing false triggers from noisy digital sensors:
const int buttonPin = 2;
const int debounceDelay = 50; // milliseconds
int lastButtonState = LOW;
int buttonState;
unsigned long lastDebounceTime = 0;
void loop() {
int reading = digitalRead(buttonPin);
// If state changed, reset debounce timer
if (reading != lastButtonState) {
lastDebounceTime = millis();
}
// If enough time has passed, accept new state
if ((millis() - lastDebounceTime) > debounceDelay) {
if (reading != buttonState) {
buttonState = reading;
// Only act on button press (LOW to HIGH transition)
if (buttonState == HIGH) {
Serial.println("Button pressed (debounced)");
toggleRobotState();
}
}
}
lastButtonState = reading;
}Pattern 6: Sensor Fusion (Multi-Sensor Agreement)
Making decisions based on multiple sensor inputs:
// Read all sensors
int frontLeft = analogRead(A0);
int frontCenter = analogRead(A1);
int frontRight = analogRead(A2);
const int obstacleThreshold = 400;
// Count how many sensors detect obstacle
int obstacleCount = 0;
if (frontLeft > obstacleThreshold) obstacleCount++;
if (frontCenter > obstacleThreshold) obstacleCount++;
if (frontRight > obstacleThreshold) obstacleCount++;
// Decision based on consensus
if (obstacleCount >= 2) {
// High confidence - multiple sensors agree
Serial.println("Obstacle confirmed by multiple sensors");
stopAndTurn();
} else if (obstacleCount == 1) {
// Low confidence - only one sensor
Serial.println("Possible obstacle - slowing");
reduceSpeed();
} else {
// No obstacle
Serial.println("Path clear");
fullSpeed();
}Advanced Decision Structures
Beyond basic if-then logic, several advanced structures enable more sophisticated decision-making.
Switch-Case Statements
For many discrete conditions based on a single variable, switch-case is cleaner than multiple if-else-if:
enum Direction {
NORTH,
SOUTH,
EAST,
WEST
};
Direction heading = NORTH;
switch (heading) {
case NORTH:
Serial.println("Heading North");
motorLeft = 200;
motorRight = 200;
break;
case SOUTH:
Serial.println("Heading South");
motorLeft = -200;
motorRight = -200;
break;
case EAST:
Serial.println("Heading East");
motorLeft = 200;
motorRight = -200;
break;
case WEST:
Serial.println("Heading West");
motorLeft = -200;
motorRight = 200;
break;
default:
Serial.println("Unknown heading!");
stopMotors();
break;
}Important: Always include break statements or execution will “fall through” to the next case.
Ternary Operator (Conditional Expression)
For simple if-else assignments, the ternary operator is more concise:
// Traditional if-else
int speed;
if (distance > 50) {
speed = 200;
} else {
speed = 100;
}
// Ternary operator (same result)
int speed = (distance > 50) ? 200 : 100;Syntax: condition ? valueIfTrue : valueIfFalse
Robotics example:
// Set LED based on obstacle detection
digitalWrite(ledPin, (obstacleDetected ? HIGH : LOW));
// Choose motor direction based on line position
int correction = (linePosition > 0) ? 50 : -50;Use ternary operators for simple cases; stick with if-else for complex logic requiring multiple statements.
Lookup Tables
For complex mappings between input values and output actions, lookup tables can be more efficient than long if-else chains:
// Map distance ranges to motor speeds
const int numRanges = 5;
const int distanceThresholds[numRanges] = {10, 20, 40, 70, 100};
const int motorSpeeds[numRanges] = {0, 80, 120, 160, 200};
int getMotorSpeed(int distance) {
for (int i = 0; i < numRanges; i++) {
if (distance < distanceThresholds[i]) {
return motorSpeeds[i];
}
}
return motorSpeeds[numRanges - 1]; // Max speed if beyond all thresholds
}
void loop() {
int distance = measureDistance();
int speed = getMotorSpeed(distance);
setMotors(speed, speed);
}Complete Decision-Making Examples
Let’s examine complete, working examples demonstrating decision-making in real robotics applications.
Example 1: Obstacle-Avoiding Robot
Simple autonomous navigation using if-then logic:
// Sensor pins
const int frontSensorPin = A0;
const int leftSensorPin = A1;
const int rightSensorPin = A2;
// Motor pins
const int motorLeftPin = 9;
const int motorRightPin = 10;
// Thresholds and speeds
const int obstacleThreshold = 400;
const int turnSpeed = 150;
const int forwardSpeed = 180;
void setup() {
pinMode(motorLeftPin, OUTPUT);
pinMode(motorRightPin, OUTPUT);
Serial.begin(9600);
}
void loop() {
// Read all sensors
int frontDistance = analogRead(frontSensorPin);
int leftDistance = analogRead(leftSensorPin);
int rightDistance = analogRead(rightSensorPin);
// Decision tree
if (frontDistance > obstacleThreshold) {
// Obstacle directly ahead
Serial.println("Obstacle ahead!");
if (rightDistance < obstacleThreshold && leftDistance < obstacleThreshold) {
// Both sides clear - choose based on which is more clear
if (rightDistance < leftDistance) {
Serial.println("Turning LEFT (more clear)");
turnLeft();
} else {
Serial.println("Turning RIGHT (more clear)");
turnRight();
}
} else if (rightDistance < obstacleThreshold) {
// Right is clear
Serial.println("Turning RIGHT");
turnRight();
} else if (leftDistance < obstacleThreshold) {
// Left is clear
Serial.println("Turning LEFT");
turnLeft();
} else {
// Both sides blocked - back up
Serial.println("BLOCKED - Backing up");
backUp();
}
} else {
// Path clear ahead
Serial.println("Moving forward");
moveForward();
}
delay(100);
}
void moveForward() {
analogWrite(motorLeftPin, forwardSpeed);
analogWrite(motorRightPin, forwardSpeed);
}
void turnLeft() {
analogWrite(motorLeftPin, 0);
analogWrite(motorRightPin, turnSpeed);
delay(500); // Turn for 500ms
}
void turnRight() {
analogWrite(motorLeftPin, turnSpeed);
analogWrite(motorRightPin, 0);
delay(500);
}
void backUp() {
analogWrite(motorLeftPin, -turnSpeed);
analogWrite(motorRightPin, -turnSpeed);
delay(300); // Back up for 300ms
}Example 2: Line-Following Robot with Proportional Steering
Using sensor values to make graduated steering decisions:
// Sensor array pins (5 sensors across line)
const int sensorPins[5] = {A0, A1, A2, A3, A4};
const int numSensors = 5;
// Motor pins
const int motorLeftPin = 9;
const int motorRightPin = 10;
// Parameters
const int baseSpeed = 150;
const int lineThreshold = 500;
void loop() {
// Read all line sensors
int sensorValues[numSensors];
for (int i = 0; i < numSensors; i++) {
sensorValues[i] = analogRead(sensorPins[i]);
}
// Calculate line position (-2 = far left, 0 = center, +2 = far right)
float linePosition = calculateLinePosition(sensorValues);
// Decision: Adjust motors based on line position
if (linePosition == -999) {
// Line not detected - stop
Serial.println("LINE LOST!");
analogWrite(motorLeftPin, 0);
analogWrite(motorRightPin, 0);
} else {
// Line detected - steer toward it
int steeringCorrection = linePosition * 30; // Multiply position by gain
int leftSpeed = baseSpeed + steeringCorrection;
int rightSpeed = baseSpeed - steeringCorrection;
// Constrain to valid range
leftSpeed = constrain(leftSpeed, -255, 255);
rightSpeed = constrain(rightSpeed, -255, 255);
analogWrite(motorLeftPin, abs(leftSpeed));
analogWrite(motorRightPin, abs(rightSpeed));
Serial.print("Line position: ");
Serial.print(linePosition);
Serial.print(", Motors: L=");
Serial.print(leftSpeed);
Serial.print(" R=");
Serial.println(rightSpeed);
}
delay(10);
}
float calculateLinePosition(int sensors[]) {
float weightedSum = 0;
int totalWeight = 0;
// Weight each sensor by its position
for (int i = 0; i < numSensors; i++) {
if (sensors[i] > lineThreshold) {
// Sensor sees line
int weight = i - 2; // -2, -1, 0, 1, 2
weightedSum += weight * sensors[i];
totalWeight += sensors[i];
}
}
if (totalWeight > 0) {
return weightedSum / totalWeight; // Weighted average position
} else {
return -999; // No line detected
}
}Example 3: Battery Monitor with Multiple Warning Levels
Graduated responses to battery status:
const int batteryPin = A0;
// Voltage thresholds (assuming voltage divider)
const float fullVoltage = 12.6;
const float normalVoltage = 11.5;
const float lowVoltage = 11.0;
const float criticalVoltage = 10.5;
// State tracking
bool warningGiven = false;
bool criticalWarningGiven = false;
void loop() {
float voltage = readBatteryVoltage();
// Multi-level decision tree
if (voltage >= normalVoltage) {
// Battery healthy
warningGiven = false;
criticalWarningGiven = false;
normalOperation();
} else if (voltage >= lowVoltage) {
// Battery getting low
if (!warningGiven) {
Serial.println("WARNING: Battery below normal level");
flashLED(2); // Visual warning
warningGiven = true;
}
reducedOperation();
} else if (voltage >= criticalVoltage) {
// Battery critically low
if (!criticalWarningGiven) {
Serial.println("CRITICAL: Battery very low - returning to base");
flashLED(5); // Urgent visual warning
criticalWarningGiven = true;
}
returnToBase();
} else {
// Battery dangerously low
Serial.println("EMERGENCY: Battery depleted - shutting down");
emergencyShutdown();
}
delay(1000); // Check every second
}
float readBatteryVoltage() {
int rawValue = analogRead(batteryPin);
// Convert ADC to voltage (adjust for your voltage divider)
float voltage = rawValue * (5.0 / 1023.0) * 3.0; // Example conversion
return voltage;
}
void normalOperation() {
Serial.println("Battery OK - normal operation");
// Full-speed operation
}
void reducedOperation() {
Serial.println("Reduced power mode");
// Slow down, reduce LED brightness, etc.
}
void returnToBase() {
Serial.println("Navigating to charging station");
// Special navigation to charger
}
void emergencyShutdown() {
Serial.println("Shutting down to protect battery");
// Stop all motors, save state, shut down
while(1); // Halt program
}
void flashLED(int times) {
for (int i = 0; i < times; i++) {
digitalWrite(LED_BUILTIN, HIGH);
delay(200);
digitalWrite(LED_BUILTIN, LOW);
delay(200);
}
}Common Logic Errors and How to Avoid Them
Even experienced programmers make logic errors. Recognizing common mistakes helps you avoid them.
Error 1: Using Assignment (=) Instead of Comparison (==)
// WRONG - Assigns 100 to speed, then tests if 100 is true (always true!)
if (speed = 100) {
Serial.println("This always executes!");
}
// CORRECT - Compares speed to 100
if (speed == 100) {
Serial.println("Executes only when speed equals 100");
}Prevention: Enable compiler warnings; some compilers warn about assignments in conditions.
Error 2: Incorrect Operator Precedence
// Ambiguous - what gets tested first?
if (a && b || c && d) { }
// Probably meant this
if ((a && b) || (c && d)) { }
// Or maybe this
if (a && (b || c) && d) { }Prevention: Always use parentheses to make precedence explicit, even when not strictly necessary.
Error 3: Floating-Point Equality Comparison
float voltage = readVoltage();
// WRONG - Floating-point values rarely equal exactly
if (voltage == 3.3) {
// Might never execute due to rounding errors!
}
// CORRECT - Check if within small range
if (abs(voltage - 3.3) < 0.1) {
// Executes if voltage is between 3.2 and 3.4
}Prevention: Never use == with float/double; always use range checking.
Error 4: Unreachable Code Due to Logic Order
int distance = 50;
// WRONG - Second condition never reached
if (distance < 100) {
Serial.println("Less than 100");
} else if (distance < 50) {
// Never executes! All values < 50 are also < 100
Serial.println("Less than 50");
}
// CORRECT - Check narrower ranges first
if (distance < 50) {
Serial.println("Less than 50");
} else if (distance < 100) {
Serial.println("Between 50 and 100");
}Prevention: Order conditions from most specific to least specific.
Error 5: Missing Braces Leading to Wrong Scope
// WRONG - Only first line is inside if statement
if (obstacleDetected)
Serial.println("Obstacle!");
stopMotors(); // ALWAYS executes, not just when obstacle detected!
// CORRECT - Braces make scope clear
if (obstacleDetected) {
Serial.println("Obstacle!");
stopMotors(); // Both lines execute only if condition is true
}Prevention: Always use braces, even for single-line if statements.
Comparison Table: Decision Structures
| Structure | Use When | Advantages | Disadvantages | Example |
|---|---|---|---|---|
| if | Single condition check | Simple, clear | Limited to one path | if (x > 5) { } |
| if-else | Two mutually exclusive options | Ensures one path executes | Only two options | if (x > 5) { } else { } |
| if-else-if | Multiple exclusive conditions | Many options, clear priority | Can become verbose | if (x < 5) { } else if (x < 10) { } |
| switch-case | Many discrete values of single variable | Clean for many cases | Only works with discrete values | switch(state) { case A: } |
| Nested if | Hierarchical decisions | Models complex logic | Can become hard to read | if (a) { if (b) { } } |
| Ternary | Simple conditional assignment | Concise, inline | Only for simple cases | x = (y > 5) ? 10 : 20; |
| Lookup table | Many value mappings | Fast, data-driven | Requires setup, uses memory | speeds[distanceIndex] |
Best Practices for Robot Decision Logic
Writing clear, maintainable decision logic requires discipline and good habits.
Use Meaningful Variable Names
// Unclear
if (x > 500) { y = 1; }
// Clear
if (distanceSensor > obstacleThreshold) { obstacleDetected = true; }Define Constants for Magic Numbers
// Bad - What does 350 mean?
if (analogRead(A0) > 350) { }
// Good - Clear meaning
const int LINE_THRESHOLD = 350;
if (analogRead(lineSensorPin) > LINE_THRESHOLD) { }Comment Complex Conditions
// Complex condition needs explanation
// Stop if battery critically low OR
// (obstacle very close AND unable to turn)
if (batteryVoltage < 10.5 ||
(frontDistance < 10 && !canTurn())) {
emergencyStop();
}Extract Complex Conditions into Functions
// Hard to understand
if (s1 > 500 && s2 > 500 && s3 < 300 || s4 > 400 && batteryOK) { }
// Clear and testable
if (lineDetected() && batteryOK) { }
bool lineDetected() {
return (sensor1 > 500 && sensor2 > 500 && sensor3 < 300) ||
(sensor4 > 400);
}Handle Edge Cases
// Check for invalid sensor readings
int distance = analogRead(distanceSensor);
if (distance == 0 || distance == 1023) {
// Sensor error - min or max reading
useDefaultBehavior();
} else {
// Valid reading - use normally
processDistance(distance);
}Test Decisions Systematically
Test all branches of your decision logic:
void testDecisionLogic() {
Serial.println("Testing decision logic...");
// Test case 1: Close obstacle
testObstacleResponse(10); // Should trigger emergency stop
// Test case 2: Moderate distance
testObstacleResponse(30); // Should trigger caution
// Test case 3: Far distance
testObstacleResponse(100); // Should continue normal
Serial.println("Tests complete");
}Conclusion: Logic as the Robot’s Intelligence
If-then logic transforms robots from mechanical devices into intelligent systems. Sensors provide data, motors enable action, but conditional logic creates the intelligence that connects perception to appropriate response. Every autonomous behavior—whether simple obstacle avoidance or sophisticated multi-goal planning—builds on the foundation of well-crafted conditional statements that evaluate situations and choose actions.
The decision-making skills you’ve developed in this article—understanding if-else structures, combining conditions with boolean operators, implementing common patterns, avoiding logic errors—apply universally across all programming and robotics platforms. The specific syntax might vary between Arduino, Python, C++, or other languages, but the logical principles remain constant. A well-structured decision tree in Arduino translates directly to equivalent logic in any other programming environment.
Start simple with your decision logic: a single if statement checking one sensor and controlling one actuator. As this becomes natural, add complexity: multiple conditions combined with AND/OR operators, if-else-if chains for multiple options, nested decisions for hierarchical logic, state machines for behavior sequencing. Each project builds understanding and confidence, developing intuition for how to structure decisions clearly and effectively.
Remember that the best decision logic is not the most complex—it’s the logic that clearly expresses your robot’s behavior in a way you and others can understand, test, and modify. Clever one-line conditionals might feel satisfying but can become maintenance nightmares. Clear, well-commented decision trees might span many lines but remain comprehensible months later when you need to debug or enhance functionality.
Most importantly, decision logic is where your robot’s personality and intelligence emerge. The same hardware with different decision logic exhibits entirely different behaviors. Your choices about what conditions matter, how sensors combine, which actions correspond to which situations—these design decisions transform generic components into unique robot behaviors. Master conditional logic, and you master the essential skill that brings robot intelligence to life.








