Go Down

Topic: Help running servo using encoder (Read 1 time) previous topic - next topic

poxusa

Hello. I am building a simple ruler using ALPS STEC12E08 encoder, regular 5V servo, and 20x4 LCD. I have adapted code from other websites and users and using for my project. The problem the lcd is displaying the correct values, but I do not know how to implement the servo into the project. I need the servo to spin corresponding to the encoder value. So for example, if you spin encoder and it says one, servo should move one degree to whatever side you have spinned the encoder. PLease help me implement the servo into the project. Thank you.
Code: [Select]
#include <LiquidCrystal.h>
#include <Servo.h>
#define ENC_A 14
#define ENC_B 15
#define ENC_PORT PINC

// Connections:
// rs (LCD pin 4) to Arduino pin 12
// rw (LCD pin 5) to Arduino pin 11
// enable (LCD pin 6) to Arduino pin 10
// LCD pin 15 to Arduino pin 13
// LCD pins d4, d5, d6, d7 to Arduino pins 5, 4, 3, 2
LiquidCrystal lcd(12, 11, 10, 5, 4, 3, 2);
//Servo myservo;  // create servo object to control a servo
// a maximum of eight servo objects can be created

int backLight = 13;    // pin 13 will control the backlight
//int pinMode = 0;  // analog pins 0 and 1 used to connect encoder
//int pos = 0;  //variable to read the value from analog pins


void setup() //code to execute once at the beginning
{
// myservo.attach(9);  // attaches the servo on pin 9 to the servo object
 pinMode(ENC_A, INPUT);
 digitalWrite(ENC_A, HIGH);
 pinMode(ENC_B, INPUT);
 digitalWrite(ENC_B, HIGH);
 Serial.begin (115200);
 Serial.println("Start");
 pinMode(backLight, OUTPUT); // LCD Code begins
 digitalWrite(backLight, HIGH); // turn backlight on. Replace 'HIGH' with 'LOW' to turn it off.
 lcd.begin(16,2);              // columns, rows.  use 16,2 for a 16x2 LCD   lcd.clear();                  // start with a blank screen
 lcd.setCursor(0,0);           // set cursor to column 0, row 0 (the first [size=10][/size]row)
 lcd.print("Paul Ulezko Ruler");    // change this text to whatever you like. keep it clean.
 //lcd.setCursor(0,1);           // set cursor to column 0, row 1
 //lcd.print("Lab 4 Ruler");
 
 // if you have a 4 row LCD, uncomment these lines to write to the bottom rows
 // and change the lcd.begin() statement above.
 //lcd.setCursor(0,2);         // set cursor to column 0, row 2
 //lcd.print("Row 3");
 //lcd.setCursor(0,3);         // set cursor to column 0, row 3
 //lcd.print("Row 4");
}

void loop() //executed over and over again
{
 static uint8_t counter = 0;      //this variable will be changed by encoder input
int8_t tmpdata;
/**/
 tmpdata = read_encoder();
 if( tmpdata ) {
   Serial.print("Counter value: ");
   Serial.println(counter, DEC);
   counter += tmpdata;
   lcd.setCursor(0,1);           // set cursor to column 0, row 1
   lcd.print("Counter value: ");
   lcd.setCursor(0,2);         // set cursor to column 0, row 2
   lcd.print(counter, DEC);
 
  }
}
 
/* returns change in encoder state (-1,0,1) */
int8_t read_encoder()
{
 int8_t enc_states[] = {0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0};
 static uint8_t old_AB = 0;
 /**/
 old_AB <<= 2;                   //remember previous state
 old_AB |= ( ENC_PORT & 0x03 );  //add current state
 return ( enc_states[( old_AB & 0x0f )]);
}

PaulS

The first thing you need to decide is what will happen when the encoder goes over 179 (or whatever the upper limit on your servo is) or below 0.

