21
Lab 4 Results Memo By: Jichuan Hu Belvia Huo Jeff Lehrer Gabe Viscariello

Lab 4 Results Memo_final

Embed Size (px)

Citation preview

Page 1: Lab 4 Results Memo_final

Lab 4 Results Memo

By:

Jichuan Hu

Belvia Huo

Jeff Lehrer

Gabe Viscariello

TA: Dibakar Das

Lab Section: 2 – B side

Lab Time: Monday 1pm -- 4pm

Due Date: 4/18/14

Page 2: Lab 4 Results Memo_final

ContentsINTRODUCTION..................................................................................................1

OBJECTIVES........................................................................................................1

CONTROL ALGORISM FOR STEERING..................................................................1

RESULTS AND ANALYSIS.....................................................................................2

CONCLUSION......................................................................................................4

APPENDIX A: CIRCUITRY DIAGRAM.....................................................................5

APPENDIX B: PSEUDO CODE...............................................................................6

APPENDIX C: C CODE..........................................................................................8

Page 3: Lab 4 Results Memo_final

IntroductionFor lab 4, the team needed to integrate the software and hardware of lab 3 from

both teams with the addition of the LCD screen and keypad. The car must be able to take inputs of desired direction and steering gain through the keypad. It should also react accordingly to these inputs and perform a run in the non-uniform magnetic field. Car battery voltage was read from analog-to-digital conversion and it was displayed with current heading, current altitude on the LCD screen.

ObjectivesThe three essential objectives were:

1. Familiarization objectives for new lab equipment such as properly receiving variables from the keypad and displaying the control information on the LCD screen.

2. Software design objectives which were to combine the C codes from the motor team and steering team so that none of the variables. This would also include setting of gain constants and desired heading using the keypad and displaying current car info on to the LCD screen. Lastly, it needed to record and display data for compass heading error, servo and motor pulse width value on SecureCRT.

3. Hardware designs objectives which were combining the hardware from the both teams on to a single protoboard, which included the Ultrasonic Ranger and an Electronic Compass. New additions to lab 3 must be integrated as well, such as the keypad, LCD screen, and wireless RF serial transceiver.

Control algorism for steeringThe first thing the team considered about when starting the lab is the control

algorism for steering with reading from the compass and desired heading input. A variable “error” is calculated by subtracting current heading value from desired heading value. It means that the desired heading is 0.1 times “error” degrees from the current heading. Generally, positive error means desired heading is to the right and negative heading is to the left. However, since the variable “error” is simply the difference, it would not make sense for some of the values. When error is larger than 1800, though it seems desired heading is more than 180 degrees to the right of current heading, the common way to understand it is that the desired heading is to the left and, practically, turning to the left would make a quicker change to fix the error. So is the case when “error” is less than -1800; the actual “error” is some degree to the right of the current heading. Since one round is 360 degrees, “error” value out of range is offset by +/- 3600 to adjust to a better “error” value. This simple algorism takes desired heading as zero “error” value and all possible “error” values falls between the -1800 and 1800. After an

1

Page 4: Lab 4 Results Memo_final

adjustment to the “error” variable, the pulse width will just be adding gain term times error to the neutral pulse width.

Results and Analysis

After finishing the software and circuits of lab 4, the team tested car’s behavior under different gain terms used for adjusting steering. Three different gain terms were used, which are 1, 4 and 8. For each gain term, the team collected data of error in degrees to desired heading, steering pulse width and motor pulse width, all with respect to time. When plotting, pulse width for steering was adjusted so that 0% is straight, 100% is maximum to the right and -100% is maximum to the left. Since the maximum speed was used for testing, the pulse width for motor was always 100%, thus always going forward at maximum speed. In order to fit all the data for one gain term in to one plot, the number on y-axis is read in such way that error is read in degrees and pulse width is read in percent. For example, when 20 is read for error, it means 20 degrees to the right is the desired heading; when 20 is read for pulse width, it means the pulse width is neutral pulse width plus 20 percent of the difference between neutral and maximum pulse width, thus the steering is turning right at 20% of the maximum turning angle.

0 5 10 15 20 25

-100

-80

-60

-40

-20

0

20

40

60

80

100

ErrorSteeringMotor

Time (s)

Erro

r(°)

PW(%

)

Graph 1: Error in degrees, Steering and Motor pulse width in percent vs. time at Gain = 1

The first gain the team tested is 1. At this gain, a 0.1 degree error to desired heading will result in a 1 unit change in pulse width. During testing, the car started to move with very little change in moving direction. After a few seconds, the car hit the wall and stopped moving, which showed as 2 horizontal lines on the graph lasting for about 10 seconds. After one of the team members retrieved the car, there was a few seconds delay before the car was turned off, thus data after 15 seconds were considered as

