Week 8 - Output Devices

This week, I started to work on my final project, so I created a board that allows connections of a microcontroller with a DC motor, a servo, a NeoPixel LED (strip), a mist generation module, and a TDS sensor.

Main Components and Machines/Tools

Components

Selection criteria: The XIAO ESP32C3 microcontroller board was chosen for its compactness and bluetooth and wifi capabilities. The 3-6V small DC motor was chosen because I don't need the boat to run super fast, but a future improvement will be to use a more powerful motor to control the propeller or use a waterjet.

Machines/Tools

  • Othermill desktop milling machine
  • 1/32'' flat end mill
  • 1/64'' flat end mill
  • Solder wire and solder station

Helpful Resources

Design Files

Images/week8/Boat_Motor_Servo_LED_MistGenerator_TDSSensor v1.f3z

PCB Schematic and Layout

Schematic
PCB Layout

Note that in the layout, the three pins out of the board outline were unused.

The pin functions and hookup explanations for each of the components are specified below:

  • Servo (3): [Data, (5V), GND]. A diode was added between the component and the 5V source for protection*.
  • DC motor (2): [POS, NEG]. An n-MOS was used to control the on/off and the speed of the motor (through PWM). Since single-direction spinning was enough for my application, no H-bridges were used. A diode was added between the two terminals to prevent voltage spike when the motor was abruptly switched off but still turning because of inertia, as suggested by Samual. A 1 u capacitor was also added to smooth out motor voltages. A diode was added between the component and the 5V source for protection*. Later when soldering the components, a 10k pull-down resistor was also added to the gate of the n-MOS so that if the gate voltage was not set in the code, it wouldn't be left floating, as recommended by Anthony.
  • NeoPixel LED (3): [5V, GND, DIN]. DOUT and DIN on different NeoPixel LEDs could be chained up and controlled together.
  • TDS Sensor (3): [5V, SensorOutput, GND]. This sensor had no switch to control and was kept on when powered on.
  • Mist Generator (2): [5V(POS), NEG]. An n-MOS was used as a switch to turn the mist generator on and off.
  • Battery (2): [5V, GND]. The battery was intended to be used to power both the microcontroller and the input/output devices. A diode was added between the battery and the microcontroller board for protection. I saw this method of powering the microcontroller board from the XIAO-ESP32C3 Getting Started Guide. However, Anthony was strongly against this method of powering the board, because the 5V was directly connected to the VUSB. If I connected the battery and the USB to my laptop at the same time, and the battery voltage exceeded 5V, it could damage my laptop. I really appreciated his efforts for persuading me not to post a great risk to my laptop, and I agreed that the connection was not a wise. Therefore, I switched to use the 5V battery that directly connected to the USB port of the microcontroller board, and when soldering the components, the diode was replaced by a 0 ohm resistor.
  • *Initially, I had the 5V of each component connected to the same diode coming out of the battery source. However, Samual pointed out that the diode had a maximum current that could pass through (150 mA or 1 A for our stock schottky diodes), and my motor and servo drawing current at the same time would be pushing the 1A limit. Therefore, I had the motor and the servo connected to different diodes to the 5V battery, which would allow more current to pass through. However, Anthony pointed out that those diodes between the 5V power and the servo or motor were in fact not necessary, so later when soldering components, those diodes were replaced by 0 ohm resistors.

    PCB Milling

    The milling went well as before:

    milling process
    milled board

    Component Soldering

    The microcontroller back was covered with insulating tape before soldering, and the soldered board is shown below:

    soldered board
    The descrepancies with the designed schematic/layout were marked. Red: diodes replaced with 0 ohm resistors. Blue: added 10k ohm resistor.

    Board Testing

    Servo Test Code

    The code was modified from the ESP32Servo Arduino Library. Although 0 and 180 degrees corresponded to 1000us and 2000us on the servo datasheet, 180 degrees could not be reached using those two values, so 500us and 2500us were used instead.

                /* Sweep
    by BARRAGAN <http://barraganstudio.com>
    This example code is in the public domain.
    
    modified 8 Nov 2013
    by Scott Fitzgerald
    
    modified for the ESP32 on March 2017
    by John Bennett
    
    modified by Fan Xue on Nov 2024
    
    see http://www.arduino.cc/en/Tutorial/Sweep 
    for a description of the original code
    */
    
    
    #include <ESP32Servo.h>
    
    Servo myservo;  // create servo object to control a servo
    
    int pos = 0;    // variable to store the servo position
    
    #if defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3)
    int servoPin = 17;
    #elif defined(CONFIG_IDF_TARGET_ESP32C3)
    int servoPin = 7;  // Used
    #else
    int servoPin = 18;
    #endif
    // int servoPin = 4;
    
    void setup() {
        // Allow allocation of all timers
        ESP32PWM::allocateTimer(0);
        ESP32PWM::allocateTimer(1);
        ESP32PWM::allocateTimer(2);
        ESP32PWM::allocateTimer(3);
        myservo.setPeriodHertz(50);    // standard 50 hz servo
        myservo.attach(servoPin, 500, 2500); // 
        // using default min/max of 500us and 2500us
        // different servos may require different min/max settings
        // for an accurate 0 to 180 sweep
    }
    
    void loop() {
    
        for (pos = 0; pos <= 180; pos += 1) { // goes from 0 degrees to 180 degrees
            // in steps of 1 degree
            myservo.write(pos);    // tell servo to go to position in variable 'pos'
            delay(15);             // waits 15ms for the servo to reach the position
        }
        for (pos = 180; pos >= 0; pos -= 1) { // goes from 180 degrees to 0 degrees
            myservo.write(pos);    // tell servo to go to position in variable 'pos'
            delay(15);             // waits 15ms for the servo to reach the position
        }
    }
    
            
        

    Motor Test Code

            const int motorPin = 20;
    
    void setup() {
        pinMode(motorPin, OUTPUT);
    }
    
    void loop() {
        //Motor
        int speed;
        for (speed = 0; speed <=255; speed +=50){
        analogWrite(motorPin, speed);
        delay(1000);
        }
        analogWrite(motorPin, 0);
        delay(1000);
    }
        
        

    Demo

    Interestingly, the servo and motor were not working when connected to my laptop direclty. Only a small range of angle/speed could be reached, and afterwards they got disconnected to my laptop, reconnected to my laptop and reset. Anthony said it was probably because my computer could not provide enough current for those parts, and whenever the current exceeded the threshold, the USB got disconnected. Therefore, I tried to power by battery instead of by my laptop, and it worked afterwards. Below is a comparison between powering the servo by laptop and by battery.

    Acknowledgements

    I would like to thank Anthony for providing me with valuable advices on many aspects and helping me with component testing, Samual for helping me with schematics design and component testing, and Yuval for idea brainstorming and component testing.