Ultrasonic sensor to control 12v fan speed.

I've been looking for examples with using HC-SR04 Ultrasonic Sensor to activate and control the speed of a 12v PC fan and haven't seen anything.

I'm new to Arduino and electrical engineering so I apologize if I've missed the obvious. I've mixed and matched the use of the sensor and turning the 3 wire 12v fan on with a relay and Ardunio UNO WiFi board but haven't been able to combine the two with any success.

If you have any experience with a project like this or any advice I'm more than grateful. Thank you

Post technical documentation, code and wiring according tothe topic "How to use this Forum".
Else You need to ask Singoalla.

suppafly:
t haven't been able to combine the two with any success.

Does that mean you have the two parts running OK on their own?

Here you go, complete working example including time of day restrictions:

#define trigPin 2  // HC-SR04 range finder - trig pin.
#define echoPin 0  // HC-SR04 range finder - echo pin.

#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
#include <TimeLib.h>

const uint16_t startTime = 8 * 60 + 0;
const uint16_t endTime = 20 * 60 + 0;
const float minDistance = 20;

char ssid[] = "*************";  //  your network SSID (name)
char pass[] = "************";       // your network password

const uint8_t timezone = 8;

unsigned int localPort = 2390;      // local port to listen for UDP packets

/* Don't hardwire the IP address or we won't get the benefits of the pool.
    Lookup the IP address for the host name instead */
//IPAddress timeServer(129, 6, 15, 28); // time.nist.gov NTP server
IPAddress timeServerIP; // time.nist.gov NTP server address
const char* ntpServerName = "time.nist.gov";

const int NTP_PACKET_SIZE = 48; // NTP time stamp is in the first 48 bytes of the message

byte packetBuffer[ NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets

// A UDP instance to let us send and receive packets over UDP
WiFiUDP udp;

void setup() {
  pinMode(trigPin, OUTPUT);
  digitalWrite(trigPin, LOW);
  pinMode(echoPin, INPUT);
  Serial.begin (9600);
  Serial.println("Starting up!");
  WiFi.begin(ssid, pass);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");

  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());

  Serial.println("Starting UDP");
  udp.begin(localPort);
  Serial.print("Local port: ");
  Serial.println(udp.localPort());
}


/*
   © Francesco Potortì 2013 - GPLv3 - Revision: 1.13

   Send an NTP packet and wait for the response, return the Unix time

   To lower the memory footprint, no buffers are allocated for sending
   and receiving the NTP packets.  Four bytes of memory are allocated
   for transmision, the rest is random garbage collected from the data
   memory segment, and the received packet is read one byte at a time.
   The Unix time is returned, that is, seconds from 1970-01-01T00:00.
*/
unsigned long inline ntpUnixTime (UDP &udp)
{
  static int udpInited = udp.begin(123); // open socket on arbitrary port

  const char timeServer[] = "pool.ntp.org";  // NTP server

  // Only the first four bytes of an outgoing NTP packet need to be set
  // appropriately, the rest can be whatever.
  const long ntpFirstFourBytes = 0xEC0600E3; // NTP request header

  // Fail if WiFiUdp.begin() could not init a socket
  if (! udpInited)
    return 0;

  // Clear received data from possible stray received packets
  udp.flush();

  // Send an NTP request
  if (! (udp.beginPacket(timeServer, 123) // 123 is the NTP port
         && udp.write((byte *)&ntpFirstFourBytes, 48) == 48
         && udp.endPacket()))
    return 0;       // sending request failed

  // Wait for response; check every pollIntv ms up to maxPoll times
  const int pollIntv = 150;   // poll every this many ms
  const byte maxPoll = 15;    // poll up to this many times
  int pktLen;       // received packet length
  for (byte i = 0; i < maxPoll; i++) {
    if ((pktLen = udp.parsePacket()) == 48)
      break;
    delay(pollIntv);
  }
  if (pktLen != 48)
    return 0;       // no correct packet received

  // Read and discard the first useless bytes
  // Set useless to 32 for speed; set to 40 for accuracy.
  const byte useless = 40;
  for (byte i = 0; i < useless; ++i)
    udp.read();

  // Read the integer part of sending time
  unsigned long time = udp.read();  // NTP time
  for (byte i = 1; i < 4; i++)
    time = time << 8 | udp.read();

  // Round to the nearest second if we want accuracy
  // The fractionary part is the next byte divided by 256: if it is
  // greater than 500ms we round to the next second; we also account
  // for an assumed network delay of 50ms, and (0.5-0.05)*256=115;
  // additionally, we account for how much we delayed reading the packet
  // since its arrival, which we assume on average to be pollIntv/2.
  time += (udp.read() > 115 - pollIntv / 8);

  // Discard the rest of the packet
  udp.flush();

  return time - 2208988800ul;   // convert NTP time to Unix time
}