2

Page 5: Lab 4 Results Memo_final

irrelevant. Since the car cannot complete the test at gain of 1, 1 is not considered as the optimal gain for steering.

0 2 4 6 8 10 12

-100

-80

-60

-40

-20

0

20

40

60

80

100

ErrorSteeringMotor

Time(s)

Erro

r(°)

PW(%

)

Graph 2: Error in degrees, Steering and Motor pulse width in percent vs. time at Gain = 4

The second gain the team tested was 4. At this gain, every 0.1 degree of error to heading will result in a 4 units change in pulse width. The car started the test with a little turning to the right, then to the left. At some moment, the car was really close to the wall, but it managed to make enough turning right and move away from the wall; as shown in the graph, the car made continuous turning to the right from 5 to 9 second. Since the car could finish the test, 4 is considered as an option of gain term.

-1 1 3 5 7 9 11 13 15

-100

-80

-60

-40

-20

0

20

40

60

80

100

ErrorSteeringMotor

Time(s)

Erro

r(°)

PW(%

)

Graph 3: Percent Error, Steering, and Motor vs. time at Gain = 8

3

Page 6: Lab 4 Results Memo_final

The last gain the team tested was 8. At this gain, every 0.1 degree error to desired heading will result in 8 units change in pulse width. How this gain was affected the steering was very similar to gain of 4. It moved quickly to fix the error in direction; however, its changes were more drastic which led the car to a more sporadic movement pattern. As shown on the graph, the steering was changing so rapidly in direction that even a little error to the desired heading would result in maximum turning to the right or left. The gain of 8 is too sensitive for steering, and as a result, the gain of 4 is used as the optimal setting of gain term.

ConclusionThe objectives for this lab were fairly straight forward and very achievable within

the given time period. The circuitry was merely integrating one team’s with another and adding a slide switch, LCD screen, and keypad. Much like the hardware, the software was easy enough to combine. The teams had the same variables for pulse width, but it was simple to change the names. Some trouble the team had was getting the timing correct when asking for inputs from the user. Our code initially had trouble waiting for the user to make a second input if he was choosing from a preset list of desired directions. By adding a simple while loop in the correct spot, we were able to get our code to work and the keypad to work with the car.

4

Page 7: Lab 4 Results Memo_final

Appendix A: Circuitry Diagram

5

Page 8: Lab 4 Results Memo_final

Appendix B: Pseudo Codeinclude filesfunction prototypesgloable variables

main functionInitializationswhile true

wait until the slide switch is turned onif new setting is flaaged

unflag new settingset desired heading

1. from user input2. from predefined value list

set steering gain from predefinsed listif new heading is flagged, every

unflag new headingread compassset reading result to variable heading

if new range is flaggedunflag new rangeread rangerset reading result to variable rangeprint time, heading error and paulsewidth for analysis

calculate desired heading erroradjustment to error so it falls in -1800 to 1800change steering pw according to erroradjustment to the steering pw so it falls between limitsapply change to compare model for steeringchange to motor pw according to variable range

if less than 10, maximum pwif between 10 and 40, decrease in pw proportional to rangeif between 40 and 50, neutral pwif between 50 and 90, increase in pw proportional to rangeif more than 90, minimum pw

apply change to compare model for motorif new display is flagged

unflag displayclear lcdreading battery voltage from adcconvert adc result back to voltageprint on lcd the heading, altitude(range) and battery voltage

if slideswitch is turn offflag new setting

end of main

6

Page 9: Lab 4 Results Memo_final

PCA interrupt service routineclear the interrupt flagset starting count so that period is 20msincrease counts1, counts2, counts3increase time count for wait functionsif counts1 greater than 2

set counts1 to 0flag new heading

if counts2 greater than 4set counts2 to 0flag new range

if counts3 greater than 17set counts3 to 0flag new display

end

7

Page 10: Lab 4 Results Memo_final

