Hi all!
My project is about managing servo motors using keypad. Only one servo can be opened at the same time. Initial state - all servos are in default state.
See small demo for details.
Everything seems easy, but:
I use Arduino Uno and decoder 74HC238.
I set control pulse using Arduino digital pin. Code here
As you can see on video, I have some noise/interference on the servos input signals.
Does someone have any ideas how to prevent this?
Also there is some problem with output signal from Demux.
When I click keypad button '2', the servos №2, 3, 5 open.
The same with keypad 4 - servo 4 and 7.
I compared binary formats, but saw no dependence.
2 -> 0010
3 -> 0011
5 -> 0101
void loop(){
// keypad start
keyboardValue = analogRead(keyboardPin); // read the keyboard value (0 - 1023)
while (keyboardValue < 25){
//do nothing until a key is pressed
keyboardValue = analogRead(keyboardPin);
servo.attach(3);
// FOR SERVO
digitalWrite(3, HIGH);
delayMicroseconds(544); // Approximately 10% duty cycle @ 1KHz
digitalWrite(3, LOW);
delayMicroseconds(20000-544);
// SERVO
//delay(50);
}//end of do nothing till a key is pressed
readkeyboard(); //get the value of key being pressed "keypressed" i.e. 0-9
// keypad end
}
OK, so we are talking here about standard radio-control model servos are we not?
I do not know why you have chosen a 74HC238. Servos are multiplexed, eight or nine at a time by using a 74HC4017 and using two control lines, reset and clock.
After resetting, you simply clock it with a series of pulses whose successive intervals correspond to the pulse values for each servo in turn. The duration of the pulse at each of the nine outputs "1" to "9" controls the respective servo.
Generally speaking, you are expected to pulse every servo at least every 20 ms, so you do not just feed pulses to only one to the exclusion of others. If not pulsed regularly, servos may fail to hold their position.
Paul__B:
OK, so we are talking here about standard radio-control model servos are we not?
I`m not sure I understand what do you mean. I try to implement locks which could be opened by special combination on the key pad.
Ex: I click btn 8 -> lock 8 opens and closes in a minute.
btn 2 -> lock 2 opens and closes in a minute.
Paul__B:
I do not know why you have chosen a 74HC238. Servos are multiplexed, eight or nine at a time by using a 74HC4017 and using two control lines, reset and clock.
As I understand this counter allows to operate all locks in the same time. They just pass ''1" in series: one after another. But I don`t need this. I guess my demo attached is pretty clear. Tell me please, if not.
Thanks.
Full code here:
#include <SPI.h>
#include <LiquidCrystal.h>
#include <Servo.h>
LiquidCrystal lcd(10);
Servo servo;
char keypressed = 0;
int keyboardPin = 0; // Analog input pin that the keypad is attached to
int keyboardValue = 0; // value read from the keyboard
//int pincodeSize = 4,
int numCount = 0;
char pincode[4];
//int presses = 2;
byte pins[] = {8,7,5};
int state;
void setup(){
Serial.begin(9600); //hardware serial to PC
// setup LCD number of columns ans rows
lcd.begin(16, 2);
// print message on LCd
lcd.print("Enter the pin:");
lcd.setCursor(0,1);
// demux
pinMode(8, OUTPUT);
pinMode(7, OUTPUT);
pinMode(5, OUTPUT);
//pinMode(2, OUTPUT);
digitalWrite(8, LOW);
digitalWrite(7, LOW);
digitalWrite(5, LOW);
// DEMUX E3
digitalWrite(3, HIGH);
}
void loop(){
// keypad start
keyboardValue = analogRead(keyboardPin); // read the keyboard value (0 - 1023)
while (keyboardValue < 25){
//do nothing until a key is pressed
keyboardValue = analogRead(keyboardPin);
servo.attach(3);
digitalWrite(3, HIGH);
delayMicroseconds(544); // Approximately 10% duty cycle @ 1KHz
digitalWrite(3, LOW);
delayMicroseconds(20000-544);
//delay(50);
}//end of do nothing till a key is pressed
readkeyboard(); //get the value of key being pressed "keypressed" i.e. 0-9
// keypad end
}
void OpenServo(int key){
Serial.println("key");
Serial.println(key);
/* convert presses to binary and store it as a string */
//key=1 && key=0;
key=key-1;
String binNumber = String(key, BIN);
/* get the length of the string */
int binLength = binNumber.length();
/*if(binLength==1){
binNumber ="00"+binNumber;
}
else if(binLength==2){
binNumber ="0"+binNumber;
}*/
Serial.println("binNumber");
Serial.println(binNumber);
//Serial.println("binNumber");
// Serial.println(binNumber);
if(key <= 255) { // if we have less or equal to 255 presses
// here is the scary code
for(int i = 0, x = 1; i < binLength; i++, x+=2) {
if(binNumber[i] == '0') state = LOW;
if(binNumber[i] == '1') state = HIGH;
digitalWrite(pins[i], state);
}
}
}
void LcdClearLine(int r)
{
lcd.setCursor(0, r);
for (int ii = 0; ii < 16; ii = ii + 1) {
lcd.print(" ");
}
}
//read the keyboard routine
void readkeyboard(){
keyboardValue = analogRead(keyboardPin); // read the value (0-1023)
if (keyboardValue <25){keypressed = 0;}
if ((keyboardValue >25) && (keyboardValue < 67)){keypressed = '1';}
if ((keyboardValue >67) && (keyboardValue < 108)){keypressed = '2';}
if ((keyboardValue >108) && (keyboardValue < 162)){keypressed = '3';}
if ((keyboardValue >162) && (keyboardValue < 253)){keypressed = '4';}
if ((keyboardValue >253) && (keyboardValue < 361)){keypressed = '5';}
if ((keyboardValue >361) && (keyboardValue < 479)){keypressed = '6';}
if ((keyboardValue >479) && (keyboardValue < 619)){keypressed = '7';}
if ((keyboardValue >619) && (keyboardValue < 765)){keypressed = '8';}
if ((keyboardValue >765) && (keyboardValue < 819)){keypressed = '9';}
if ((keyboardValue >819) && (keyboardValue < 889)){keypressed = '*';}
if ((keyboardValue >889) && (keyboardValue < 938)){keypressed = '0';}
if (keyboardValue >938){keypressed = '#';}
//NOTE: the values used above are all halfway between the value obtained with each keypress in previous test sketch
while (keyboardValue > 25) {
//delay (100);
keyboardValue = analogRead(keyboardPin); // read the value (0-1023)
}//wait until key no longer being pressed before continuing
switch (keypressed) {
case '#':
Serial.println("ENTER");
LcdClearLine(0);
lcd.setCursor(0, 0);
lcd.print("Welcome");
lcd.setCursor(0, 1);
LcdClearLine(1);
// send pin to server to validate
break;
case '*':
Serial.println("RESET");
// clean entered pincode
numCount = 0;
//pincode = char[4];
LcdClearLine(0);
lcd.setCursor(0, 0);
lcd.print("Enter the pin:");
LcdClearLine(1);
lcd.setCursor(0, 1);
break;
default:
//if(numCount != 4){
pincode[numCount] = (char) keypressed;
Serial.println("NUM");
lcd.write(keypressed);
OpenServo(keypressed- '0');
numCount++;
//}
}
Serial.println(keypressed); // print the value back to the Serial view window on your PC
// delay(1000); // wait 1000 milliseconds before the next loop
}
//end of read the keyboard routine
They operate by being fed a continuousstream of pulses whose length varies between 1 and 2 ms, with 1.5 ms corresponding to a "centre" position.
happyBanshee:
As I understand this counter allows to operate all locks in the same time. They just pass ''1" in series: one after another. But I don`t need this.
I think you do need to control all servos at the same time and therefore explained how to do it most efficiently. If you do not send control pulses to a servo, it ceases to hold its position against forces tending to move it. This may not matter if the friction in the mechanism is sufficient to prevent further movement, but if you only address one servo at a time, there is nothing to prevent the others drifting or being moved by external pressure.
happyBanshee:
I guess my demo attached is pretty clear. Tell me please, if not.
Without examining it in too much detail, it is pretty clear that you are only controlling and holding the position of one servo at any one time. They may also "glitch" each time you start feeding them pulses
I have no idea what the code in Reply #5 is supposed to do. It seems to be a complete bird's nest with, for example, code about keyboard IFs all over the place. There are delay()s and blocking WHILEs all over the place.
The function OpenServo() doesn't have a single reference to a servo within it.
Well, looks like I still miss something, I can not understand the logic.
I tried the example with Aduino and 74HC4017. I used code attached there, but I got this result .
In the example the Mega is used, but I need Uno. So, mayb I need update the code somehow.
Help me please. My wild guessing drives me crazy.
What is precision_loop() supposed to do ?
Why does a loop need precision ?
Why not just rely on the standard loop() function ?
I see this line
keyboardValue = analogRead(keyboardPin);
in at least three four places. It would make a lot more sense to read the value once and use that everywhere. As it is the value you act on may not be within the bounds you want it to be.
My overall impression is that the code is more complicated than necessary.
I haven't read the code, just scrolled through #14, so you're probably wondering why I feel qualified to comment. Anyways, read on...
Have you considered isolating the problem to it's bare minimum ?
As in remove all other clutter and functionality until you have a bare bones representation of what you need to achieve and can say something like "all I want to happen is when X is Y that K does U", and all there is in the program is X,Y,K,U. This is opposed to "here I have ABCDARQ%^!KAAJHIG, and I want it to ~#@ and TY^, but I'm not sure about why KUI(* does %^TRD sometimes, is that correct? or should 4efE sometimes, I'm a noob, help"
This will help in two regards:
You might just find the error was related to some of the clutter (conflicting libraries, code error etc.)
People on this forum will be much (mu****ch__!) more inclined to both look at your code and here's the kicker: SOLVE it
Forget the LCD
Forget the keypad
Test your Servo mux/demux thingy with hardcoded TEST inputs
Solve that.
Move onto LCD and keypad
TEST that, make sure that the output of that is represented as the same variable type as the input to the servo stuff
Have you considered using a device already designed for this purpose, removes the processing requirements off the Arduino, already on a circuit board, and has a working library?
happyBanshee:
Ok, I reduce my code, remove extra lines.
You have produced a new program but you have not told us what it does and what you want it to do. Have you tried to make it control a single servo ?
There is an enormous amount of common sense in the advice @1:1 has given in Reply #15.
Get each part of your problem sorted out on its own with the shortest possible program. When all the parts work, then you can start joining them together. That's why I posted the link to planning and implementing a program in Reply #7
Also, please don't ignore comments and questions that people make in an attempt to help you.