Back to Weekly Assignments

Week 16: Plan for system integration

Plan for System Integration

My final project is a rotating-disc color sorting machine that detects the color of small objects like beads, and sorts them into different bins according to the color. The core components:

  • XIAO ESP32-C3 (main controller)
  • TCS34725 color sensor (I2C)
  • Stepper motor (28BYJ-48) or DC geared motor for disc rotation
  • Micro servo (SG90) for moving the sliding track
  • Micro limit switch (at base, for position feedback or trigger)
  • 3D-printed parts: funnel, rotating disc (with pockets), base frame, sliding chute, bins
  • Power supply: 5V USB or battery pack

Integration plan

  1. Mount the motor on the base plate. Attach the rotating disc to the motor shaft.
  2. Mount the funnel above the disc so objects drop into disc pockets.
  3. Mount the color sensor at a fixed station over the disc (or under it).
  4. Mount the servo with a sliding chute (pivoting track) underneath the disc.
  5. Install the limit switch at the base to detect disc home position or to act as a manual start button.
  6. Write firmware that:
    • Rotates the disc step-by-step.
    • Reads color when an object is under the sensor.
    • Moves servo to the correct chute angle.
    • Releases the object into the chute.
    • Uses the switch for synchronisation.
  7. Enclose electronics and organise wiring.

Implemented Methods of Packaging

The result is a self-contained desktop sorter: no loose wires, no exposed moving belts.

Component Packaging / Mounting
XIAO ESP32 Mounted on a small PCB breakout with M2 screws; placed inside a printed electronics box under the base.
Stepper motor Fixed to the base plate using M3 screws; motor shaft coupled to disc via a printed hub.
Color sensor Inserted into a printed holder that keeps it 5mm above the disc surface.
Servo Screwed into a bracket that supports the sliding chute.
Limit switch Mounted on the base with an adjustable screw actuator; triggered by a tab on the disc (home position).
Wiring All wires routed through channels in the base; using cable ties and a single cable exit.
Overall enclosure A laser-cut acrylic cover with ventilation slots protects the electronics and moving parts.

Designed to Look Like a Finished Product

  • Color: White PLA + transparent acrylic top to show the mechanism.
  • Funnel: Transparent window to see objects as they enter the disc.
  • Bins: Colour-coded (red, green, blue, black for “other”) with engraved labels.
  • Base switch: Prominent, user-friendly illuminated push button to start each sorting cycle.
  • Feet: Rubber pads to prevent sliding.
  • Cable management: All electronics hidden in a bottom compartment accessible via a snap-fit lid.
  • Status (optional): LED ring around the funnel that glows in the colour of the detected object.

Documentation of System Integration

Hardware Integration

  1. Motor & disc assembly
    • Stepper motor (28BYJ-48) controlled via ULN2003 driver.
    • Disc rotation: 60° per step (6 positions). Home position detected by limit switch.
  2. Sensor mounting
    • TCS34725 placed over the disc at station #2 (after funnel). Distance = 5mm, ambient light blocked by a printed shroud.
  3. Servo & chute
    • Servo mounted under the disc, pointing upward. Its horn rotates a sliding track (a curved ramp). Angles:
      • Red → 0° (chute aligns with Bin 1)
      • Green → 45° (Bin 2)
      • Blue → 90° (Bin 3)
      • Other → 135° (Bin 4)
  4. Base switch
    • Normally open micro switch wired to GPIO3 (internal pull-up). When pressed, it starts the sorting routine. Also used to confirm that the chute is clear (after a 200ms delay).
  5. Power
    • XIAO ESP32 powered via USB-C (5V).
    • Stepper motor and servo powered separately from a 5V/2A supply with common ground.

Software Integration (Arduino IDE)

#include <Stepper.h>
    #include <Wire.h>
    #include <Adafruit_TCS34725.h>
    #include <ESP32Servo.h>
    
    // Pins
    #define STEPPER_IN1  D0
    #define STEPPER_IN2  D1
    #define STEPPER_IN3  D2
    #define STEPPER_IN4  D3
    #define SERVO_PIN    D4
    #define SWITCH_PIN   D5
    #define SDA_PIN      D6
    #define SCL_PIN      D7
    
    Adafruit_TCS34725 tcs = Adafruit_TCS34725(TCS34725_INTEGRATIONTIME_50MS, TCS34725_GAIN_4X);
    Servo chuteServo;
    Stepper myStepper(2048, STEPPER_IN1, STEPPER_IN3, STEPPER_IN2, STEPPER_IN4);
    
    int currentPos = 0;
    const int stepsPerPocket = 341; // 2048/6
    
    void setup() {
      Serial.begin(115200);
      Wire.begin(SDA_PIN, SCL_PIN);
      if (!tcs.begin()) {
        Serial.println("Sensor error");
        while (1);
      }
      chuteServo.attach(SERVO_PIN);
      pinMode(SWITCH_PIN, INPUT_PULLUP);
      myStepper.setSpeed(15);
      // Home: rotate until switch is pressed
      while(digitalRead(SWITCH_PIN)) {
        myStepper.step(10);
        delay(2);
      }
      currentPos = 0;
      Serial.println("Ready");
    }
    
    String classifyColor(uint16_t r, uint16_t g, uint16_t b) {
      if (r > g && r > b && r > 200) return "RED";
      if (g > r && g > b && g > 180) return "GREEN";
      if (b > r && b > g && b > 180) return "BLUE";
      return "OTHER";
    }
    
    void setChute(String color) {
      if (color == "RED") chuteServo.write(0);
      else if (color == "GREEN") chuteServo.write(45);
      else if (color == "BLUE") chuteServo.write(90);
      else chuteServo.write(135);
      delay(500); // chute settles
    }
    
    void loop() {
      // Wait for base switch press to start
      if (digitalRead(SWITCH_PIN) == LOW) {
        delay(50); // debounce
        // Move disc to bring a pocket from funnel to sensor
        myStepper.step(stepsPerPocket);
        currentPos = (currentPos + 1) % 6;
        delay(300);
        
        // Read color
        uint16_t r, g, b, c;
        tcs.getRawData(&r, &g, &b, &c);
        String color = classifyColor(r, g, b);
        Serial.println(color);
        
        // Set chute angle
        setChute(color);
        
        // Move disc to release position (e.g., next step)
        myStepper.step(stepsPerPocket);
        currentPos = (currentPos + 1) % 6;
        delay(500);
        
        // Return chute to neutral (optional)
        chuteServo.write(90);
        
        // Wait for user to press switch again
        while(digitalRead(SWITCH_PIN) == LOW);
        delay(100);
      }
    }

Sketches for System Integration:

Sketch 1 – System block diagram

Finished module / enclosure overview

Sketch 2 – Mechanical layout (side view)

Finished module / enclosure overview Finished module / enclosure overview