If you set the servo position to counter in your code, and constrain (http://arduino.cc/en/Reference/Constrain) the servo position, you will be able to simply Servo::write() the value to the servo.

poxusa

I have tried implementing the suggested, however, the counter numbers are not diplaying from 1 to 255 anymore and the servo begins to infinite spinning when I turn encoder knob.
Code: [Select]
#include <LiquidCrystal.h>
#include <Servo.h>
#define ENC_A 14
#define ENC_B 15
#define ENC_PORT PINC

// Connections:
// rs (LCD pin 4) to Arduino pin 12
// rw (LCD pin 5) to Arduino pin 11
// enable (LCD pin 6) to Arduino pin 10
// LCD pin 15 to Arduino pin 13
// LCD pins d4, d5, d6, d7 to Arduino pins 5, 4, 3, 2
LiquidCrystal lcd(12, 11, 10, 5, 4, 3, 2);
Servo myservo;  // create servo object to control a servo
// a maximum of eight servo objects can be created

int backLight = 13;    // pin 13 will control the backlight
//int pinMode = 0;  // analog pins 0 and 1 used to connect encoder
int sensVal = 0;  //variable to read the value from analog pins
int val = 0;


void setup() //code to execute once at the beginning
{
 myservo.attach(8);  // attaches the servo on pin 9 to the servo object
 pinMode(ENC_A, INPUT);
 pinMode(ENC_A, INPUT);
 digitalWrite(ENC_A, HIGH);
 pinMode(ENC_B, INPUT);
 digitalWrite(ENC_B, HIGH);
 Serial.begin (115200);
 Serial.println("Start");
 pinMode(backLight, OUTPUT); // LCD Code begins
 digitalWrite(backLight, HIGH); // turn backlight on. Replace 'HIGH' with 'LOW' to turn it off.
 lcd.begin(20,4);              // columns, rows.  use 16,2 for a 16x2 LCD, etc.
 lcd.clear();                  // start with a blank screen
 lcd.setCursor(0,0);           // set cursor to column 0, row 0 (the first row)
 lcd.print("Paul Ulezko Ruler");    // change this text to whatever you like. keep it clean.
 //lcd.setCursor(0,1);           // set cursor to column 0, row 1
 //lcd.print("Lab 4 Ruler");
 
 // if you have a 4 row LCD, uncomment these lines to write to the bottom rows
 // and change the lcd.begin() statement above.
 //lcd.setCursor(0,2);         // set cursor to column 0, row 2
 //lcd.print("Row 3");
 //lcd.setCursor(0,3);         // set cursor to column 0, row 3
 //lcd.print("Row 4");
}

void loop() //executed over and over again
{
 static uint8_t counter = 0;      //this variable will be changed by encoder input
int8_t tmpdata;
/**/
 tmpdata = read_encoder();
 if( tmpdata ) {
   Serial.print("Counter value: ");
   Serial.println(counter, DEC);
   counter += tmpdata;
   lcd.setCursor(0,1);           // set cursor to column 0, row 1
   lcd.print("Counter value: ");
   lcd.setCursor(0,2);         // set cursor to column 0, row 2
   lcd.print(counter, DEC);
  // sensVal = constrain(sensVal, 10, 150);
   val = digitalRead(ENC_A);    // reads the value of the eno (value between 0 and 1023)
   val = digitalRead(ENC_B);
   val = constrain(val, 10, 180);
   //val = map(val, 0, 1023, 0, 179);     // scale it to use it with the servo (value between 0 and 180)
   myservo.write(val);                  // sets the servo position according to the scaled value
   delay(15);                           // waits for the servo to get there

 
  }
}
 
/* returns change in encoder state (-1,0,1) */
int8_t read_encoder()
{
 int8_t enc_states[] = {0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0};
 static uint8_t old_AB = 0;
 /**/
 old_AB <<= 2;                   //remember previous state
 old_AB |= ( ENC_PORT & 0x03 );  //add current state
 return ( enc_states[( old_AB & 0x0f )]);
}

PaulS

Code: [Select]
   val = digitalRead(ENC_A);    // reads the value of the eno (value between 0 and 1023)
   val = digitalRead(ENC_B);
   val = constrain(val, 10, 180);
   //val = map(val, 0, 1023, 0, 179);     // scale it to use it with the servo (value between 0 and 180)
   myservo.write(val);                  // sets the servo position according to the scaled value

The first digitalRead function returns HIGH (1) or LOW(0). The second one does the same, overwriting the value in val.

Constrain then always returns 10.

Quote
and the servo begins to infinite spinning

Then, you haven't got a servo. You have an electric motor in a servo housing. That is not what you said you had up front.

poxusa

I am using Vex motor module and it has signal wire (PWM), power, and ground.

AWOL

Quote
it has signal wire (PWM),

If it really is PWM, then feeding it PPM from the servo library isn't going to give good results.
PPM is effectively very low duty-cycle (5 - 10%) PWM.

Can you post the specs of the "Vex motor module", please?
"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

poxusa

Technical Specifications.Kit Contents (1)VEX continuous rotation motor
(1)VEX motor gear set (4 total gears, 1 replacement for each gear inside)
(2)6-32 x 1/4" Screws
(2)6-32 x 1/2" Screws
(1)Clutch
(1)Clutch Post
(1)Inventor's Guide Insert

Downloads & Docs Inventor's Guide - Motor
Inventor's Guide - Motion
VEX Robot Speed Chart - Spur Gear Reductions
VEX Robot Speed Chart - Chain Reductions
VEX Robot Speed Chart - High Strength Chain Reductions
Compatibility All VEX Microcontrollers.
All VEX Square Shafts 0.125" (3.2mm)  
Specifications Free Speed:100 rpm @ 7.5 volts
Stall Torque:6.5 in-lbs
Voltage:4.4 - 9.1 Volts (Motor life will be reduced operating outside this range)
PWM Input:1ms - 2ms will give full reverse to full forward, 1.5ms is neutral
Dead Band:1.47ms - 1.55m
Black Wire:Ground
Orange Wire:Power
White Wire:PWM signal

Note: Performance varies slightly due to variations in manufacturing.  
Weight Motor0.096 lbs (43.5 grams)
6-32x1/4" Screw0.0014 lbs (0.617 grams)
6-32x1/2" Screw0.00209 lbs (0.948 grams)
Clutch0.007 lbs (3.17 grams)
Actual weight one item (no packaging)

http://www.vexrobotics.com/products/accessories/motion/276-2163.html

poxusa

After working a whole day on this project's code, I somewhat figure out the problem. The anlaog value from the encoder had to be sent to the Vex motor module. However, even so the servo moves to the encoder without infinite loop anymore, it still has huge values due to the code bellow. Special thanks to who tried to help me.
Code: [Select]
pulse = map(analogValue,0,1023,minPulse,maxPulse);

Go Up