Adjusting simple (so it should be) shift register coding for a different result

Hi y'all.

I am using basic basic coding which I took from the examples section in the arduino app, but am not sure how to achieve desired result.

I put together the knob and shift register sketches in the examples to control the speed and direction of a servo (modified for continuous rotation) and eight LEDs. I would like to sync the LEDs to be more of a reflection of the servo status. I know the code can be easily changed or modified to do this, but I am confused by the different options. Also, wondering if it's even possible, if it would be better to have the shift register/LEDs read from the servo position rather than the pot.

As it is right now, with the knob turned all the way left, the servo runs at full speed and slows down as the knob turns right toward its center position where the servo changes direction and picks up speed as the knob continues to the farthest right position. This is fine, though it would be nice to have a finer resolution incrementally.

However, the LEDs, which begin off with the knob turned all the way left, increase in number (0-8) until the knob is turned all the way right, with half the LEDs lit when knob and servo are midway.

Goal: I would like the LEDs to light all the way (1-8) with the speed of the servo and reverse as the servo slows down and reverses. I know that may involve mods to the INT or FOR and putting in something that has -- in contrast to the ++, but I have been unsuccessful in my experimentation. I am new at this arduino stuff. Any advice will be great. Thanks much.

Here is my current sketch:

 #include <Servo.h>
 
int potPin = 0;
int servoPin = 9;
Servo servo;
int latchPin = 5;
int clockPin = 6;
int dataPin = 4;
 
int leds = 0;
 
void setup() 
{
  pinMode(latchPin, OUTPUT);
  pinMode(dataPin, OUTPUT);  
  pinMode(clockPin, OUTPUT);
  servo.attach(servoPin);
}
 
void loop() 
{
  int reading  = analogRead(potPin);   // 0 to 1023
  int angle = reading / 6;  //0 to 100-ish
  servo.write(angle);
  int numLEDSLit = reading / 114;  //1023 / 9
  leds = 0;
  for (int i = 0; i < numLEDSLit; i++)
  {
    bitSet(leds, i); 
  }
  updateShiftRegister();
}
 
void updateShiftRegister()
{
   digitalWrite(latchPin, LOW);
   shiftOut(dataPin, clockPin, LSBFIRST, leds);
   digitalWrite(latchPin, HIGH);
}

So do you want the LEDs to go like this as you rotate the knob from 0 to full.

********  // fast anti-CW
-*******
--******
---*****
----****
-----***
------**
-------*
--------  // stop
-------*
------**
-----***
----****
---*****
--******
-*******
******** // fast CW

Rob

Yes, exactly.

vjpcat:

Try:

 #include <Servo.h>
 
int potPin = 0;
int servoPin = 9;
Servo servo;
int latchPin = 5;
int clockPin = 6;
int dataPin = 4;
int leds = 0;
 
void setup() {
  pinMode(latchPin, OUTPUT);
  pinMode(dataPin, OUTPUT);  
  pinMode(clockPin, OUTPUT);
  servo.attach(servoPin);
}
 
void loop(){
  int reading  = analogRead(potPin);   // 0 to 1023
  int angle = reading / 6;  //0 to 100-ish
  servo.write(angle);
  int numLEDSLit = reading / 228;  //You only want max. 4 LEDs lit.
  leds = 0;
  if (angle >= 55){  //positive half of turn
    for (int i = 4; i < (numLEDSLit+4); i++){
       bitSet(leds, i);    // lights LEDs 4 to 7
    }
  }
  else if (angle<=45){  //negative half of turn
    for (int i = (numLEDSLit -1) ; i >-1; i--){
       bitSet(leds, i);
    }     // lights LEDs 3 to 0
 }
// angles between 46 and 54 (centre of turn) will have no LEDs lit
updateShiftRegister();
}
 
void updateShiftRegister(){
   digitalWrite(latchPin, LOW);
   shiftOut(dataPin, clockPin, LSBFIRST, leds);
   digitalWrite(latchPin, HIGH);
}

Also look at the map function.

Hi y'all. It's been a while since i worked on this project, but it's in front of me again. i did try the suggested code adjustments and struggled with my lack of experience and knowledge in these areas however, I was able to get a basic set up running for the time being.

