Continous servo with Ultrasonic sensor

I was wondering if anyone might be able to offer any ideas/advice…

For my project, I am trying to use an ultrasonic sensor (Maxbotix MB1043) with a continuous rotation servo (Hitech HSR-2645CRH) and a simple rotary encoder to try to give feedback for the position to control the movement of a curtain.

Basically, i want the curtain to lower and raise in proportion (or close to that) in relation to how far away a person is standing to the sensor. For example, if the person was >15’ away, the curtain would be all the way up, if they were ~7’ away, it would be half way down, and if they were ~1’ away it would be at its lowest point. If they move closer, the curtain falls, and if they move away, the curtain raises back up…

I fully admit that im pretty weak when it comes to the coding part of arduinos (art student here). i can figure out how to make the servo rotate in one direction, but not back the other way.

My instinct tells me that i need to create some way for the arduino to “remember” a distance (or perhaps a rotary encoder value?) and then compare that to a new distance, but i really dont know how to do that. Ive tried a few things, but unfortunately, what ive tried makes the servo move a tiny bit and stop and then move a little more and stop again.

Ive written and re-written the code about a zillion times, so I’ll begin by posting a sort of bare bones version and see where you all can guide me. Any help is greatly appreciated

//NOTE Servo Full Stop at 93

#include <Servo.h>
#include <Wire.h>
#include <Adafruit_MotorShield.h>
#include "utility/Adafruit_MS_PWMServoDriver.h"

Servo myservo;  // create servo object to control a servo


//SENSOR

int sonarPin = A0; //pin connected to analog out on maxsonar sensor
int inchesAway; // inches away from the maxsonar sensor
int lastDistance;

const int clkPin = 2; //the clk attach to pin 2
const int dtPin = 3; //the dt pin attach to pin 3
const int swPin = 4 ; //the sw pin attach to pin 4

int buttonState = 0;
int encoderVal = 0;
int counter;

//////////////////////////////////////////////////////////////////////////////////////////////////////////////



void setup() {


  Serial.begin(9600);
  myservo.attach(7);  // attaches the servo on pin 9 to the servo object

  //set clkPin,dePin,swPin as INPUT
  pinMode(clkPin, INPUT);
  pinMode(dtPin, INPUT);
  pinMode(swPin, INPUT);
  digitalWrite(swPin, HIGH);

}



//////////////////////////////////////////////////////////////////////////////////////////////////////////////


void loop() {
  Serial.println(encoderVal);
  Serial.println(inchesAway);
  //   Serial.println(lastDistance);
  //   lastDistance = inchesAway;;
  inchesAway = analogRead(sonarPin) * 5 / 25.4; // converts to inches


  int change = getEncoderTurn();//
  encoderVal = encoderVal + change;
  if (digitalRead(swPin) == LOW) //if button pull down
  {
    encoderVal = 0;
  }

  if (inchesAway >= 180) {
    myservo.write(93);
  }


  if (inchesAway <= 179 && inchesAway > 168 && encoderVal != 20) {
    myservo.write(35);
    if(encoderVal = 20){
      myservo.write(93);
    }
  }

  if (inchesAway <= 168 && inchesAway > 156 && encoderVal != 40) {
    myservo.write(35);
    if(encoderVal = 40){
      myservo.write(93);
    }
  }

  if (inchesAway <= 156 && inchesAway > 144 && encoderVal != 60) {
    myservo.write(35);
    if(encoderVal = 60){
      myservo.write(93);
    }
  }

  if (inchesAway <= 144 && inchesAway > 132 && encoderVal != 80) {
    myservo.write(35);
    if(encoderVal = 80){
      myservo.write(93);
    }
  }

  if (inchesAway <= 132 && inchesAway > 120 && encoderVal != 1000) {
    myservo.write(35);
    if(encoderVal = 100){
      myservo.write(93);
    }
  }

  if (inchesAway <= 120 && inchesAway > 108 && encoderVal != 120) {
    myservo.write(35);
    if(encoderVal = 120){
      myservo.write(93);
    }
  }

  if (inchesAway <= 108 && inchesAway > 96 && encoderVal != 140) {
    myservo.write(35);
    if(encoderVal = 140){
      myservo.write(93);
    }
  }

  if (inchesAway <= 96 && inchesAway > 84 && encoderVal != 160) {
    myservo.write(35);
    if(encoderVal = 160){
      myservo.write(93);
    }
  }

  if (inchesAway <= 84 && inchesAway > 72 && encoderVal != 180) {
    myservo.write(35);
    if(encoderVal = 180){
      myservo.write(93);
    }
  }

  if (inchesAway <= 72 && inchesAway > 60 && encoderVal != 200) {
    myservo.write(35);
    if(encoderVal = 200){
      myservo.write(93);
    }
  }

  if (inchesAway <= 60 && inchesAway > 48 && encoderVal != 220) {
    myservo.write(35);
    if(encoderVal = 220){
      myservo.write(93);
    }
  }

  if (inchesAway <= 48 && inchesAway > 36) {
    myservo.write(35);
    if(encoderVal = 240){
      myservo.write(93);
    }
  }

  if (inchesAway <= 36 && inchesAway > 24 && encoderVal != 260) {
    myservo.write(35);
    if(encoderVal = 260){
      myservo.write(93);
    }
  }

  if (inchesAway <= 24 && inchesAway > 12 && encoderVal != 280) {
    myservo.write(35);
    if(encoderVal = 280){
      myservo.write(93);
    }
  }

  if (inchesAway <= 12 && inchesAway > 1 && encoderVal != 300) {
    myservo.write(35);
    if(encoderVal = 300){
      myservo.write(93);
    }
  }

// if (encoderVal == 20 || 40 || 60 || 80 || 100 || 120 || 140 || 160 || 180 || 200 || 220 || 240 || 260 || 280 || 300){
//     myservo.write(93);
//}

}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////


int getEncoderTurn(void)
{
  static int oldA = HIGH; //set the oldA as HIGH
  static int oldB = HIGH; //set the oldB as HIGH
  int result = 0;
  int newA = digitalRead(clkPin);//read the value of clkPin to newA
  int newB = digitalRead(dtPin);//read the value of dtPin to newB
  if (newA != oldA || newB != oldB) //if the value of clkPin or the dtPin has changed
  {
    // something has changed
    if (oldA == HIGH && newA == LOW)
    {
      result = (oldB * 2 - 1);
    }
  }
  oldA = newA;
  oldB = newB;
  return result;
}

A few things:

  • = and == are different. = is an assignment, == is a comparison

if(encoderVal = 20){ should be if(encoderVal == 20){

  • You may want some more slop around the encoder values as hitting exactly 20 is harder than hitting in the range 17 to 23

  • Testing for encoderVal == 20 inside a loop that can only be entered if encoderVal != 20 won’t do much.

  • If you are using a continuous-rotation servo, you will need to turn it on for a certain amount of time and then turn it off when it is at the right position. This will need some sensor (or guaranteed initial value) to know where it started from and a timer to know how long it has been running. I am not sure what size your curtain is, but a regular servo or stepper motor with a home sensor would be a much better choice

  • If you change to a regular servo, then the code could simply be myServo.write(inchesAway); with suitable scaling and offset if the servo doesn’t need to move a full 180 degrees to open the curtain.

/mike