Appendix C: C code// Jeff Lehrer, Gabe Viscariello, Jichuan Hu, Belvia Huo// Litec section 2 side B// Lab 4 Code// April 14th 2014#include <c8051_SDCC.h>#include <stdio.h>#include <stdlib.h>#include <i2c.h>//-----------------------------------------------------------------------------// Function Prototypes//-----------------------------------------------------------------------------void Port_Init(void); // initialize pins for output and inputvoid PCA_Init (void); // initialize PCAvoid ADC_Init(void); // initialize ADCvoid XBR0_Init(void); // initialize cross barvoid PCA_ISR (void) __interrupt 9; // code after PCA overflows void SMB_Init(void); // initialize SMBvoid Read_Comp(void); // read compass and return current headingvoid Servo(void); // adjust the steering according to current and desired headingvoid Read_Ranger(void); // read ranger and return altitudevoid Motor(void); // adjust the speed according to altitudevoid Motor_Init(void); // initialize motorunsigned char read_AD_input(void); // read P1.7 and return batter voltage in 0-255void Desired_heading(void); // set desired heading with keypadvoid Steering_gain(void); // set steering gain with keypadvoid Display(void); // update display every 350ms void Heading_Gain(void); // set desired heading and steering gain every time slideswith is toggledvoid pause(void); // wait for 20msvoid wait(void); // wait for 1s//-----------------------------------------------------------------------------// Global Variables//-----------------------------------------------------------------------------__sbit __at 0xB7 SS; // slideswitch on port 3 pin 7unsigned int T=0; // time variable for secure crt plotting dataunsigned char Data_C[2]={0}; // compass dataunsigned char Data_R[2]={0}; // ranger dataunsigned int heading; // current heading valueunsigned int range; // current range valueunsigned char new_heading=0; //flag for desired headingunsigned char new_range=0; // flag for ranger unsigned char new_display=0; // flag for lcd displayunsigned char new_setting=1; // flag for heading gainunsigned char counts1; // timer for headingunsigned char counts2; // timer for rangerunsigned char counts3; // timer for gainunsigned int time; // time variable for pause and waitunsigned char input; // input for character, used for testingunsigned int desired_heading=900; // default desired heading

8

Page 11: Lab 4 Results Memo_final

signed int error; // error to desired headingunsigned int temp_servo_pw; // current pw for steeringunsigned int temp_motor_pw; // current pw for motor

unsigned int pw_center_servo = 2834; //neutral steering pulsewidth unsigned int pw_min_servo = 2294; // min steering pulsewidthunsigned int pw_max_servo = 3414; // max steering pulsewidth

unsigned int pw_center_motor = 2774; // neutral motor pulsewidthunsigned int pw_min_motor = 2027; // motor min pulsewidthunsigned int pw_max_motor = 3502; // motor max pulsewidth

unsigned int cex0; // starting position for compare model oneunsigned int cex2; // starting position for compare model two

unsigned char battery; // battery voltage from adcunsigned char voltage[2]; // float number for battery voltage in Vfloat gain=0.8333; // default gain for steering//-----------------------------------------------------------------------------// Main Function//-----------------------------------------------------------------------------void main(void){ // initialize board Sys_Init(); putchar(' '); //the quotes in this line may not format correctly Port_Init(); XBR0_Init(); PCA_Init();

ADC_Init();SMB_Init();Motor_Init();wait();

while (1){

//printf("Start program. %d", SS);while (SS); // wait until the slide switch is turned onHeading_Gain(); // set gain and desired heading with keypadRead_Comp(); // read the compass Read_Ranger(); // read the ranger Servo(); // call servo function that calculated steering

pulsewidthMotor(); //call motor function that calculates speed pulsewidthDisplay(); // display function prints to the LDC display

}}

//-----------------------------------------------------------------------------// Port_Init//-----------------------------------------------------------------------------//// Set up ports for input and output

9

Page 12: Lab 4 Results Memo_final

//void Port_Init(){

//P0 P0MDOUT |= 0x50; //set output pin for CEX0 and CEX2 in push-pull mode

//P1P1MDIN &= ~0x80; //set for analog input on p1P1MDOUT &= ~0x80; // set to open drain modeP1 |= 0x80; // send logic 1 to input pins//P3P3MDOUT &= ~0x80; // set to push pull modeP3 |= 0x80; // send logic 1 to pins

}

//-----------------------------------------------------------------------------// XBR0_Init//-----------------------------------------------------------------------------//// Set up the crossbar//void XBR0_Init(){ XBR0 = 0x25; //configure crossbar as directed in the laboratory

XBR2 |= 0x40; //additional configuration that might not be necessary}

//-----------------------------------------------------------------------------// PCA_Init//-----------------------------------------------------------------------------//// Set up Programmable Counter Array//void PCA_Init(void){

CR = 1; // enable PCA PCA0MD = 0x81; // SYSCLK/12, enable PCA0 overflow interruptPCA0CPM0 = 0xC2; // PCA config for compass 16 bit compare modePCA0CPM2 = 0xC2; // PCA config for ranger 16 bit compare modeEIE1 = 0x0A; //enable PCA interruptsEA = 1; //enable all interruptsPCA0L = 0x00; // starting value of pca counter PCA0H = 0x70; // which gives 20ms period

}

