Toggling a relay switch at random intervals, but only once a user is detected

Hi everyone! I have a question in regards to an interaction design project that I am currently setting up for an exhibition.

The concept involves a lamp that reacts with breathing light once a user presents themselves to it. It makes use of a HC-SR04 distance sensor, Arduino Uno board, LED array and a warm bulb connected to a relay.

Originally, the project had a counterpart overseas and the two communicated using an online server to interpret and send back instructions. Each lamp's distance would be sent, and then a value would be pushed out by the server to trigger a specific state back on each of the lamps. The LED array reacts almost as a local feature of each lamp, and is just dependent on the user's distance away from the sensor. The bulb however is triggered when a user is present at both lamps, showing that someone else is there, standing in front of theirs. If only one user is present at a lamp, then only local LED functions will happen.

As of now, the lamp is just to be exhibited in a gallery and will not be connected to the internet, meaning that I have had to redo the code for the lamp we have. Currently I have created the desired breathing/intensity effect of the LED array based upon specific distance zones I have defined, also being the only reaction that needs to happen real time.

For the purpose of the exhibition, I would just like to replicate the toggling of the bulb relay. I am hoping someone would be able to help me with code that randomly toggles the relay switch, at relatively long intervals? Would this even be feasible?

My thoughts is that it would give the same effect of someone walking past at the other hypothetical lamp. I am not quite sure how to go about randomizing a switch at the same time as my breathing script, as I am still pretty new to Arduino. This randomising code would only need to run concurrently to the LED breathing, and not when the lamp is in resting state and not detecting a user.

Let me know what you think! And thank you for any help you may give :slight_smile:

#define echoPin 2
#define trigPin 3

long duration;
int distance;
const int ledPin = 9;

void setup() {
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
  pinMode(ledPin, OUTPUT);
  Serial.begin(9600);
  Serial.println("Ultrasonic Sensor HC-SR04 Test");
  Serial.println("with Arduino UNO R3");
  digitalWrite (ledPin, LOW);
}
void loop() {
  digitalWrite(trigPin, LOW);
  delayMicroseconds(1);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(1);
  digitalWrite(trigPin, LOW);
  duration = pulseIn(echoPin, HIGH);
  distance = duration * 0.034 / 2;
  Serial.print("Distance: ");
  Serial.print(distance);
  Serial.println(" cm");
   if ((distance < 60) && (distance > 10)){
    
    for (int a=20; a<=255;a++)
  {
    analogWrite(ledPin, a);
    delay(2);
  }
    for (int a=255; a>=20;a--)
  {
    analogWrite(ledPin, a);
    delay(2);
  }
  delay(100);
       digitalWrite (ledPin, LOW);
   }
   
  if ((distance < 130) && (distance >= 60)){
    
    for (int a=3; a<=60;a++)
  {
    analogWrite(ledPin, a);
    delay(15);
  }
    for (int a=60; a>=3;a--)
  {
    analogWrite(ledPin, a);
    delay(15);
  }
  delay(50);
       digitalWrite (ledPin, LOW);
   }

  if (distance >= 130){
    
    for (int a=0; a<=10;a++)
  {
    analogWrite(ledPin, a);
    delay(100);
  }
    for (int a=10; a>=0;a--)
  {
    analogWrite(ledPin, a);
    delay(100);
  }
  delay(800);
       digitalWrite (ledPin, LOW);
   }
     if (distance <= 10){
      digitalWrite (ledPin, LOW);
     }
   else{ 
       digitalWrite (ledPin, LOW);
  }
}

Do you think it might help to see your current code ?

Please follow the advice on posting code given in posting code

In particular note the advice to Auto format code in the IDE and to use code tags when posting code here as it prevents some combinations of characters in code being interpreted as HTML commands such as italics, bold or a smiley character, all of which render the code useless

Code added! That is without any sort of randomisation of a relay.

Here is the core of what you say you want

unsigned long startTime;
unsigned long currentTime;
unsigned long period;

void setup()
{
  Serial.begin(115200);
  while (!Serial);
}

void loop()
{
  currentTime = millis();
  if (currentTime - startTime >= period)
  {
    startTime = currentTime;
    period = random(1000, 5001); //random period between 1000 and 5000 milliseconds
    Serial.print("waiting ");
    Serial.print(period);
    Serial.println(" milliseconds");
  }
}

Thank you! This really helped a lot :smiley:
I will say I haven't quite gotten there yet though. Currently I have the relay toggling at the desired intervals once it is within the distance range I have set, but once it leaves that range it stays at the state it was toggled to. How can I fix this? I have tried setting the Bulb state to LOW in the setup, as well as an 'else' statement after your code you gave me. Nether worked. The code I am using to test it out is below, will add the other LED code once it works.

#define echoPin 2
#define trigPin 3

long duration;
int distance;
const int ledPin = 9;
const int Bulb = 7;

unsigned long startTime;
unsigned long currentTime;
unsigned long period;

void setup()
{
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
  pinMode(ledPin, OUTPUT);
  Serial.begin(115200);
  digitalWrite (ledPin, LOW);
    while (!Serial);
  pinMode(Bulb, OUTPUT);
}

void loop()
{
  digitalWrite(trigPin, LOW);
  delayMicroseconds(1);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(1);
  digitalWrite(trigPin, LOW);
  duration = pulseIn(echoPin, HIGH);
  distance = duration * 0.034 / 2;
  Serial.print("Distance: ");
  Serial.print(distance);
  Serial.println(" cm");
  
  if ((distance < 60) && (distance > 10))
 {
  currentTime = millis();
  if (currentTime - startTime >= period)
  {
    startTime = currentTime;
    period = random(1000, 25001); //random period between 1000 and 5000 milliseconds
    digitalWrite(Bulb, !digitalRead(Bulb));
  }
 }
}

You need to detect when the distance becomes is in the the trigger range rather than when it is in the trigger range. See the StateChangeDetection example in the IDE.

When that happens, save the start time, set the output as required and start the timing

Hi there, apologies for the slow reply, I have only been able to continue with this today.

I have tried to get my head around this but I think I may have too little experience. I am no sure how to tailor the StateChangeDetection example I found to suit my needs and register when the sensor becomes in the distance zone. Would you be able to shed a little more light on this?

You know what the current distance is because you just measured it
You know what the previous distance was because you saved it last time it was read
If the previous distance was not in range and the current distance is then act on it

The idea makes sense to me, but I don't really know how I would input the current and saved distances to do so. I have been looking around and trying tomake sense of it but I am completely new to this.

Also, seeing as it would be dependent on previous and current distances, would I not need a few statements to make it work? Like for example; moving from outside distance range to within distance range runs the randomiser, no change must keep running, and moving from within distance to outside distance means stop randomiser? Would that not also leave it in a toggled state?

I don't really know how I would input the current and saved distances

You already have the distance in your code

  Serial.print("Distance: ");
  Serial.print(distance);

Yes, you will need to detect both when the object comes into range an when it goes out of range. You have the basis of this in your code too

   if ((distance < 60) && (distance > 10))

Where are you stuck ?

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.