View previous topic :: View next topic |
Author |
Message |
daalex
Joined: 10 Jan 2014 Posts: 10
|
Motor encoder problem |
Posted: Sun Mar 15, 2015 7:56 am |
|
|
Hello,
I try to count the encoder signals of a high speed motor,
if i turn the motor by hand everything runs fine and the program counts right but if i let the motor run - it doesn't work properly...the motor seem to be too fast for my program.
Is the pic too slow for this work or is it a software problem?
I use a PIC18F27J53
the Motor is a sanyo denki super r with 3000 rpm max.
here is my code:
it would be very nice if someone could help me a little bit with this problem.
Code: |
// --------------------------------------------------------------------------
#include <18F27J53.h>
#device ADC=12
#fuses HSPLL,PLLEN,PLL5, NOCPUDIV, NOWDT,NOPROTECT
#fuses ADC12, RTCOSC_INT, DSWDTOSC_T1
#use delay(clock=48000000)
//Bootloader ------------------------------------------------
#build (reset=0x1000, interrupt=0x1008)
#org 0x0,0xfff {}
// -------------------------------------------------------------------------------------------
#include <usb_cdc.h>
#include <stdlib.h>
#include <stdio.h>
//Encoderposition
#define EncMotor1CHA PIN_B7
#define EncMotor1CHB PIN_B6
unsigned short kanalA1,kanalB1;
unsigned short B_signal=0;
unsigned short A_signal=0;
signed int16 encoder_pulsA1=0;
signed int16 pulsE1=0;
// USB ------------------------------------------------------------------------------------------
void usb_putc(char cc) // printf(usb_putc,...)
{
while(!usb_cdc_putready());
delay_ms(1);
usb_cdc_putc(cc);
}
// USB -------------------------------------------------------------------------------------------
void HW_Init()
{
delay_us(50);
enable_interrupts(global);
enable_interrupts(int_rb);
}
// Initialize Encoder
void encoder_init() {
pulsE1 = 0; // Clear Positions
A_signal = 0; // Clear state
B_signal = 0;
encoder_pulsA1=0;
}
//read Encoderposition
void encoder(){
kanalA1 = input_state(EncMotor1CHA);
kanalB1 = input_state(EncMotor1CHB);
//Encoder 1
if(kanalA1 == 1)
{
if(A_signal == 0)
{
A_signal = 1;
if(B_signal == 0)
{
if(kanalB1 == 1)
{
encoder_pulsA1 = encoder_pulsA1 + 1;
B_signal = 1;
}
if(kanalB1 == 0)
{
encoder_pulsA1 = encoder_pulsA1 - 1;
B_signal = 1;
}
}
}
}
if(kanalA1 == 0)
{
if(A_signal == 1)
{
A_signal = 0;
if(B_signal == 1)
{
if(kanalB1 == 1)
{
B_signal = 0;
}
if(kanalB1 == 0)
{
B_signal = 0;
}
}
}
}
pulsE1 = encoder_pulsA1;
}
//Interrupt Port B
#int_rb
void button_isr(){
encoder();
}
//---------------------------------------------------------------------------------------
void main()
{
//encoder_init();
HW_Init();
usb_init();
while(!usb_cdc_connected()); // Warte auf PC-USB-Verbindung
while (true)
{
//initialize encoder
if(input_state(PIN_A3)){
//init
encoder_init();
}
printf ( usb_putc, "%Ld \r\n ",pulsE1);
}
}
|
|
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9225 Location: Greensville,Ontario
|
|
Posted: Sun Mar 15, 2015 8:18 am |
|
|
quick answer...
Would need to know how many 'slots' are on the encoder wheel, as this relates to the number of 'PPR' ( Pulses Per Revolution ).
If it has 1024 slots, at 3000 RPM this will generate 51,200 interrupts per second. Now a quadrature encoder is 4X that number....
This does explain the 'works at slow speed- not at high speed' observation you have.
Normally, I use a US Digital encoder counter chip to 'offload' the PIC from doing the raw counting/direction details. This method, while costing a bit more, allows the PIC to do 'other things'. There are PICs with a QEI but I'm 'old school' and keep building on known reliable parts and PICs.
Jay |
|
|
daalex
Joined: 10 Jan 2014 Posts: 10
|
|
Posted: Sun Mar 15, 2015 8:23 am |
|
|
Hello and thanks for answering,
it should be 1000 pulses/revolution... tells me the sticker on the motor and this is what my program counts in "slow motion".
I have read about the QEI PIC but i only have the pic 18f27j53, and if possible i would use the pic18F. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9225 Location: Greensville,Ontario
|
|
Posted: Sun Mar 15, 2015 8:47 am |
|
|
at 1000 PPR X 3000RPM that's 3,000,000 counts per minute or 50,000 counts per second .
You can 'do the math'... 48MHz clock= 12M inst/ sec...an ISR might take 50 for overhead PLUS whatever code is inside the ISR ( your 'state decoder' ) maybe another 200 ? You can dump the listing out to actually see what is 'in there'.
My gut feeling is the PIC can't keep up....can't process the counts without losing a lot of them.
You could spin the motor at a know speed and see where the PIC loses.
You also have to decide what else the PIC has to do and factor that code in as well.Maybe the PIC could keep up with say 1200RPM BUT it'd be the ONLY code it could do.
Also any printing should be in an ISR as well to maximize the PICs speed.
Jay |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19506
|
|
Posted: Sun Mar 15, 2015 9:00 am |
|
|
Have a look at this thread:
<http://www.ccsinfo.com/forum/viewtopic.php?t=44491&highlight=quadrature>
This contains a quadrature routine I originally posted many years ago. Written to be efficient (uses the global interrupt, and code designed to minimise the time taken to actually deal with the encoder). It could fractionally be improved on the PIC18 (since this has hardware to save three of the registers). As written, this is capable of handling well in excess of 200000 edges per second on a chip as fast as yours.
How fast is your motor?. As Temtronic points out, a 1000ppr encoder, gives 4000 edges per rev. This should be able to handle up to perhaps 3000RPM+, but if you need faster than this, then 'think again'....
However there is another possibility. Are you sure the pulse train from your encoders is working properly at higher speeds?. If these are using resistive pull-ups, it's very possible that the pulses are no longer actually cycling high properly as the rotational speed increases. Look at this first. This may well be the core problem.
Other possibilities:
1) Use an external encoder chip.
2) Use a PIC with QEI.
3) Add external gate logic, and use the CCP's.
Both the first and last options are very easy. However there are also PIC18's with a QEI decoder. Look for chips that have the 'motion feedback module'. The PIC 18F4431 for example. |
|
|
Jerry I
Joined: 14 Sep 2003 Posts: 96 Location: Toronto, Ontario, Canada
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19506
|
|
Posted: Sun Mar 15, 2015 10:11 am |
|
|
I just have to disagree totally, with Temtronic's last line:
"Also any printing should be in an ISR as well to maximize the PICs speed."
Definitely not.
You need though to copy the 'position' value to be printed to a local variable, like:
Code: |
int16 local;
while (local!=position)
local=position;
//then print the 'local' value.
|
Otherwise if the position changes during the print, you _will_ get garbage results..... |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9225 Location: Greensville,Ontario
|
|
Posted: Sun Mar 15, 2015 10:32 am |
|
|
guess I didn't word it right...but I meant that by using an ISR for printing, it should be faster as it uses a buffer and transmits data when required NOT tieing up the PIC like delay_ms() does.
Perhaps the USB driver does this ???
Jay |
|
|
daalex
Joined: 10 Jan 2014 Posts: 10
|
|
Posted: Sun Mar 15, 2015 10:54 am |
|
|
Hello again ,
so i tried different things and now it seems to be ok and the programm is counting right. :-)
one part was the signal "cleaning" , i did that and now i have perfect quad signals.
the other part was my fault...
for explanation:
i can run the motor in different modes with a pcb...one mode runs the motor continiously in one direction with ~ 2000 rpm -> now the programm works and the counting is right.
but i used another mode and the motor runs in step mode...in this mode the motor turns a quarter step->stops-> and so on... would be nice - but this is not neccessary to count.
Thanks to all who helped me and giving tipps, thats why i like this forum...a beginner like me is getting answer's and tipps - so i can learn and get better :-)
greetz Alex |
|
|
|