void ADC_Init(void){

REF0CN = 0x03; // set internal reference voltage to 2.4 vADC1CN = 0x80; // enable a/d converter ADC1ADC1CF |= 0x01; // set a/d converter to a gain of 1

}

void SMB_Init(void){

10

Page 13: Lab 4 Results Memo_final

SMB0CR=0x93; //set clock frequency 100khzENSMB=1; // enable SMBus

}

void Motor_Init(void){

PCA0CPL2 = 0xFFFF - pw_center_motor; // low byte of start countPCA0CPH2 = (0xFFFF - pw_center_motor) >> 8; // high byte start counttime = 0;while (time<28);// wait

}

//-----------------------------------------------------------------------------// PCA_ISR//-----------------------------------------------------------------------------//// Interrupt Service Routine for Programmable Counter Array Overflow Interrupt//void PCA_ISR ( void ) __interrupt 9{ // reference to the sample code in Example 4.5 -Pulse Width Modulation // implemented using the PCA (Programmable Counter Array), p. 50 in Lab Manual.

if (CF){

CF = 0; //clear overflow flagPCA0L = 0x00; PCA0H = 0x70; counts1++; //increment counter for headingcounts2++; //increment counter for rangecounts3++; //increment counter for lcd displaytime++;if (counts1>=2) //timer for heading{

counts1 = 0;new_heading = 1;

}if (counts2 > 4) // wait 80ms timer for ranger{

counts2 = 0;new_range = 1;

}if (counts3 > 17) //wait 350ms timer for display timer{

counts3 = 0;new_display = 1;

}}PCA0CN &= 0xC0; // handle all other PCA interrupt sources

}

void Read_Comp(void){

if (new_heading) //if new heading flag is flagged{

11

Page 14: Lab 4 Results Memo_final

i2c_read_data(0xC0, 2, Data_C, 2); // read 2 bytes to register 2heading = (((unsigned int)Data_C[0]<<8) | Data_C[1]); //set

headingnew_heading = 0; // reset heading//printf("heading = %u", heading);//printf("Compass reading finished.\r\n");

}}void Read_Ranger(void){

if (new_range) // if new range flag is flagged{

unsigned char Data[1]; // local variable for setting return uniti2c_read_data(0xE0,2,Data_R,2); // read 2 byte at register 2range =(((unsigned int)Data_R[0]<<8) | Data_R[1]); //set rangenew_range = 0; //reset rangeData[0]=0x51; // set address of rangeri2c_write_data(0xE0,0,Data,1); //write the addressT++; // time used for data acquisitionprintf("%d,%d,%d,%d\r\n",T, error, temp_servo_pw,

temp_motor_pw); // print error,pulsewitdh, and time//printf(" the range =%u\r\n",range);//printf("PW = %u\r\n",temp_motor_pw);

}}void Servo(void){

//float k=0.8333;error = desired_heading - heading; //set errorif (error<=-1800) // if error is less than -1800 then the new error is

calculated{

error+=3600; //new error adds 3600}else if (error>=1800) // if greater than -1800 then calculate new error{

error-=3600; //subtract 3600 }temp_servo_pw = gain*(error) + pw_center_servo; //calculate temporary

servo pulsewitdh//printf("%d, %d, %d\r\n", heading, error, temp_servo_pw);if (temp_servo_pw>pw_max_servo) // if temp pulsewidth is greater than

max {

temp_servo_pw = pw_max_servo; //set temp pulsewidth equal to max pulsewidth

}else if (temp_servo_pw<pw_min_servo)// if temp pulsewidth less than

minimum pulsewidth{

temp_servo_pw = pw_min_servo; // set temp pulsewidth equal to minimum pulsewidth

}//printf("%d\r\n", temp_servo_pw);cex0=0xFFFF - temp_servo_pw;PCA0CPL0 = cex0;PCA0CPH0 = cex0 >> 8;

12

Page 15: Lab 4 Results Memo_final

//printf("Servo adjusted.\r\n");}void Motor(void){

if(range<=10) //if object is 10 cm or less above then adjust pulsewidth{

temp_motor_pw= pw_max_motor; // sets max pulsewidth}else if ((range>10) && (range<40)) // if range is between 40 and 50{

temp_motor_pw= ((-25*range)+3748); // linear decay of speed}else if((range>=40) && (range<=50)) // if range is between 40 and 50{

temp_motor_pw = pw_center_motor; //car is in neutral}else if ((range>50) && (range<90)) // if range greater than 50 and less

than 90{

temp_motor_pw = ((-18*range)+3686); // temp motor pulsewidth takes linear decay

}else if (range >=90) // if greater than 90 {

temp_motor_pw = pw_min_motor; // set car in full reverse pulsewidth

}cex2 = 0xFFFF - temp_motor_pw;PCA0CPL2 = cex2;PCA0CPH2 = cex2 >> 8;

}unsigned char read_AD_input(void){

AMX1SL = 7; // set analog input on pin 7ADC1CN &= ~0x20; //clear the conversion flagADC1CN |= 0x10; //initiate the ad conversionwhile ((ADC1CN & 0x20) == 0x00); //wait for conversion to be completereturn ADC1; // return digital value

}void Desired_heading(void){

char keypad;lcd_clear(); // clear ldclcd_print("Desired heading\n"); //print lcd_print("1:Specific Value\n2:Predefined Value"); // print options to

lcdkeypad = read_keypad(); //read the keypad for user inputpause(); // wait 20mswhile (keypad == -1) //when the keypad is released{

keypad = read_keypad(); //read the keypadpause(); // wait for response

}if (keypad == 49) //if 1 is pressed{

