Go Down

Topic: encoder (Read 16 times) previous topic - next topic

mem

Could you post the entire sketch so I can see where val is set.

mingki

yep, of course.
Code: [Select]
 
#define encoder0PinA  2
#define encoder0PinB  4

volatile unsigned long encoder0Pos = 0;
int startCount;
int steps;
int val = 0;            
int arduino_digitalpin = 3;                                

void setup()                      
{
 pinMode (arduino_digitalpin, OUTPUT);    
 pinMode(encoder0PinA, INPUT);
 digitalWrite(encoder0PinA, HIGH);      
 pinMode(encoder0PinB, INPUT);
 digitalWrite(encoder0PinB, HIGH);      

 attachInterrupt(0, doEncoder, CHANGE);  
 Serial.begin (9600);
 Serial.println("start");                
 startCount = encoder0Pos;
}

void loop(){
 steps = analogRead(0) / 25;        
 if (val > 1 && val < 20)
 {
   if(encoder0Pos > startCount + steps){  
     startCount = encoder0Pos;
     digitalWrite(3, HIGH);
     delay(1000);
     digitalWrite(3, LOW);
     delay(1000);
   }
 }
}

void doEncoder(){
 if (digitalRead(encoder0PinA) == HIGH) {  
   if (digitalRead(encoder0PinB) == LOW) {  
     // encoder is turning
     encoder0Pos = encoder0Pos - 1;        
   }
   else {
     encoder0Pos = encoder0Pos + 1;        
   }
 }
 else                                        
 {
   if (digitalRead(encoder0PinB) == LOW) {  
   
     encoder0Pos = encoder0Pos + 1;          
   }
   else {
     encoder0Pos = encoder0Pos - 1;          
   }

 }
 Serial.println (encoder0Pos, DEC);          
 }

mingkimingki@gmail.com

mem

#47
Feb 10, 2008, 06:33 am Last Edit: Feb 10, 2008, 06:38 am by mem Reason: 1
val is not being set. remove the declaration of val (its just causing confusion)  and replace val in your code with steps. (the variable steps is set by the pot in the first line of code in your loop and holds the number of count steps necessary to trigger the led)

mingki

