|
|
View previous topic :: View next topic |
Author |
Message |
Baraaghazal
Joined: 01 May 2015 Posts: 1
|
Controlling two motors using UART |
Posted: Sat May 02, 2015 12:10 am |
|
|
Hey,
I am trying to make a PID control of 2 hacked servo motors (the control circuit is removed) wirelessly. The TX PIC16F877a is receiving the reference data from 2 potentiometers using the ADC and send it to the RX PIC18F4431 which calls a method that calculates the error, etc... and then drives the motors using the Power PWM Module.
First of all when I am sending data for only 1 motor it works really well. However when I also send the data for the second motor problems arise.
I feel I have something wrong with the logic I am using to send the data. I first send the first potentiometer reading, and immediatly send a character of number '1'. Then I send the second potentiometer reading, and immediately send a character of number '2'. On the RX side I receive the reading, then receive the number. I check which number that was and then call the necessary functions for the corresponding motor.
The simulation (Proteus) showed the motors not moving at all. I played around a bit and noticed that if I add a delay of 2 ms between each putc() the motors start moving. However, the problem is that the motors aren't acting properly. When I try sending data for 1 motor only it works properly. However when I send data for 2 motors, the second motor for some reason sometimes follows the first (it should potentiometer).
TX
Code: | #include <16f877a.h>
#DEVICE ADC=8;
#fuses PUT, HS, NOWDT, NOLVP, NOBROWNOUT
#use delay (crystal=4000000)
#use rs232 (baud=9600, xmit=PIN_C6, rcv=PIN_C7, bits=8, parity=N, errors)
unsigned int Desired1;
unsigned int Desired2;
//unsigned int Desired3;
unsigned int counter=1;
void main() {
setup_adc(ADC_CLOCK_DIV_8);
setup_adc_ports(ALL_ANALOG);
while (TRUE) {
//Read first potentiometer
set_adc_channel(0);
delay_us(20); // Delay needed for the channel selection to settle
Desired1 = read_adc();
delay_ms(2);
putc(Desired1);
output_d(Desired1); // Display the reading to check
delay_ms(2);
putc(1); // First Reading
delay_us(100);
//Read first potentiometer
set_adc_channel(1);
delay_us(20); // Delay needed for the channel selection to settle
Desired2 = read_adc();
delay_ms(2);
putc(Desired2);
output_d(Desired2); // Display the reading to check
delay_ms(2);
putc(2); // Second Reading
delay_us(100);
}
} |
RX
Code: | #include <18f4431.h>
#DEVICE ADC=8;
#fuses PUT, HS, NOWDT, NOLVP, NOBROWNOUT
#use delay (crystal=4000000)
#use rs232 (baud=9600, xmit=PIN_C6, rcv=PIN_C7, bits=8, parity=N, ERRORS)
//#use pwm(PWM1,FREQUENCY=5000) // TODO - Fix freq
#define PORTD0 PIN_D0
#define PORTD1 PIN_D1
#define PORTD2 PIN_D2
#define PORTD3 PIN_D3
#define PORTD4 PIN_D4
#define PORTD5 PIN_D5
#define PORTB7 PIN_B7
unsigned int Desired;
unsigned int Desired1;
unsigned int Actual1;
unsigned int Desired2;
unsigned int Actual2;
//unsigned int Desired3;
//unsigned int Actual3;
unsigned int n;
float epsilon = 0.01;
float PWM_signal;
float dt =0.01;
float Kp = 0.6;
float Kd =0.2;
float Ki =0.5;
void outputset(unsigned int port,unsigned int val){
// Adjusts motor direction
}
float PIDcal(unsigned int Desired,unsigned int Actual, unsigned int in2 ,unsigned int in1){
//Calculate PID
}
void main() {
setup_adc(ADC_CLOCK_DIV_2);
setup_adc_ports(sAN0|sAN1|sAN2|sAN3||sAN4|sAN5);
setup_power_pwm_pins(PWM_BOTH_ON, PWM_BOTH_ON, PWM_BOTH_ON, PWM_BOTH_ON);
setup_power_pwm(PWM_CLOCK_DIV_4|PWM_FREE_RUN, 1, 0, 199, 0, 1, 0); // 4Mhz: 2499 for 400Hz, 199 for 4000Mhz
while (TRUE) {
if (kbhit()) {
Desired = getc(); // Recieve reading
}
if (kbhit()) {
n = getc(); // Recieve number
}
if(n==1){ // First potentiometer - motor1
Desired1 = Desired;
set_adc_channel(0);
delay_us(10); // Delay needed forthe channel selection to settle
Actual1 = read_adc();
PWM_signal= PIDcal(Desired1,Actual1, 0, 1);
set_power_pwm0_duty(PWM_signal);
}
if(n==2){ // Second potentiometer - motor1
Desired2= Desired;
set_adc_channel(1);
delay_us(10); // Delay needed for the channel selection to settle
Actual2 = read_adc();
PWM_signal= PIDcal(Desired2,Actual2, 2, 3);
set_power_pwm2_duty(PWM_signal);
}
}
}
} |
In short:
Is the logic I am using to transmit the data here wrong ? Maybe the data is being lost in the middle ?
Thanks. |
|
|
Mike Walne
Joined: 19 Feb 2004 Posts: 1785 Location: Boston Spa UK
|
|
Posted: Sat May 02, 2015 1:52 am |
|
|
You mention Proteus.
Do you have real hardware?
Mike |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Sat May 02, 2015 3:08 am |
|
|
Code: | while (TRUE) {
if (kbhit()) {
Desired = getc(); // Recieve reading
}
if (kbhit()) {
n = getc(); // Recieve number
} | Try changing to: Code: | while (TRUE) {
if (kbhit()) {
Desired = getc(); // Receive reading
n = getc(); // Receive number
} | You want to make sure you have received the whole message before processing the received data. In your original version it is very likely that when you have received the reading, that the next character with the number has not arrived yet. This means you will skip the second getc() call and repeat the loop again. Only by luck, one in thousand times, you will enter the second getc() call.
Another improvement would be that you start your message always with a known character. Just in case your master and slave get out of sync, this is a method for your slave to detect which received byte is the start of a new message. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9246 Location: Greensville,Ontario
|
|
Posted: Sat May 02, 2015 6:20 am |
|
|
In any form of 'serial communications' with the PICs UART it is necessary to use an 'interrupt driven buffer'. Look at the CCS supplied example 'ex_sisr.c'.
Well maybe not necessary but to get reliable communications !
Jay |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|