while (keypad != -1){keypad = read_keypad();pause();}//wait until the keypad is unpressed

13

Page 16: Lab 4 Results Memo_final

lcd_clear(); // clear lcdlcd_print("Please type in the desired heading.\nDesired

heading:");desired_heading = kpd_input(1); //desired heading is user input

}else if (keypad == 50) // if 2 is pressed{

while (keypad != -1){keypad = read_keypad();pause();}lcd_clear();//clear lcd displaylcd_print("Please select\n1:0 2:90\n3:180 4:270\n"); //prints

a list to select fromwhile (keypad == -1){keypad = read_keypad();pause();}if (keypad == 49) //when 1 is pressed{

desired_heading = 0; //heading is 0}else if (keypad == 50) //when 2 is pressed{

desired_heading = 900; //heading is 90 degrees}else if (keypad == 51) // when 3 is pressed{

desired_heading = 1800; // heading is 180 degrees}else if (keypad == 52) // if 3 pressed {

desired_heading = 2700; //heading is 270 degrees}

}while (keypad != -1) // wait until the keypad is unpressed{

keypad = read_keypad(); }

}void Steering_gain(void){

char keypad; //loc variablelcd_clear(); // clear the lcdlcd_print("Steering gain\n1:1 2:4\n3:8 4:14\n"); // print gain

optionskeypad = read_keypad(); //read the keypad for inputpause(); //waitwhile (keypad == -1) //wait until the keypad is pressed{

keypad = read_keypad(); //read the keypad for inputpause();// wait

} if (keypad == 49) // if 1 is pressed{

gain = 1; //gain equals 1}else if (keypad == 50) // if 2 is pressed{

gain = 4; // gain equals 4}else if (keypad == 51) //if 3 is pressed{

14

Page 17: Lab 4 Results Memo_final

gain = 8; // gain equals 8}else if (keypad == 52) //if 4 is pressed{

gain = 14; //gain equals 14}while (keypad != -1) //wait until the keypad is unpressed{

keypad = read_keypad();//read for input}

}void pause(void) // pause timing{ time = 0; while (time < 1);// 1 count -> (65536-PCA_START) x 12/22118400 = 20ms} // 6 counts avoids most of the repeated hitsvoid wait(void) //wait timing{ time = 0; while (time < 50); // 50 counts -> 50 x 20ms = 1000ms}void Battery_voltage(void) //function to calculate battery voltage{

battery = read_AD_input(); //battery is equal to the ad conversion on 7voltage[0] = 142*battery/233; //10*battery voltagevoltage[1]=voltage[0]%10;// voltage before the decimalvoltage[0]=voltage[0]/10; //voltage after the decimal to the tenths

place}void Display(void) //diplay function for the lcd{

if (new_display == 1) //if new display flagged{

new_display = 0; //reset flaglcd_clear(); //clear lcdBattery_voltage(); //convert adc to voltagelcd_print("heading: %d\n", heading); //print heading to lcdlcd_print("altitude: %d\n", range); // print range to lcdlcd_print("battery: %d.%d\n", voltage[0], voltage[1]); // print

voltage to lcd}if (SS == 1) // if slideswitch is off{

new_setting = 1; //}

}void Heading_Gain(void){

if (new_setting == 1) // if new setting if flagged{

new_setting = 0;Desired_heading(); //call heading functionSteering_gain(); //call steering gain function

}}

15