#48
Feb 10, 2008, 09:43 am Last Edit: Feb 10, 2008, 09:47 am by mingki Reason: 1
i know it's very confusing to understand my project.
the reason why i use two arduino is because i thought i could use HIGH state of digital pins acting like a switch which triggers the encoder to count untill certain steps since HIGH state will last just for a short period(using delay function).
so, i wanted to use HIGH state as a commend to second arduino so that it count encoder's steps for a designated amount and get HIGH on digital pin #13.
i think the following sketch has the most closest function i have in mind.
It has only one small aspect that is different from what i want it to do.
void loop(){
val = digitalRead(3);
if (val == HIGH && encoder0Pos > startCount + 512)
{
startCount = encoder0Pos;        
digitalWrite(13, HIGH);    
delay(1000);    
if i run this sketch, LED is blinked on #13 pin after encoder rotate 512 steps. but this is because it has sensed HIGH state after encoder rotated above 512 steps in advance .
I would like to make this to be opposite.
I want second arduino to sense the HIGH state(as a commend to start count) in advance(for a short time), and start count encoder until a designated amount of steps.
i've referenced arduino website, but i couldn't get any clue on defferentiate two if conditions. please help.

mingkimingki@gmail.com

mem

#49
Feb 10, 2008, 10:44 am Last Edit: Feb 10, 2008, 11:10 am by mem Reason: 1
Did the last sketch posted work with the change suggested above? If it does but doesn't do what you want could you say how you want the functionality to differ?

Quote
the reason why i use two arduino is because i thought i could use HIGH state of digital pins acting like a switch which triggers the encoder to count until certain steps since HIGH state will last just for a short period(using delay function).


Mingki, I don't understand what this means. Please try and express what you want to explain in a different way.  Forget about arduinos and pins and HIGH states, just talk about what you want to count and what should happen when the count reaches a particular level.

mem

#50
Feb 10, 2008, 12:59 pm Last Edit: Feb 10, 2008, 01:03 pm by mem Reason: 1
I think that helps a lot, lets see if my understanding is correct.

Items moving on a conveyer need to be sorted by weight.
There are a range of solenoids that can select an item and each solenoid is intended for a particular range of weights.

An encoder generates pulses in proportion to the movement of the conveyer. There is a specific number of pulses to indicate the distance from the weight detector to the location of each solenoid.

The task is to weigh the moving items and activate the solenoid appropriate to each items weight when it is over that particular solenoid.



Does that match what you want to do?

If so, then there are a few more details to clarify before you should start writing your sketch.

-What is the maximum number of items that will be on the conveyer between the weighing point and the solenoid furthest away from that point?  (your sketch needs to keep track of the weights for all of these)

-How many solenoids will you have?

-Do you know how many pulses there will be from the weighing point to the first solenoid?

-Do you know how many pulses between solenoids ? (are the solenoids equally spaced?)

-Does the time to activate a solenoid depend on conveyer speed? (does the speed change?)

mingki

Quote

Items moving on a conveyer need to be sorted by weight.
There are a range of solenoids that can select an item and each solenoid is intended for a particular range of weights.

An encoder generates pulses in proportion to the movement of the conveyer. There is a specific number of pulses to indicate the distance from the weight detector to the location of each solenoid.  

The task is to weigh the moving items and activate the solenoid appropriate to each items weight when it is over that particular solenoid.

Does that match what you want to do?

Exactly!!!

The maximum number of items(fruits or cups) will be 20pcs(from the weighing point to the furthest solenoid) and I hope i could have more than 10 solenoids.
Since my encoder's resolution is 512 per revolution, i think the pulses from the weighing point to the first solenoid would be approximately, 5,120(10 revolutions).
The solenoids are equally spaced to each other. Approximately, 3072(6 revolutions).
i hope the solenoids' activation time could be proportional to the conveyer speed.


mingkimingki@gmail.com

John_Ryan

Can you expand on this.

Quote

LED is blinked on #13 pin after encoder rotate 512 steps. but this is because it has sensed HIGH state after encoder rotated above 512 steps in advance.


And have you tried this:-

Code: [Select]

val = digitalRead(3);  
if ((val == HIGH) && (encoder0Pos > (startCount + 512)))  
{
startCount = encoder0Pos;        
digitalWrite(13, HIGH);    
delay(1000);
digitalWrite(13, LOW);
}


I suspect the use of delay might be a problem, it's good for holding the pin high, but it is pausing the whole loop, but, I'll need to see if I'm understanding the problem correctly first.

mem

#53
Feb 10, 2008, 05:47 pm Last Edit: Feb 10, 2008, 06:59 pm by mem Reason: 1
There are many ways of implementing your application. Here is one idea for a design, let me know if this makes sense to you and if you want any help understanding and implementing it.

If you can adjust the physical distance of the weighing device so that it is the same distance from the first solenoid as the solenoids are from each other then that makes the design simpler. We can add in functionality later to cope with a different distance if necessary but my explanation will be easier if we assume that the weight sensor and the solenoids are all separated by 3072 counts.

Assume ten solenoids numbered from 1 to 10 with number 1 being the one for the lightest objects and 10 for the heaviest.

Lets refer to every 3072 counts as a cycle. For each cycle (3072 counts) we want to weigh an item that is over the weight sensor and activate a solenoid when an item weighed in an earlier cycle comes over the correct solenoid.

A cycle has a duration in counts, this duration starts at the time an object is near enough that a solenoid should be activated, and it finishes when the solenoid is deactivated.  The actual timings will depend on how long the solenoid needs activating in order to ensure the object drops. You also want to make sure that you are taking your weight value a point in the cycle that the object is fully over the weight sensor.

If I was building this for commercial use I would be tempted to use a photo transistor to detect the physical presence of the objects (or whatever is holding the objects) to trigger the start and end of a cycle, but this may be more complex then you need. So to keep it simpler for now, say a new cycle starts every 3072 counts and lasts for enough counts for an object to drop.

At each cycle I would get the weight value. If the value was greater than a threshold I would use a lookup table or calculate the appropriate solenoid number for this weight. For example, no object would return a value of 0 (no solenoid), the lightest objects would return solenoid 1 etc. with the heaviest object returng 10.

I would then have a circular buffer,  you can google circular buffers if you are not familiar with this, but for now think of it as a kind of shift register that holds integer values.  We will put the solenoid number we just calculated at the first available position in this buffer. At each new cycle, the appropriate solenoid number (or 0 if no object)  would put into the next position in the buffer.

here is an example where  we assume that obj1 has weight value of 2, obj2 has value of 1, and obj3 has value of 3

At the start, the first cycle with an object above the weight threshold will look like this
       obj3  obj2   obj1     ?      ?      ?
                        weight   Sol1 Sol2  SoL3

and if obj1 has a weight value of 2 then immediately after weighing  the buffer will look like this:
       [2]
  •  ?.

    Here is the second cycle:
            Obj4   obj3  obj2    obj1  ?      ?
                            weight   Sol1  Sol2  SoL3

    buffer after cycle 2:  [1]  [2]
  •  ?.

    And the third cycle:
     Obj5     Obj4     obj3     obj2    obj1   ?
                            weight   Sol1   Sol2  SoL3

    buffer after cycle 3:  [3]  [1]  [2]
  •  ?.

    Now the trick is to remember that at the start of every cycle the first element of this circular buffer is always over the weighing sensor, the second is always over solenoid 1. the third over two etc.  So all that needs to be done is to check if the value in each buffer position from 1 to 10 (remember in C that the first position is 0) is the same as the solenoid number. In every case that the value equals the position then that solenoid should be activated.

    Because we need a circular buffer (memory is finite on the arduino so we need to reuse elements of the buffer that represent objects that have been dropped, the current position wraps around when it gets to the end of the buffer. But I think all this is easier to implement then it is to explain.

    That's a lot to take in. Does it make any sense to you?

mingki

#54
Feb 11, 2008, 12:35 am Last Edit: Feb 11, 2008, 12:37 am by mingki Reason: 1
thank you. yes, they all make sense. I think if i use photo transistor to detect the object above solenoid, the solenoid will trigger every object over itself even though the object is not corresponding to its position. so i thought encoder will solve this problem. is there any other way to use photo transistor while avoiding this?
also, another aspect that should be put under consideration is that the objects which will be going through the weighing system won't be all differ in terms of weight. some of them(which are same weight) are infeeded in serial, not positioned in an order of different weight. so, if the first object is weight to be 200g and the second object also happends to be 200g then, there must be some solution to cope with for both data of the same objects.
as you've mentioned, calculating the appropriate solenoid for a certain weight is the best way to pull this off.

mingkimingki@gmail.com

mem

Object weight order should not matter for the above logic to work.   Objects can all be the same weight or any random mix of weights from minimum to maximum. What does matter is the ability to know when an object of known weight appears over a particular solenoid.

We know how far apart the solenoids are (they are one cycle apart, which is 3072 counts). So if we know when a particular object is over the first solenoid then we also know that it will be over the second in the next cycle, over the one after that in the following cycle etc.

The challenge is knowing when a specific object that has been weighed arrives over the solenoids. An easy way to do this is if the objects can carried on the conveyer so they are the exactly the same space apart as the solenoids.  Its not essential but I think it may be a little easier to implement the sketch if this is the case. Can your conveyer be constructed so the objects are carried the same distance apart as the solenoid spacing?

mingki

#56
Feb 11, 2008, 12:57 pm Last Edit: Feb 11, 2008, 01:27 pm by mingki Reason: 1
Quote
Can you expand on this.
Quote

LED is blinked on #13 pin after encoder rotate 512 steps. but this is because it has sensed HIGH state after encoder rotated above 512 steps in advance.

And have you tried this:-
Code: [Select]

val = digitalRead(3);  
if ((val == HIGH) && (encoder0Pos > (startCount + 512)))  
{
startCount = encoder0Pos;        
digitalWrite(13, HIGH);    
delay(1000);
digitalWrite(13, LOW);
}

I suspect the use of delay might be a problem, it's good for holding the pin high, but it is pausing the whole loop, but, I'll need to see if I'm understanding the problem correctly first.

thank you.
I just tried your suggestion. but it is the same result that i am having at the moment. i first have to rotate encoder until 512 steps before i provide voltage variable to analoginput.
i hope i could reverse such result. If i provide a certain voltage variable temporarily(through a quick rotation of the potentiameter) to arduino, i hope the receiption of voltage variable act like an internal switch in arduino sketch so that arduino's 13th digital pin get HIGH after encoder rotate for 512 counts.

mingkimingki@gmail.com

mem

#57
Feb 11, 2008, 04:27 pm Last Edit: Feb 12, 2008, 10:03 am by mem Reason: 1
I hope the following code will be not too far from what you want, but I have thrown it together really fast so not only has it not been tested, I am pretty sure it will need fixing in a few places to get it to work correctly. You probably will need to put lots of debug serial.print statemens in various places to see whats going on. I hope it helps. good luck!

Code: [Select]
 
#define encoder0PinA  2
#define encoder0PinB  3  // this was 4
#define  firstSolenoidPin 4                                
#define  numberOfSolenoids  10   //note that solenoid 10 will be pin 14 which is analog pin 0
#define weightPin           5    // weight sensor to be connected to analog pin 5 (was pin 0, but this is used above)
#define numberOfCycles  (numberOfSolenoids + 1) // one cycle for each solenoid position plus one for the weight position


#define CountsPerCycle  3072   //adjust this so its the number of counts to get an object from entering proximity of one soleniod to the next
                              // it should also be the count to get from the center of the weight sensor to the first solenoid
                             
volatile int encoder0Pos = 0;  // this can be an int because we only need to count up to 3072 (its signed just in case the belt ever runs backwards)
unsigned int CycleCount = 0;   // this is the current cycle count  

int ObjectBuffer[numberOfCycles ] = {0};  // this used to make a circular buffer holding the appropriate solenoid for each object
int tail = 0;      // index to the next avalailable space in the above buffer

void setup()                        
{
 for(int i=0; i < numberOfSolenoids; i++)
    pinMode( i + firstSolenoidPin, OUTPUT);
 pinMode(encoder0PinA, INPUT);
 digitalWrite(encoder0PinA, HIGH);      
 pinMode(encoder0PinB, INPUT);
 digitalWrite(encoder0PinB, HIGH);      
 attachInterrupt(0, doEncoder, CHANGE);  
 Serial.begin (9600);
 Serial.println("start");                
}

void activateSolenoid(int solenoid){
   digitalWrite(firstSolenoidPin + solenoid -1 , HIGH);  
}

void  deactivateSolenoids() {  
for(int i = 0; i < numberOfSolenoids; i++)
   digitalWrite( firstSolenoidPin + i, LOW);  
}        
     
int getSolenoidFromWeight( int weight){
  int  solenoid;
 
  solenoid = 0;
  if( weight > 1)
     solenoid =  1 + ( weight / 110);  // this gives a  solenoid number from 1 to 10
                // replace this code with a table or formula that sorts as you require
  if(solenoid > 10)
     solenoid = 10;
 return solenoid;    
}

void objectQueAdd(int requiredCycles){     // store the number of cycles to the correct solenoid for the object now being weighed

 int t;
 t = tail;
 ObjectBuffer[t] = requiredCycles;
 if (++t >= numberOfCycles ){  //wrap around if buffer capacity has been exceeded
    t = 0;
    tail = t;        
  }    
}

int objectQueGet(int index){     // return the solenoid number appropriate for the object stored at this location
  int target = (index + tail) %  numberOfCycles;
 return  ObjectBuffer[target];  
}

int objectQueDebug(){
// you may want to write a temporary debug function here to print all values in the buffer starting from the tail. Dont forget you need to wrap (see the two functions above for some ideas on how to do that)
}

void ProcessCycle(int weight) {
 int requiredCycles =  getSolenoidFromWeight(weight);  // this is the solenoid number to be activated when the object currently being weighed
   // is over that solenoid. Because of the way we have spaced everthing,
   // this will happen in exactly requiredCycles from now.
  objectQueAdd( requiredCycles);    // save this value in our circular buffer
  for(int i = 1; i <= numberOfSolenoids; i++){
    if(objectQueGet(i) == i)
        activateSolenoid(i);  // triger solenoid becuase the correct weight is over it  
  }
  delay(100);  // all appropriate solenoids have been activated so wait for objects to drop    
  deactivateSolenoids();    // deactivate solenoids  
}

void loop(){
 cli();      //disable interrupts
 if(encoder0Pos >= CountsPerCycle){  
     encoder0Pos = 0;  // reset the count
     sei();             // enable interrupts
     int weightVal = analogRead(weightPin) ;      
     ProcessCycle(weightVal);      
  }
  else
     sei();   // make sure interrupts are enabled
}

void doEncoder(){
 if (digitalRead(encoder0PinA) == HIGH) {  
   if (digitalRead(encoder0PinB) == LOW) {  
     // encoder is turning
     encoder0Pos = encoder0Pos - 1;        
   }
   else {
     encoder0Pos = encoder0Pos + 1;        
   }
 }
 else                                        
 {
   if (digitalRead(encoder0PinB) == LOW) {  
     
     encoder0Pos = encoder0Pos + 1;          
   }
   else {
     encoder0Pos = encoder0Pos - 1;          
   }

 }    
}


mingki

Thank you very much. After testing, i shall get back to you.

mingkimingki@gmail.com

mem

I just had a read through the code I posted and noticed that there was a second call to reset the encoder count. I have edited the code to remove it.

I guess there will be a few other things you will need to do to get this to work. Feel free to ask for clarification of anything that is not clear. And you would be well served to put Serial.print statements in key areas so you can see how the data in the buffer is managed.

Go Up