void loop() {
  static WiFiUDP udp;
  static bool haveTime = false;
  static uint32_t lastNtpCheck;
  if ((haveTime && millis() - lastNtpCheck > 60 * 60 * 1000) ||
      (haveTime == false && millis() - lastNtpCheck > 1000)) {
    lastNtpCheck = millis();
    unsigned long unixTime = ntpUnixTime(udp);
    if (unixTime > 0) {
      haveTime = true;
      setTime(unixTime + timezone * 60 * 60);
      Serial.println(F("Got time."));
      Serial.print("Hour: ");
      Serial.print(hour());
      Serial.print(", minute: ");
      Serial.println(minute());
    }
    else {
      haveTime = false;
    }
  }

  static uint32_t lastPing;
  static bool relayOn = false;
  static uint32_t seenGwai;
  if (hour() * 60 + minute()  > startTime && hour() * 60 + minute() < endTime) {
    if (millis() - lastPing > 1000) {
      lastPing = millis();
      uint16_t duration;
      float distance;
      digitalWrite (trigPin, LOW);
      delayMicroseconds(2);
      digitalWrite (trigPin, HIGH);
      delayMicroseconds(10);
      digitalWrite (trigPin, LOW);
      delayMicroseconds(2);
      duration = pulseIn(echoPin, LOW, 20000); // Inverted signal!
      distance = float(duration / 2) / 29.1;
      if (distance > 0 &&
          distance < minDistance) {
        seenGwai = millis();
        if (relayOn == false) {
          switchRelayOn();
          relayOn = true;
        }
      }
      else {
        if (relayOn &&
        millis() - seenGwai > 60000) {  // Keep on for at least a minute after the gwai was detected.
          switchRelayOff();
          relayOn = false;
        }
      }
//      Serial.println(String("duration: " + String(duration) + ", distance: " + String(distance) + " cm."));
    }
  }
  else if (relayOn) {
    switchRelayOff();
    relayOn = false;
  }
}
bool switchRelayOn() {
  Serial.write(0xa0);
  Serial.write(0x01);
  Serial.write(0x01);
  Serial.write(0xa2);
  Serial.println("On.");
}

bool switchRelayOff() {
  Serial.write(0xa0);
  Serial.write(0x01);
  Serial.write(0x00);
  Serial.write(0xa1);
  Serial.println("Off.");
}

Switching relay based on HC-SR04. In my case the relay is switching the 220VAC heat lamp for my terrapin, but that's irrelevant to the rest of the project. It could just as well have been a 12VDC fan.

Of note: this is running on an ESP-01 relay module; using Serial commands to switch the relay (which has its own little MCU - beats me why they don't just a transistor there) and as I had to connect the HC-SR04 to GPIO0 and 2 I had to invert the echo signal.

No speed control can sensibly be done when switching a fan with a relay.

That's awesome, thank you. After some more digging I think a L298N H-Bridge Motor Driver might be a good fit here over a standard Relay. Only needs 0.15a for the single fan and it will provide the speed control.

I'll work with your example, thanks again.

The L298N is a terrible fit (if only because it's an obsolete design making it a terrible fit for just about any application).

You don't need a motor driver to speed control a fan; you need a simple MOSFET (or at your current a BJT will do as well) that's driven by the Arduino's PWM output.