Skip to content

IoT Sensors & Actuators — Complete Hardware Guide

DodaTech Updated 2026-06-21 8 min read

In this tutorial, you'll learn about IoT Sensors & Actuators. We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.

IoT sensors and actuators are the physical interface between digital systems and the real world — sensors collect environmental data while actuators perform physical actions, forming the foundation of any IoT deployment.

What You'll Learn

You'll explore common IoT sensor types (temperature, pressure, motion, gas), actuator interfaces (servos, relays, motors), sensor calibration and signal conditioning techniques, and wiring/interfacing code for ESP32 and Arduino.

Why Sensors & Actuators Matter

Every IoT system starts with sensing and ends with action. A temperature sensor without a cooling actuator is just a weather station. An alarm without a sensor is useless. At DodaTech, our Industrial Iot security system uses PIR motion sensors to detect physical intrusion and relay actuators to trigger locks and alerts.

Real-World Use Case

A greenhouse deploys 12 sensors (temperature, humidity, soil moisture, light) and 6 actuators (water pump, vent motors, grow lights). When soil moisture drops below 30%, the pump activates. When temperature exceeds 35°C, vents open. The system saves 40% water and increases crop yield by 25%.

Sensor Types and Interfaces

Sensor Type Measures Interface Common ICs
Temperature Ambient temp I2C, OneWire DHT22, BME280, DS18B20
Pressure Barometric I2C, SPI BMP280, MS5611
Motion Movement, presence Digital GPIO PIR HC-SR501
Gas Air quality I2C, Analog MQ-135, CCS811
Distance Proximity I2C, PWM HC-SR04, VL53L0X
Humidity Moisture in air I2C, OneWire DHT22, SHT30

Reading Sensors with ESP32

Temperature and Humidity (DHT22)

#include <DHT.h>

#define DHTPIN 4
#define DHTTYPE DHT22

DHT dht(DHTPIN, DHTTYPE);

void setup() {
  Serial.begin(115200);
  dht.begin();
}

void loop() {
  float humidity = dht.readHumidity();
  float temperature = dht.readTemperature(); // Celsius
  
  // Check for read errors
  if (isnan(humidity) || isnan(temperature)) {
    Serial.println("ERROR: Failed to read from DHT sensor!");
    delay(2000);
    return;
  }
  
  Serial.print("Temperature: ");
  Serial.print(temperature);
  Serial.print("°C | Humidity: ");
  Serial.print(humidity);
  Serial.println("%");
  
  // Alert if out of range
  if (temperature > 35.0) {
    Serial.println("WARNING: High temperature detected!");
  }
  if (humidity < 20.0) {
    Serial.println("WARNING: Low humidity detected!");
  }
  
  delay(2000);
}

Expected output:

Temperature: 24.5°C | Humidity: 55.2%
Temperature: 24.6°C | Humidity: 55.1%

Error handling catches sensor disconnection gracefully.

Ultrasonic Distance Sensor (HC-SR04)

#define TRIG_PIN 5
#define ECHO_PIN 18

void setup() {
  Serial.begin(115200);
  pinMode(TRIG_PIN, OUTPUT);
  pinMode(ECHO_PIN, INPUT);
}

float measureDistance() {
  // Send 10us pulse
  digitalWrite(TRIG_PIN, LOW);
  delayMicroseconds(2);
  digitalWrite(TRIG_PIN, HIGH);
  delayMicroseconds(10);
  digitalWrite(TRIG_PIN, LOW);
  
  // Measure echo pulse duration
  long duration = pulseIn(ECHO_PIN, HIGH, 30000); // 30ms timeout
  
  if (duration == 0) {
    return -1.0; // No echo — out of range
  }
  
  // Convert to cm: speed of sound = 343m/s
  float distance = (duration * 0.034) / 2;
  return distance;
}

void loop() {
  float cm = measureDistance();
  
  if (cm < 0) {
    Serial.println("Out of range");
  } else {
    Serial.print("Distance: ");
    Serial.print(cm);
    Serial.println(" cm");
    
    if (cm < 20) {
      Serial.println("WARNING: Object too close!");
    }
  }
  
  delay(500);
}