It has been so long since i looked at this code and stuff, I am having to relearn everything so far all over again. I have been experimenting quite a bit more though which may have only made things worse as I've tangentted off into too many directions.

So, here I am, just trying to make an led level meter which shows the position/direction of my continuous rotation servo controlled by potentiometer.

I have eliminated the shift register and switched to the map function, but as before, I can only get the leds to light in a straight sequence. I have problems understanding which parts of code to change and to what sometimes, so i come up with so many ways to resolve it, but then don't know the best way to execute. i am currently wondering if i should treat the two different directions of the servo should be mapped to two different led arrays - thoughts anyone?

here is my code:

#include <Servo.h> 

// these constants won't change:
const int analogPin = A0;   // the pin that the potentiometer is attached to
const int ledCount = 7;    // the number of LEDs in the bar graph
const int servoPin = 3;
Servo servo;

int ledPins[] = { 
  7,8,9,10,11,12,13 };   // an array of pin numbers to which LEDs are attached


void setup() {
  // loop over the pin array and set them all to output:
  for (int thisLed = 0; thisLed < ledCount; thisLed++) {
    pinMode(ledPins[thisLed], OUTPUT);
   servo.attach(servoPin); 
  }
}

void loop() {
  // read the potentiometer:
  int sensorReading = analogRead(analogPin);
  // map the result to a range from 0 to the number of LEDs:
  int ledLevel = map(sensorReading, 0, 1023, 0, ledCount);
  int angle = sensorReading / 6;
  servo.write(angle);

  // loop over the LED array:
  for (int thisLed = 0; thisLed < ledCount; thisLed++) {
    // if the array element's index is less than ledLevel,
    // turn the pin for this element on:
    if (thisLed < ledLevel) {
      digitalWrite(ledPins[thisLed], HIGH);
    } 
    // turn off all pins higher than the ledLevel:
    else {
      digitalWrite(ledPins[thisLed], LOW); 
    }
  }
}

Goal: I would like the LEDs to light all the way (1-8) with the speed of the servo and reverse as the servo slows down and reverses.

Firstly, I would use an odd number of LEDs so that the centre one is lit even when the servo is stationary. In fact, it would always be lit. Instead of looking at the speed of the servo, it would be easier to determine how far away from it's target position it is. You know the position it's in (= the current position). Lets call it curPos. And you know the position you want it to go to (= target position). Lets call it tarPos. If curPos < tarPos the servo will be going forwards and if curPos > tarPos the servo will be going backwards. tarPos - curPos will give you the distance to be moved forwards and curPos - tarPos will give you the distance to be moved backwards, so you can calculate the number of LEDs to be lit. You'll need to update curPos as the servo moves nearer to the target position. When curPos == tarPos all the LEDs, except the centre one, will be off. You could use a tricolour LED for the centre one and have it showing white when the servo is stationary and red when it's moving.
If you agree that that is the way you want it to go, we can start thinking about the programming.

Yes, Henry, that is very much the way it should go. In fact, if you look at my most recent coding attempt which I included in my earlier post today, I have changed the LED count to 7 (though would like to make it 9) and have actually been using a different color for the center led than the rest which were split into two colors, one for each direction. I had even pondered using a tricolor LED for the center, but thought I should at least get the main code down before incorporating yet more complex scenarios. I seem to have the hardest time combining the various example sketches I borrow from, to work all together, much less simply modifying the single examples themselves which can be confusing enough to me.

Anyway so, yes, I do agree with your idea mostly however, I think I would prefer to have the LEDs stay lit as they increase towards their respective direction and likewise, to turn off as they return towards the center position.

For example, with 9 LEDs total, there would be four steps in each direction away from the center LED. If the knob is turned all the way left, the servo will be rotating at its max speed backwards, so the center LED and all the LEDs to the left of center, will be lit. As the knob is turned to the right from that position, the LEDs left of center, will gradually each turn off as the position moves closer towards the center. As the knob turns to the right, passing the center, the LEDs to the right of center will each turn on incrementally as the position moves farther to the right until the knob has reached its max forward position when all LEDs right of center will be lit.

Does that make sense? If so, and it is doable, would it be easier to adapt the code I have been working with or is it best to just scrap that code and start over with a fresh sketch?

