I'm currently working on a robot as an intern and must choose replacement drivers for the motors. The position information of the axis are given by analog pot. I do have 3 drivers by technosoft that needs a rotary encoder (quadrature) information to do their regulation job. I was thinking about converting this analog signal into the right quadrature signal to make it work.
The way I designed it is a pic18 sampling the pot value at 150hz, subtracting the previous value to the current one to have an idea (a kind of derivation) of the speed. It generates an absolute value of the speed and a direction signal whose regulate the rate of change of a state machine with the 4 states of the quadrature encoder. I finally send these signals to the 2 outputs.
My questions are the following.
Is it feasible. Or is there a clever way of doing so ? Or even a dedicated chip that can do the job? I searched the web to find someone who would have already done something similar but found nothing.
I've spend my 2 last days to code this solution & debug it without success... On the scope, the quadrature signal is there but it behaves with no real logic. Changing really fast or slowly whether I move or don't move the pot.
Here's my code
#include <p18f4685.h>
#include <stdlib.h>
#include <stdio.h>
#include <delays.h>
// ----------------------
// Configuration Hardware
// ----------------------
#pragma config OSC = HSPLL
#pragma config MCLRE = ON, PWRT = OFF
#pragma config DEBUG = ON, LVP = OFF
#pragma config FCMEN = OFF
#pragma config IESO = OFF
#pragma config BOREN = OFF
#pragma config WDT = OFF
#pragma config XINST = OFF
#pragma code
// Variables
unsigned int position_t0=0;
unsigned int position_t1=0;
signed int speed=0;
unsigned int speed_abs=0;
int direction=0; // si 0 cw, si 1 ccw
unsigned int count_1 = 0;
unsigned int state_out = 0;
//proto fonctions
void setup(void);
void get_pot(void);
void set_out(void);
void low_isr(void);
void high_isr(void);
int abval(int);
void main(void)
{
setup(); //initialisation
get_pot();
LATE = 0b00000000;
while(1)
{
}
}
void setup (void)
{
/*config timers*/
T0CON = 0b11000101; // timer on, 8bits, internal clock, prescaler on + value 1/64 (152 interruptions par seconde)
// data acquisition interrup
T2CON = 0b00111100; // output moditication loop timer 8bits 1/8postscale 1200 interrupt/second
PR2 = 0b00001111;
/*config adc*/
ADCON1 = 0b00001010; // A0->A4 analo + VDD+GND reference
ADCON2 = 0b10111000; // A/D acq time (ADCON2) 20TAD, A/D conversion clock (ADCON2)
// right justified
ADCON0 = 0b00000001; // Turn on A/D module (ADCON0) + channel select
/*config des pins*/
// TRISA = 0b00011111; // 5 entrées analogiques + 3 digitales
// TRISB = 0b01001100; // sorties pour la version finale
TRISE = 0b00000000; // sorties pour la version test
// PORTA = 0b00000000; // Clear A
PORTE = 0b00000000; // clear E
/*config interruptions*/
RCONbits.IPEN = 1; // priority enabled
INTCON = 0b11100000; // enable les interruption hautes et basses, Timer0 interrupt On
INTCON2 = 0b10000100; // Pull up désactivés +timer0 high(acquisition vitesse)
PIE1bits.TMR2IE = 1; // enable interrupt timer2
IPR1bits.TMR2IP = 0; // timer 2 en priorité basse(mise à jour des pins)
}
void get_pot (void) //get the value of the pot and computes the data
{
ADCON0bits.CHS1 = 0;
ADCON0bits.CHS0 = 0;
ADCON0bits.GO = 1;
while(ADCON0bits.GO==1){}
position_t1 = ADRESH*256+ADRESL;
speed = position_t1 - position_t0;
if(speed<0) direction = 1;
else direction = 0;
speed_abs = abval(speed);
position_t0 = position_t1;
}
void set_out (void) //set the output according the speed and direction
{
if(speed_abs>1)
{
count_1++;
if(count_1>=(1023-speed_abs)/4) //counter that makes the output change more or less faster
{
if(direction==1)
{
switch(state_out)
{
case 0:
{
LATE = 0b00000000;
state_out++;
}
break;
case 1:
{
LATE = 0b00000001;
state_out++;
}
break;
case 2:
{
LATE = 0b00000011;
state_out++;
}
break;
case 3:
{
LATE = 0b00000010;
state_out=0;
}
break;
}
}
else if(direction==0)
{
switch(state_out)
{
case 0:
{
LATE = 0b00000000;
state_out=3;
}
break;
case 1:
{
LATE = 0b00000001;
state_out--;
}
break;
case 2:
{
LATE = 0b00000011;
state_out--;
}
break;
case 3:
{
LATE = 0b00000010;
state_out--;
}
break;
}
}
count_1=0;
}
}
}
int abval(int val)
{
return (val<0 ? (-val) : val);
}
#pragma interrupt high_isr
void high_isr (void) //interruption de récupération des adc
{
if(INTCONbits.TMR0IF==1)
{
get_pot();
INTCONbits.TMR0IF=0;
}
}
#pragma interruptlow low_isr
void low_isr (void) //interruption de mise à jour des sorties
{
if(PIR1bits.TMR2IF==1)
{
set_out();
PIR1bits.TMR2IF=0;
}
}
/*
*********************************************************************************************************
* Interupt Vectors
*********************************************************************************************************
*/
#pragma code low_vector=0x18
void interrupt_at_low_vector(void)
{
_asm goto low_isr _endasm
}
#pragma code high_vector=0x08
void interrupt_at_high_vector(void)
{
_asm goto high_isr _endasm
}
Part of the code comments are in french, i translated the important ones. Do you see any obvious mistakes/wrong ways of coding. Do you have any advices of "where to search" or what to watch ?
Thanks by advance for your help !
Nicolas