Expected output:

Distance: 45.2 cm
Distance: 12.8 cm
WARNING: Object too close!

The sensor detects objects from 2cm to 400cm with ±3mm accuracy.

Controlling Actuators

Servo Motor Control

#include <ESP32Servo.h>

Servo myServo;
#define SERVO_PIN 13

void setup() {
  myServo.attach(SERVO_PIN);
  Serial.begin(115200);
}

void loop() {
  // Sweep from 0 to 180 degrees
  for (int angle = 0; angle <= 180; angle += 1) {
    myServo.write(angle);
    Serial.print("Angle: ");
    Serial.println(angle);
    delay(15); // Allow servo to reach position
  }
  
  // Return to 0
  for (int angle = 180; angle >= 0; angle -= 1) {
    myServo.write(angle);
    delay(15);
  }
}

Expected output: Servo sweeps from 0° to 180° and back. Each position takes ~15ms to reach. PWM signal on pin 13 controls the angle.

Relay Module for High-Power Devices

#define RELAY_PIN 12

void setup() {
  pinMode(RELAY_PIN, OUTPUT);
  Serial.begin(115200);
}

void controlDevice(bool turnOn, const char* deviceName) {
  digitalWrite(RELAY_PIN, turnOn ? HIGH : LOW);
  Serial.print(deviceName);
  Serial.println(turnOn ? " turned ON" : " turned OFF");
}

void loop() {
  // Simulate thermostat: turn on when cold
  float temp = readTemperature(); // From earlier DHT22 code
  
  if (temp < 18.0) {
    controlDevice(true, "Heater");
  } else if (temp > 25.0) {
    controlDevice(false, "Heater");
  }
  
  delay(10000); // Check every 10 seconds
}

Expected output: The relay module switches a 220V heater based on temperature. The LED on the relay indicates on/off state.

Sensor Calibration

class CalibratedSensor {
  private:
    float offset;    // Zero-point calibration value
    float scale;     // Gain correction factor
    
  public:
    CalibratedSensor(float ref_temp) {
      // Calibrate against known reference
      float raw = readRaw();
      offset = ref_temp - raw;
      scale = 1.0; // Assume linear gain = 1
    }
    
    float readCalibrated() {
      float raw = readRaw();
      return (raw * scale) + offset;
    }
    
    void twoPointCalibration(float ref_low, float raw_low, 
                              float ref_high, float raw_high) {
      scale = (ref_high - ref_low) / (raw_high - raw_low);
      offset = ref_low - (raw_low * scale);
    }
};

Expected output: Calibration corrects for sensor manufacturing tolerances. A DHT22 may read 24.5°C while the actual temperature is 25.0°C — calibration adjusts the offset.

Mermaid Diagram: Sensor-to-Actuator Loop

flowchart LR
    A[Sensor] -->|Analog/Digital| B[Microcontroller]
    B --> C[Processing & Decision]
    C -->|PWM/GPIO| D[Actuator]
    C -->|MQTT/WiFi| E[Cloud Platform]
    E -->|Command| C
    D --> F[Physical Action]
    F -->|Changes Environment| A
    style A fill:#d4edda
    style B fill:#e6f3ff
    style D fill:#fff3cd
    style F fill:#cce5ff

Signal Conditioning

Issue Solution Circuit
Noise Low-pass filter 10kΩ + 100nF to ground
Voltage shift Level shifter BSS138 MOSFET
Amplification Op-amp LM358 non-inverting
Debouncing Schmitt trigger 74HC14 or RC filter
Isolation Optocoupler PC817

Common Sensor Errors

1. Floating Input Pins

Problem: Unconnected pin reads random values. Fix: Enable internal pull-up/pull-down or use external resistor.

2. ADC Voltage Mismatch

Problem: ESP32 ADC is 0-3.3V but sensor outputs 0-5V. Fix: Use voltage divider (2:1 ratio with 10kΩ and 20kΩ resistors).