You are asking about the speed of the servo and I'm talking about the position of it. Two different things. The speed of the servo will be very difficult to detect. Knowing the position of it will be a lot easier and give you similar results. If you want to use the speed, then I'm unable to help you, as I don't know how to detect when a servo's speed varies. I don't know if that is even possible.

The way I see it is:
If the servo and pot are in the centre position, only the centre light will be on. Turn the pot fully to the right and all the right-hand LEDs come on and incrementally go out as the servo turns to the right. When the servo is fully to the right, only the rightmost LED will be on. Turning the pot fully to the left from this position will light all the LEDs and these will incrementally go out as the servo moves to the left, leaving only the leftmost LED on when the servo reaches the end of its travel. Any position that the servo stops between its limits will be shown (approximately, unless you have 180 LEDs :slight_smile: ) by which LED is lit.

So you will have a position indicator, which will also show you how far the servo (if it's moving) has to travel before it reaches the set position. How does that sound to you?

There's no point in doing any coding until you've got the parameters set correctly. You don't start driving until you know where you're heading for, even if you don't know the route you need to take. Otherwise you could end up driving 100 miles when you only want to go next door.

Ok, I see your point regarding position, but I am confused then by what the Arduino reference says for certain functions in the Servo library in terms of a continuos rotation servo, such as 'write' which is described:

write()

Description

Writes a value to the servo, controlling the shaft accordingly. On a standard servo, this will set the angle of the shaft (in degrees), moving the shaft to that orientation. On a continuous rotation servo, this will set the speed of the servo (with 0 being full-speed in one direction, 180 being full speed in the other, and a value near 90 being no movement).

So, is speed then an incidental outcome of changing the position? I find the description above to mean that speed can be used synonymously as position if the servo has continuos rotation.

Regardless although I prefer to have a full grasp of the varying terms, is it possible for the LEDs to light on incrementally, as they go off incrementally? I feel I was not clear enough in posing my new question.

Let's say the position is centered and only the center LED is lit. As the knob is turned left or right (the position moves away from center) the LEDs would incrementally light on (in direction knob is turned) and remain on, as they move towards the far left or right (target position?). Upon arriving at the far left or right, five LEDS will be lit (center and four to the left or right of center) and then incrementally turn off as position is returned to center where only the one center LED will remain lit.

I apologize for further complicating, but I just want to clarify as best I can. I feel like I've driven hundreds of miles to get across the street.

vjpcat:
Ok, I see your point regarding position, but I am confused then by what the Arduino reference says for certain functions in the Servo library in terms of a continuos rotation servo, such as 'write' which is described:

write()

Description

Writes a value to the servo, controlling the shaft accordingly. On a standard servo, this will set the angle of the shaft (in degrees), moving the shaft to that orientation. On a continuous rotation servo, this will set the speed of the servo (with 0 being full-speed in one direction, 180 being full speed in the other, and a value near 90 being no movement).

So, is speed then an incidental outcome of changing the position? I find the description above to mean that speed can be used synonymously as position if the servo has continuos rotation.

What that is saying is you can make a continuous servo turn clockwise, anticlockwise or stop. Sending an intermediate value, e.g. 120, would turn the servo more slowly, but it's speed would not change once set. Nothing to do with its position. But you're not using a continuous rotation servo!

Regardless although I prefer to have a full grasp of the varying terms, is it possible for the LEDs to light on incrementally, as they go off incrementally? I feel I was not clear enough in posing my new question.

Let's say the position is centered and only the center LED is lit. As the knob is turned left or right (the position moves away from center) the LEDs would incrementally light on (in direction knob is turned) and remain on, as they move towards the far left or right (target position?). Upon arriving at the far left or right, five LEDS will be lit (center and four to the left or right of center) and then incrementally turn off as position is returned to center where only the one center LED will remain lit.

I apologize for further complicating, but I just want to clarify as best I can. I feel like I've driven hundreds of miles to get across the street.

We're almost there. One minor point to clear up. Do you want the LEDs to follow the position of the knob (immediate) or the position of the servo (delayed by the time it takes the servo to reach its position). Either can be incremental.

Ah, but I am using a continuous rotation servo. Do my questions make a little more sense now?

I think the LEDs should reflect the servo, do you agree?

Ah, but I am using a continuous rotation servo. Do my questions make a little more sense now?

I think the LEDs should reflect the servo, do you agree?

No, they do not. No, I do not.

Do you expect the LEDs to reflect the position of the servo? If so, which position, when? The servos are not commanded to go to a position, so reflecting the position makes no sense.

Therefore, you must mean that you want the LEDs to reflect the speed of the servo, but that doesn't make sense.

Ok, then let's skip the questions regarding position and speed.

I have been tweaking the combined sketches I have put together and am almost satisfied with the outcome except for one thing, which I am unsure how to deal with and that is when 'angle' is between around 94 to 113, led pins 13,12,11,10 are all lit and should be off.

I think it has something to do with one of the for loops - either in setup or the one at the beginning of the loop, but can't figure out what to do to fix it, so any help here would be appreciated. Anything else will not be necessary. Thank you.

Following is my latest version of this sketch as referenced above:

#include <Servo.h>

// these constants won't change:
const int analogPin = A0; // the pin that the potentiometer is attached
const int ledCount = 9; // to the number of LEDs in the bar graph
const int servoPin = 3;
Servo servo;

int ledPins[] = {
13,12,11,10,9,8,7,6,5 }; // an array of pin numbers
//to which LEDs are attached

void setup() {
// initialize serial communication at 9600 bits per second:
Serial.begin(9600);
// loop over the pin array and set them all to output:
for (int thisLed = 0; thisLed < ledCount; thisLed++) {
pinMode(ledPins[thisLed], OUTPUT);
servo.attach(servoPin);
}
}

void loop() {
// read the potentiometer:
int sensorReading = analogRead(analogPin);
// map the result to a range from 0 to the number of LEDs:
int ledLevel = map(sensorReading, 0, 1023, 0, ledCount);
int angle = sensorReading / 6;
Serial.println(angle); // print out the value you read
delay(1); // delay in between reads for stability
servo.write(angle);

if (angle >=95){
// loop over the LED array:
for (int thisLed = 0; thisLed <= ledCount; thisLed++) {
// turn the pin for this element on:
if (thisLed < ledLevel) {
digitalWrite(ledPins[thisLed], HIGH);
}
// turn off all pins higher than the ledLevel:
else {
digitalWrite(ledPins[thisLed], LOW);
}
}
}
else if (angle <=85){
// loop over the LED array:
for (int thisLed = 4; thisLed > -5; thisLed--) {
// turn the pin for this element on:
if (thisLed > ledLevel-1) {
digitalWrite(ledPins[thisLed], HIGH);
}
// turn off all pins higher than the ledLevel:
else {
digitalWrite(ledPins[thisLed], LOW);
}
}
}
}

  for (int thisLed = 0; thisLed < ledCount; thisLed++) {
    pinMode(ledPins[thisLed], OUTPUT);
   servo.attach(servoPin);
  }

How many times do you need to attach the servo?
How many times do you need to attach the servo?
How many times do you need to attach the servo?
How many times do you need to attach the servo?
How many times do you need to attach the servo?
How many times do you need to attach the servo?
How many times do you need to attach the servo?
How many times do you need to attach the servo?
How many times do you need to attach the servo?

when 'angle' is between around 94 to 113, led pins 13,12,11,10 are all lit and should be off.

A value of angle of 95 or more means that the potentiometer reading was 570 or more. That means that ledLevel will be 4 or more.

  for (int thisLed = 4; thisLed > -5; thisLed--) {
    // turn the pin for this element on:
    if (thisLed > ledLevel-1) {
      digitalWrite(ledPins[thisLed], HIGH);
    }
    // turn off all pins higher than the ledLevel:
    else {
      digitalWrite(ledPins[thisLed], LOW);
      }
    }

When thisLed (dumb name) is an index into an array, it makes NO sense for the range of values to be anything other than 0 to ledCount. You are iterating with thisLed equal to 4, 3, 2, 1, 0, -1, -2, -3, and -4, and then reading from 4 undefined positions in the array.

Since ledLevel is 4 or more, ledLevel -1 will be 3 or more. So, you are turning the pin at position 4 in the array (13) on. You are then turning the pins at positions 3, 2, 1, 0, -1, -2, -3, and -4 off. Since the pins at positions -1, -2, -3, and -4 are undefined, who knows what pins you just diddled with.