3. Insufficient Power for Actuators

Problem: Servo causes ESP32 to reset. Fix: Use separate power supply for motors/servos — never draw from MCU 3.3V pin.

4. Sensor Delayed Readings

Problem: DHT22 requires 2s between reads. Fix: Respect sensor timing specs — most sensors have minimum interval.

5. I2C Address Conflicts

Problem: Two sensors share same I2C address. Fix: Use I2C multiplexer (TCA9548A) or sensors with configurable addresses.

6. PWM Frequency Mismatch

Problem: Servo jitters at wrong PWM frequency. Fix: Use 50Hz (20ms period) for standard servos, 1-2ms pulse width.

Practice Questions

  1. What is the difference between a sensor and a transducer? All sensors are transducers, but not all transducers are sensors. A transducer converts energy form. A sensor specifically measures a physical quantity.

  2. Why use I2C over analog sensors? I2C provides digital reading, no ADC needed, multiple sensors on two wires, and built-in calibration.

  3. What is PWM and how does it control actuators? Pulse-Width Modulation varies the duty cycle to control motor speed, servo position, or LED brightness.

  4. How do you protect MCU pins from inductive loads? Use a flyback diode (1N4007) across relay coils and motor terminals to suppress voltage spikes.

  5. What is the Nyquist sampling theorem for sensors? Sample at least 2x the highest frequency in the signal. For temperature (changes slowly), 1 sample/10s is fine. For vibration analysis, 1kHz+ needed.

Challenge

Build a closed-loop temperature control system: read a DS18B20 temperature sensor, implement a PID controller on ESP32, drive a MOSFET-controlled heating element, and maintain temperature at 25°C ± 0.5°C. Log data to serial and display in real-time.

Real-World Task

Design a sensor array for a smart hydroponic system. Sensors needed: water temperature (DS18B20), pH (analog pH probe), water level (HC-SR04), ambient temperature/humidity (DHT22). Actuators: water pump (relay), LED grow light (PWM), nutrient dosing pump (stepper motor). Draw a wiring diagram and write the main loop.

Mini Project: Multi-Sensor Dashboard

struct SensorData {
  float temperature;
  float humidity;
  float distance;
  int motion_detected;
};

SensorData readAllSensors() {
  SensorData data;
  data.temperature = dht.readTemperature();
  data.humidity = dht.readHumidity();
  data.distance = measureDistance();
  data.motion_detected = digitalRead(PIR_PIN);
  
  // JSON-like output for parsing
  Serial.println("=== Sensor Readings ===");
  Serial.printf("Temp: %.1f°C\n", data.temperature);
  Serial.printf("Humidity: %.1f%%\n", data.humidity);
  Serial.printf("Distance: %.1fcm\n", data.distance);
  Serial.printf("Motion: %s\n", 
                data.motion_detected ? "DETECTED" : "None");
  Serial.println("======================");
  
  return data;
}

This function centralizes all sensor reads into a structured format for easy serial Parsing or MQTT publishing.

  • Arduino — Foundation sensor programming
  • ESP32 — Advanced sensor interfacing
  • IoT Security — Secure sensor data transmission
  • Next: IoT Cloud Platforms — AWS IoT, Azure IoT & GCP IoT
  • Previous: IoT Edge Computing — Processing Data at the Edge Guide
Which sensor should I use for accurate temperature?

DS18B20 for ±0.5°C precision (OneWire), BME280 for temperature + humidity + pressure (I2C, ±1°C). Avoid DHT11 for precision work (±2°C).

Can I connect multiple I2C sensors?

Yes — each I2C device has a unique address (7-bit). You can connect up to 127 devices on the same SDA/SCL lines, but bus capacitance limits practical count to ~20 at 400kHz.

How do I choose between analog and digital sensors?

Use digital (I2C/SPI) for precision, built-in calibration, and noise immunity. Use analog only when the sensor output is inherently analog (microphone, light-dependent resistor) and you have a clean ADC reference.

Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro