Contest Entry - Universal Telemetry System Demonstrated with Unmanned Aerial Vehicle
Universal Telemetry System (UTS) Demonstrated with Unmanned Aerial Vehicle (UAV)
My colleagues and I designed a Parallax Propeller based UAV that warranted an innovative telemetry system. Fortunately, Parallax released the Spinneret at just the right time.
Our goals were to design and build a complete telemetry system capable of capturing sensor feedback, controlling outputs, and transmitting video. These tasks had to be accomplished with web based products and in real time. By utilizing the Parallax community and our combined knowledge of SPIN, asynchronous JavaScript, XML parsing, and HTML; we were able to accomplish our system. The main components of our system include the Spinneret Webserver, Planex MZK-MF150 router, and the Lorex LNE1001 IP camera.
My colleagues and I designed a Parallax Propeller based UAV that warranted an innovative telemetry system. Fortunately, Parallax released the Spinneret at just the right time.
Our goals were to design and build a complete telemetry system capable of capturing sensor feedback, controlling outputs, and transmitting video. These tasks had to be accomplished with web based products and in real time. By utilizing the Parallax community and our combined knowledge of SPIN, asynchronous JavaScript, XML parsing, and HTML; we were able to accomplish our system. The main components of our system include the Spinneret Webserver, Planex MZK-MF150 router, and the Lorex LNE1001 IP camera.

Comments
Our code does not fit. Apparently there's a limit to 100000 characters.
I have included some sample code:
''continue working on PID and flight routines. Test Display implementation!!!! 02/24/2011 '''create conditions for pitch and roll orientation, do not use PID loop. '''use a ranged value, set point pitch of 0, if pitch is inbetween -5 and 5 then OKAY! {{ COG COUNT Cog 0 = Main Program Loop Cog 1 = ESC Motor Driver Cog 2 = FullDuplexSerial Cog 3 = F32 Cog 4 = Flight Control_PID_Kalman Cog 5 = Cog 6 = Cog 7 = Flight_Control(PID, Kalman Filter, Wii Objects) ''''OLD'''''' Possible Solutions to Free Up Cogs Combine Flight Control/PID into main program loop. Do not give Propeller to Spinneret Communication it's own cog. Eliminate the need for 2 cogs for the Floating Point Math. The above free's up 4 cogs, including the Display Test Values. Results: Flight_control is no longer using a cog, I have put a call to that funtion in each of the Decision engine's routine. I eliminated the 2nd cog for floating math, I am using F32 instead..... For the moment I took out the propeller to spinneret communication, the display test values is using its cog. Total Cogs Used : 4 Total Free Cogs : 4 IF no communication and no display test values then total free cogs = 5 }} CON _CLKMODE = XTAL1 + PLL16X _XINFREQ = 5_000_000 CLOCKS_PER_MICROSECOND = 5*16 ' simple xin*pll / 1_000_000 CLOCKS_PER_MILLISECOND = 5000*16 ' simple xin*pll / 1_000 Error_LED = 0 ON = 1 OFF = 0 RXPIN = 11 TXPIN = 12 SCL = 28 SDA = 29 Mtr_A = 0 Mtr_B = 1 Mtr_C = 2 Mtr_D = 3 Auto_Forward = 50 ''FIXED POINT VALUES ONLY Auto_Reverse = -50 Auto_Left = -50 Auto_Right = 50 Auto_Rotate = 50 CLS = 16, CR = 13, CLREOL = 11, CRSRXY = 2 MP_ONLY = 4 'MotionPlus only MP_NUN = 5 'MotionPlus w/ Nunchuck MP_CLASSIC = 7 'MotionPlus w/ Classic Controller VAR long Accel_X, Accel_Y long Gx_F, Gy_F, Gz_F word Alt,Thrust word Heading, Bearing, Temp long SP_Alt, SP_Head byte Error_Status, User_Control, i byte Wants_Control, Has_Control byte Landing, TakingOff, Holding, Rotating, Moving long RI_IR, LE_IR, FR_IR, RR_IR, TO_IR, BO_IR long count long cur_State byte startbtn long M_A, M_B, M_C, M_D 'long Received_Commands, RecBuffer[6], SenBuffer[6] 'long stack[200] OBJ Ser : "FullDuplexSerialPlus" FC : "Flight_Control0429" SCG : "sparecogs" SIR : "Sharp_IR" ESC : "ESC_Spin" Clk : "Clock" 'fString : "FloatString" 'TxRx : "FullDuplexSerialPlus" PUB MAIN | q '''''''''''''''''''''''INITIALIZING OBJECT DRIVERS''''''''''''''''''''''''''''''''''''''' 'TxRx.start(11, 12, 0, 115200) Ser.start(31,30,0,115200) ESC.Start FC.Init(SCL, SDA, MP_NUN) Delay_MS(2000) '''''''''''''''''''''''INITIALIZE ALL CONDITIONS'''''''''''''''''''''' Error_Status := Wants_Control := Has_Control := User_Control := 0 SP_Alt := Alt := Temp := Thrust := 0 FR_IR := RR_IR := LE_IR := RI_IR := TO_IR := BO_IR := 0 Landing := TakingOff := Rotating := Moving := Holding := 0 Thrust := 0 '''''''''''''''''''''''MAIN PROGRAM CODE'''''''''''''''''''''''''''''''''''''''''''''''''' startbtn := 0 DIRA[14]~~ OUTA[14]~~ DIRA[15]~ Delay_MS(1000) REPEAT UNTIL startbtn == 1 IF INA[15] == 1 Delay_MS(500) IF INA[15] == 1 Delay_MS(500) IF INA[15] == 1 startbtn := 1 TestDisplay Delay_MS(2000) '''''''''''''''''''''''INITIALIZE ESC's AND MOTOR's'''''''''''''''''''''' ESC.Servo(Mtr_A,1000) ESC.Servo(Mtr_B,1000) ESC.Servo(Mtr_C,1000) ESC.Servo(Mtr_D,1000) Delay_MS(10000) ''//////////////////Slow Start Sequence/////////////////////////// Decision_Engine(9) ''//////////////////Take-Off Sequence/////////////////////////// 'Decision_Engine(0) ''//////////////////Hold-Position Sequence/////////////////////////// 'Decision_Engine(2) 'Hover, get initial IR distance readings, and Pause to stabalize ''//////////////////Start Of Auto Routines/////////////////////////// } REPEAT WHILE startbtn == 1 Repeat 150 FC.PID(0,0,0,0,0,Thrust) Get_Data Motor_Output TestDisplay IF Accel_X > 10 OR Accel_Y > 10 ShutDownProcess Decision_Engine(1) ShutDownProcess IF INA[15] == 1 Delay_MS(500) IF INA[15] == 1 Delay_MS(500) IF INA[15] == 1 startbtn := 0 IF startbtn == 0 ShutDownProcess PUB Decision_Engine(Control_Variable) | Command '''''''''''''''''''''''Decision ENGINE'''''''''''''''''''''''''''''''''''''''''''''''''' '''FC.PID(Pitch_Orient, Roll_Orient, Rotate_Command, Alt_Command) '''' Has_Control := Control_Variable CASE Has_Control 0: 'Take Off cur_State := string("Taking-Off") SP_Alt := 30 Thrust := 10 SIR.Get_IR REPEAT WHILE SIR.IR_BO > 22 SIR.Get_IR Thrust := Thrust + 1 FC.PID(0,0,0,0,0,Thrust) REPEAT UNTIL SIR.IR_BO > (SP_Alt - 5) AND SIR.IR_BO < (SP_Alt + 5) SIR.Get_IR IF SIR.IR_BO < (SP_Alt - 5) Thrust := Thrust + 1 FC.PID(0,0,0,0,0,Thrust) ELSEIF SIR.IR_BO > (SP_Alt + 5) Thrust := (Thrust - 1) #>0 FC.PID(0,0,0,0,0,Thrust) 1: 'Land cur_State := string("Landing") REPEAT UNTIL Thrust == 0 SIR.Get_IR Alt := SIR.IR_BO Delay_MS(50) FC.PID(0,0,0,0,0,(Thrust - 10)) FC.PID(0,0,0,0,0,0) ShutDownProcess 2: 'Hold Position cur_State := string("Hovering") FC.PID(0,0,0,0,0,Thrust) SIR.Get_IR IF SIR.IR_FR < 50 FC.PID(Auto_Reverse, 0,0,0, 0, Thrust) IF SIR.IR_LE < 50 FC.PID(0, Auto_Right,0,0, 0, Thrust) IF SIR.IR_RI < 50 FC.PID(0, Auto_Left,0,0, 0, Thrust) IF SIR.IR_RR < 50 FC.PID(Auto_Forward, 0,0,0, 0, Thrust) IF SIR.IR_TO < 25 Thrust := (Thrust - 5)#>0 FC.PID(0, 0,0,0, 0, Thrust) 'IF SIR.IR_BO < 30 'Thrust := Thrust + 5 'FC.PID(0, 0,0,0, 0, Thrust) 3: 'Rotate cur_State := string("Rotating") IF Heading > (SP_Head + 20) Command := 50 FC.PID(0,0,0,0,Command,Thrust) ElseIF Heading < (SP_Head - 20) Command := -50 FC.PID(0,0,0,0,Command,Thrust) ELSE Command := 0 FC.PID(0,0,0,0,Command,Thrust) 4: 'Move Forward cur_State := string("Forward") IF FR_IR > 20 FC.PID(Auto_Forward,0,0,0,0,0) Else FC.PID(0,0,0,0,0,Thrust) 'Error_Status := 1 5: 'Move Reverse cur_State := string("Reverse") IF RR_IR > 20 FC.PID(Auto_Reverse,0,0,0,0,Thrust) Else FC.PID(0,0,0,0,0,Thrust) 6: 'Move Left cur_State := string("Left") IF LE_IR > 20 FC.PID(0,Auto_Left,0,0,0,Thrust) Else FC.PID(0,0,0,0,0,Thrust) 7: 'Move Right cur_State := string("Right") IF RI_IR > 20 FC.PID(0,Auto_Right,0,0,0,Thrust) Else FC.PID(0,0,0,0,0,Thrust) 8: 'Change Altitude cur_State := string("Throttle") FC.PID(0,0,0,0,0,Thrust) 9: 'Slow Start cur_State := string("Slow Start") Repeat Until Thrust == 375 Thrust := Thrust + 5 FC.PID(0,0,0,0,0,Thrust) Get_Data Motor_Output TestDisplay Delay_MS(50) 'Delay_MS(3000) 'ShutDownProcess PUB Motor_Output ESC.Servo(Mtr_A, M_A) 'SEND OUTPUT PULSE TO MOTORS A, B, C, AND D ESC.Servo(Mtr_B, M_B) ESC.Servo(Mtr_C, M_C) ESC.Servo(Mtr_D, M_D) PUB ShutDownProcess M_A := M_B := M_C := M_D := 1000 Motor_Output ESC.Stop FC.Stop SIR.Stop Clk.Init(5_000_000) Clk.SetClock(RCSLOW) REPEAT IF INA[15] == 1 REBOOT PUB Get_Heading | n, avgvalue IF avgvalue > 350 OR avgvalue < 10 Bearing := string("North") ELSEIF avgValue > 11 AND avgvalue < 31 Bearing := string("North-East") ELSEIF avgValue > 32 AND avgvalue < 52 Bearing := string("East") ELSEIF avgValue > 53 AND avgvalue < 73 Bearing := string("South-East") ELSEIF avgValue > 74 AND avgvalue < 94 Bearing := string("South") ELSEIF avgValue > 95 AND avgvalue < 115 Bearing := string("South-West") ELSEIF avgValue > 116 AND avgvalue < 136 Bearing := string("West") ELSEIF avgValue > 137 AND avgvalue < 157 Bearing := string("North-West") ELSE Bearing := string("Unknown") return avgvalue PUB Get_Data Gx_F := FC.GetGX Gy_F := FC.GetGY Gz_F := FC.GetGZ Accel_X := FC.GetAccelX Accel_Y := FC.GetAccelY 'RawAx := FC.GetRawAx 'RawAy := FC.GetRawAy 'RawAz := FC.GetRawAz 'Ax := FC.GetAx 'Ay := FC.GetAy 'Az := FC.GetAz Heading := FC.GetHeading count := FC.Return_Count M_A := FC.Motor_A M_B := FC.Motor_B M_C := FC.Motor_C M_D := FC.Motor_D SIR.Get_IR FR_IR := SIR.IR_FR RR_IR := SIR.IR_RR LE_IR := SIR.IR_LE RI_IR := SIR.IR_RI TO_IR := SIR.IR_TO BO_IR := SIR.IR_BO {PUB Comm '''''''''''''''''''''''INTER-PROPELLER COMMUNICATION'''''''''''''''''''''''''''''''''''''''''''''''''' Repeat TxRx.str(string("!v=")) 'SEND SYNC PULSE Repeat i from 0 to 8 'SEND ENTIRE BUFFER TxRx.PutLong(SenBuffer[i]) TxRx.waitstr(string("!x*"), clkfreq*20) Repeat i from 0 to 8 'RECEIVE ENTIRE BUFFER RecBuffer[i] := TxRx.GetLong IF RecBuffer[0] <>= 9847_3817 'COGINIT(7, Comm, @stack[0]) RecBuffer[1] := User_Control RecBuffer[2] := Received_Commands RecBuffer[3] := 0 RecBuffer[4] := 0 RecBuffer[5] := 0 RecBuffer[6] := 0 RecBuffer[7] := 0 RecBuffer[8] := 0 RecBuffer[9] := 0 SenBuffer[0] := Gx_F SenBuffer[1] := Gy_F SenBuffer[2] := Gz_F SenBuffer[3] := Ax SenBuffer[4] := Ay SenBuffer[5] := Az SenBuffer[6] := 0 SenBuffer[7] := 0 SenBuffer[8] := Heading SenBuffer[9] := cur_State } PUB TestDisplay | tempe Ser.tx(CLS) Ser.str(string("Test Data From UAV..............", CR)) ser.str(string("Cogs Free: ")) ser.dec(SCG.freecount) ser.tx(13) Ser.str(string(CR, "Start Button : ")) ser.dec(startbtn) Ser.str(string(CR, "INA pin 15 : ")) ser.dec(INA[15]) ser.str(string(CR, CR, "GX : ")) ser.dec(Gx_F) Ser.str(string(CR, "GY : ")) ser.dec(Gy_F) Ser.str(string(CR, "GZ : ")) ser.dec(Gz_F) Ser.str(string(CR, CR, "Pitch : ")) ser.dec(Accel_X) Ser.str(string(CR, "Roll : ")) ser.dec(Accel_Y) { Ser.str(string(CR, CR, "Raw Ax : ")) ser.dec(RawAx) Ser.str(string(CR, "Raw Ay : ")) ser.dec(RawAy) Ser.str(string(CR, "Raw Az : ")) ser.dec(RawAz) Ser.str(string(CR, CR, "Ax : ")) ser.dec(Ax) Ser.str(string(CR, "Ay : ")) ser.dec(Ay) Ser.str(string(CR, "Az : ")) ser.dec(Az) SER.str(string(CR,CR, "Heading: ")) ser.dec(Heading) Ser.tx(CR) } Ser.str(string(CR, "Motor A: ")) ser.dec(M_A) Ser.str(string(CR, "Motor B: ")) ser.dec(M_B) Ser.str(string(CR, "Motor C: ")) ser.dec(M_C) Ser.str(string(CR, "Motor D: ")) ser.dec(M_D) ser.tx(CR) ser.dec(count) Delay_MS(100) ' ///////////////////////////////////////////////////////////////////////////// PUB Delay_MS( time ) {{ Delays "time" milliseconds and returns. }} waitcnt (cnt + time*CLOCKS_PER_MILLISECOND) ' // end Delay_MS ' ///////////////////////////////////////////////////////////////////////////// PUB Delay_US( time ) {{ Delays "time" microseconds and returns. }} waitcnt (cnt + time*CLOCKS_PER_MICROSECOND) ' // end Delay_US '////////////////////////////////////////////////////////////////////////////// {{&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&''&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&''&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&''&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&''&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&''&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&}} '' From Parallax Inc. Propeller Education Kit - Objects Lab v1.1 {{ ──────────────────────────────────────────────────────────────────────────────────────── File: FullDuplexSerialPlus.spin Version: 1.2 Copyright (c) 2008 Parallax, Inc. See end of file for terms of use. This is the FullDuplexSerial object v1.1 from the Propeller Tool's Library folder with modified documentation and methods for converting text strings into numeric values in several bases. v1.2 - Added WaitStr, GetLong and PutLong methods. ──────────────────────────────────────────────────────────────────────────────────────── }} CON '' ''Parallax Serial Terminal Control Character Constants ''──────────────────────────────────────────────────── HOME = 1 ''HOME = 1 CRSRXY = 2 ''CRSRXY = 2 CRSRLF = 3 ''CRSRLF = 3 CRSRRT = 4 ''CRSRRT = 4 CRSRUP = 5 ''CRSRUP = 5 CRSRDN = 6 ''CRSRDN = 6 BELL = 7 ''BELL = 7 BKSP = 8 ''BKSP = 8 TAB = 9 ''TAB = 9 LF = 10 ''LF = 10 CLREOL = 11 ''CLREOL = 11 CLRDN = 12 ''CLRDN = 12 CR = 13 ''CR = 13 CRSRX = 14 ''CRSRX = 14 CRSRY = 15 ''CRSRY = 15 CLS = 16 ''CLS = 16 VAR long cog 'cog flag/id long rx_head '9 contiguous longs long rx_tail long tx_head long tx_tail long rx_pin long tx_pin long rxtx_mode long bit_ticks long buffer_ptr byte rx_buffer[16] 'transmit and receive buffers byte tx_buffer[16] PUB start(rxpin, txpin, mode, baudrate) : okay {{ Starts serial driver in a new cog rxpin - input receives signals from peripheral's TX pin txpin - output sends signals to peripheral's RX pin mode - bits in this variable configure signaling bit 0 inverts rx bit 1 inverts tx bit 2 open drain/source tx bit 3 ignor tx echo on rx baudrate - bits per second okay - returns false if no cog is available. }} stop longfill(@rx_head, 0, 4) longmove(@rx_pin, @rxpin, 3) bit_ticks := clkfreq / baudrate buffer_ptr := @rx_buffer okay := cog := cognew(@entry, @rx_head) + 1 PUB stop '' Stops serial driver - frees a cog if cog cogstop(cog~ - 1) longfill(@rx_head, 0, 9) PUB tx(txbyte) '' Sends byte (may wait for room in buffer) repeat until (tx_tail <> (tx_head + 1) & $F) tx_buffer[tx_head] := txbyte tx_head := (tx_head + 1) & $F if rxtx_mode & %1000 rx PUB rx : rxbyte '' Receives byte (may wait for byte) '' rxbyte returns $00..$FF repeat while (rxbyte := rxcheck) < 0 PUB rxflush '' Flush receive buffer repeat while rxcheck => 0 PUB rxcheck : rxbyte '' Check if byte received (never waits) '' rxbyte returns -1 if no byte received, $00..$FF if byte rxbyte-- if rx_tail <> rx_head rxbyte := rx_buffer[rx_tail] rx_tail := (rx_tail + 1) & $F PUB rxtime(ms) : rxbyte | t '' Wait ms milliseconds for a byte to be received '' returns -1 if no byte received, $00..$FF if byte t := cnt repeat until (rxbyte := rxcheck) => 0 or (cnt - t) / (clkfreq / 1000) > ms PUB str(stringptr) '' Send zero terminated string that starts at the stringptr memory address repeat strsize(stringptr) tx(byte[stringptr++]) PUB getstr(stringptr) | index '' Gets a carriage return terminated string and stores it (starting at stringptr) '' as a zero terminated string index~ repeat until ((byte[stringptr][index++] := rx) == 13) byte[stringptr][--index]~ PUB waitstr(stringptr, timeout) : success | index, tstart {{Wait for a string. Parameters: stringptr - points to the comparison string timeout - number of clock ticks to wait Returns: success - true if string found or false if timeout exceeded }} tstart := cnt index~ repeat until byte[stringptr][index] == 0 if (cnt - tstart) > timeout return if byte[stringptr][index] == rx index++ else index~ success~~ PUB dec(value) | i '' Prints a decimal number if value < 0 -value tx("-") i := 1_000_000_000 repeat 10 if value => i tx(value / i + "0") value //= i result~~ elseif result or i == 1 tx("0") i /= 10 PUB GetDec : value | tempstr[11] '' Gets decimal character representation of a number from the terminal '' Returns the corresponding value GetStr(@tempstr) value := StrToDec(@tempstr) PUB StrToDec(stringptr) : value | char, index, multiply '' Converts a zero terminated string representation of a decimal number to a value value := index := 0 repeat until ((char := byte[stringptr][index++]) == 0) if char => "0" and char =< "9" value := value * 10 + (char - "0") if byte[stringptr] == "-" value := - value PUB bin(value, digits) '' Sends the character representation of a binary number to the terminal. value <<= 32 - digits repeat digits tx((value <-= 1) & 1 + "0") PUB GetBin : value | tempstr[11] '' Gets binary character representation of a number from the terminal '' Returns the corresponding value GetStr(@tempstr) value := StrToBin(@tempstr) PUB StrToBin(stringptr) : value | char, index '' Converts a zero terminated string representaton of a binary number to a value value := index := 0 repeat until ((char := byte[stringptr][index++]) == 0) if char => "0" and char =< "1" value := value * 2 + (char - "0") if byte[stringptr] == "-" value := - value PUB hex(value, digits) '' Print a hexadecimal number value <<= (8 - digits) << 2 repeat digits tx(lookupz((value <-= 4) & $F : "0".."9", "A".."F")) PUB GetHex : value | tempstr[11] '' Gets hexadecimal character representation of a number from the terminal '' Returns the corresponding value GetStr(@tempstr) value := StrToHex(@tempstr) PUB StrToHex(stringptr) : value | char, index '' Converts a zero terminated string representaton of a hexadecimal number to a value value := index := 0 repeat until ((char := byte[stringptr][index++]) == 0) if (char => "0" and char =< "9") value := value * 16 + (char - "0") elseif (char => "A" and char =< "F") value := value * 16 + (10 + char - "A") elseif(char => "a" and char =< "f") value := value * 16 + (10 + char - "a") if byte[stringptr] == "-" value := - value PUB GetLong : value | index ''Receives four serial bytes that comprise an int in little endian format. ''Returns an int. repeat index from 0 to 3 byte[@value][index]:=rx PUB PutLong(value) | index ''Transmits and int value parameter as four bytes in little endian format. repeat index from 0 to 3 tx(byte[@value][index]) DAT '*********************************** '* Assembly language serial driver * '*********************************** org ' ' ' Entry ' entry mov t1,par 'get structure address add t1,#4 << 2 'skip past heads and tails rdlong t2,t1 'get rx_pin mov rxmask,#1 shl rxmask,t2 add t1,#4 'get tx_pin rdlong t2,t1 mov txmask,#1 shl txmask,t2 add t1,#4 'get rxtx_mode rdlong rxtxmode,t1 add t1,#4 'get bit_ticks rdlong bitticks,t1 add t1,#4 'get buffer_ptr rdlong rxbuff,t1 mov txbuff,rxbuff add txbuff,#16 test rxtxmode,#%100 wz 'init tx pin according to mode test rxtxmode,#%010 wc if_z_ne_c or outa,txmask if_z or dira,txmask mov txcode,#transmit 'initialize ping-pong multitasking ' ' ' Receive ' receive jmpret rxcode,txcode 'run chunk of tx code, then return test rxtxmode,#%001 wz 'wait for start bit on rx pin test rxmask,ina wc if_z_eq_c jmp #receive mov rxbits,#9 'ready to receive byte mov rxcnt,bitticks shr rxcnt,#1 add rxcnt,cnt :bit add rxcnt,bitticks 'ready next bit period :wait jmpret rxcode,txcode 'run chunk of tx code, then return mov t1,rxcnt 'check if bit receive period done sub t1,cnt cmps t1,#0 wc if_nc jmp #:wait test rxmask,ina wc 'receive bit on rx pin rcr rxdata,#1 djnz rxbits,#:bit shr rxdata,#32-9 'justify and trim received byte and rxdata,#$FF test rxtxmode,#%001 wz 'if rx inverted, invert byte if_nz xor rxdata,#$FF rdlong t2,par 'save received byte and inc head add t2,rxbuff wrbyte rxdata,t2 sub t2,rxbuff add t2,#1 and t2,#$0F wrlong t2,par jmp #receive 'byte done, receive next byte ' ' ' Transmit ' transmit jmpret txcode,rxcode 'run chunk of rx code, then return mov t1,par 'check for head <> tail add t1,#2 << 2 rdlong t2,t1 add t1,#1 << 2 rdlong t3,t1 cmp t2,t3 wz if_z jmp #transmit add t3,txbuff 'get byte and inc tail rdbyte txdata,t3 sub t3,txbuff add t3,#1 and t3,#$0F wrlong t3,t1 or txdata,#$100 'ready byte to transmit shl txdata,#2 or txdata,#1 mov txbits,#11 mov txcnt,cnt :bit test rxtxmode,#%100 wz 'output bit on tx pin test rxtxmode,#%010 wc 'according to mode if_z_and_c xor txdata,#1 shr txdata,#1 wc if_z muxc outa,txmask if_nz muxnc dira,txmask add txcnt,bitticks 'ready next cnt :wait jmpret txcode,rxcode 'run chunk of rx code, then return mov t1,txcnt 'check if bit transmit period done sub t1,cnt cmps t1,#0 wc if_nc jmp #:wait djnz txbits,#:bit 'another bit to transmit? jmp #transmit 'byte done, transmit next byte ' ' ' Uninitialized data ' t1 res 1 t2 res 1 t3 res 1 rxtxmode res 1 bitticks res 1 rxmask res 1 rxbuff res 1 rxdata res 1 rxbits res 1 rxcnt res 1 rxcode res 1 txmask res 1 txbuff res 1 txdata res 1 txbits res 1 txcnt res 1 txcode res 1 {{ ┌──────────────────────────────────────────────────────────────────────────────────────┐ │ TERMS OF USE: MIT License │ ├──────────────────────────────────────────────────────────────────────────────────────┤ │Permission is hereby granted, free of charge, to any person obtaining a copy of this │ │software and associated documentation files (the "Software"), to deal in the Software │ │without restriction, including without limitation the rights to use, copy, modify, │ │merge, publish, distribute, sublicense, and/or sell copies of the Software, and to │ │permit persons to whom the Software is furnished to do so, subject to the following │ │conditions: │ │ │ │ │ │The above copyright notice and this permission notice shall be included in all copies │ │or substantial portions of the Software. │ │ │ │ │THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, │ │INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A │ │PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT │ │HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION │ │OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE │ │SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ └──────────────────────────────────────────────────────────────────────────────────────┘ }} {{&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&''&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&''&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&''&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&''&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&''&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&}} {{ Flight Control Controls Wii Nunchuck, Wii MotionPlus, Digital Compass, ESC outputs, Kalman Filter, and PID loop. Uses 3 cogs. }} CON CLOCKS_PER_MICROSECOND = 5*16 ' simple xin*pll / 1_000_000 CLOCKS_PER_MILLISECOND = 5000*16 ' simple xin*pll / 1_000 HzToSec = 1.0 / 80_000_000.0 F_Mode = 4.54545454545 ' fast rotation G_Mode = 0.111 ' slow rotation for gyro, decreases sample speed A_Mode = 0.25 'slow rotation for accel, decreases sample speed Deg_Sec = 594.7 'the sensetivity of the Wii Motionplus aslope = 2.8571 'scaling used for accel, convert to g's aoffset = -1000.0 'offset used for accel, convert to g's ''/////////////Tune the Following values for the PID loop and the Kalman Filter/////////////////////// slope = 0 'FLOATING POINT VALUE scale input values to outputs offset = 1150 slopeY = 0.004899 'used to convert the Wii Nunchuck raw values to radians slopeX = 0.004800 slopeZ = 0.004854 offsetY = -2.521583 offsetX = -2.445026 offsetZ = -2.452766 Accel_Noise = 0.00003 'expected accel noise Accel_Trust = 0.00003 'how much to trust the accel Gyro_Trust = 0.000001 'how much to trust the gyro ''ALL REMAINING FLOATING POINT VALUES Proportional_Gain = 1 'floating point Integral_Gain = 0.0 'fixed point Derivative_Gain = 0.0 'floating point Mtr_A = 0 'ESC pins Mtr_B = 1 Mtr_C = 2 Mtr_D = 3 VAR long stack[700] 'stack space for PID loop cog ''/////////////////////////Variables for the Wii sensor measurements//////////////////////////// long Ay, Ax, Az, GZ 'conditioned accel and gyro data long RawAx, RawAy, RawAz 'raw accel and gyro data long RawGx, RawGy, RawGz long Cgx, Cgy, Cgz, Cax, Cay, Caz, Cap, Car 'inital center values of gyro and accel long AccXCen, AccYCen ''/////////////////////Variables for the Kalman Filter////////////////////////// long xAngleInt, yAngleInt long CurTime, PrevTime, DeltaTime, fDelta long AccelX, AccelY, fAccelX, fAccelY long GyroX, GyroY, fGyroX, fGyroY long GyroXUnb, GyroYUnb, fGyroXUnb, fGyroYUnb long xAngle, xBias long xP00, xP01, xP10, xP11 long yAngle, yBias long yP00, yP01, yP10, yP11 long QAngle, QGyro, RAngle ''/////////////////////////Variables for the PID loop//////////////////////////// long SP[5], b, m, Kp, Ki, Kd 'gains long M_A, M_B, M_C, M_D 'motor outputs long Auto_Pitch, Auto_Roll 'command given roll and pitch long Acc_Pitch, Acc_Roll 'instaneous roll and pitch long SP_R, RawCompass, Alt 'rotate, compass, and altitude long count byte cog1, cog2 OBJ IMU : "I2C_Wii" f : "F32" ESC : "ESC_Spin" PUB Stop 'stop all objects and cogs M_A := M_B := M_C := M_D := 1000 ESC.Stop f.Stop cogstop(cog1) 'cogstop(cog2) PUB Init(SCL, SDA, IMU_Mode) IMU.init( SCL,SDA,IMU_Mode ) ' Initialize the accelerometer / gyro IMU.enable ' Enable the Wii f.start ' Start the F32 Floating Point Math object KalmanInit( Accel_Trust, Gyro_Trust, Accel_Noise ) 'initialize the kalman filter xAngleInt := yAngleInt := 0 Delay_MS(500) ' Wait 1/2 second before initializing gyros ''/////////Acquire some center values////////////////////// IMU.readData 'Must be called before measurements are received IMU.readData 'retrieve center values Cgx := IMU.rotate_x Cgy := IMU.rotate_y Cgz := IMU.rotate_z Cax := IMU.accelX Cay := IMU.accelY Caz := IMU.accelZ Gyro_Accel_Compass_Calibrate PrevTime := cnt SP[0] := 0 'initialize set points to zero SP[1] := 0 SP[2] := 0 SP[3] := 0 SP[4] := 0 m := slope 'SET CONDITIONS AND GAINS. ONLY M AND KI ARE FLOATING POINT b := offset Kp := Proportional_Gain Ki := Integral_Gain Kd := Derivative_Gain Delay_MS(3000) cog1 := cognew(Flight_Control, @stack[0]) 'start new cog for PID loop return PUB Motor_Start ESC.Start 'start ESC object Delay_MS(1000) '''''''''''''''''''''''INITIALIZE ESC's AND MOTOR's'''''''''''''''''''''' ESC.Servo(Mtr_A,1000) 'initialize ESC's by sending a low pulse to each ESC.Servo(Mtr_B,1000) ESC.Servo(Mtr_C,1000) ESC.Servo(Mtr_D,1000) Delay_MS(500) return PUB Motor_Run ESC.Servo(Mtr_A, M_A) 'SEND OUTPUT PULSE TO MOTORS A, B, C, AND D ESC.Servo(Mtr_B, M_B) ESC.Servo(Mtr_C, M_C) ESC.Servo(Mtr_D, M_D) PUB PID(Pitch_Orient, Roll_Orient, SP_Pitch, SP_Roll, Rotate_Command, Alt_Command) SP[0] := 0 'SAVE SETPOINTS AND FEEDBACK SIGNAL IN SPECIFIED ARRAY SLOTS SP[1] := 0 SP[2] := 0 SP[3] := 0 'SP_Pitch SP[4] := 0 'SP_Roll Auto_Pitch := Pitch_Orient Auto_Roll := Roll_Orient SP_R := Rotate_Command Alt := Alt_Command return PUB Flight_Control | GX_PID, GY_PID, GZ_PID, AccX_PID, AccY_PID, FB[5], Pre_Error[5], e[5], P[5], I[5], D[5], dt[5], pre_dt[5], j '''''''''''''''''''''''FLIGHT CONTROL AND PID LOOP'''''''''''''''''''''''''''''''''''''''''''''''''' Update 'first get initial sensor values Pre_Error[0] := SP[0] - GyroXUnb 'set first error Pre_Error[1] := SP[1] - GyroYUnb Pre_Error[2] := SP[2] - GZ Pre_Error[3] := SP[3] - Acc_Pitch Pre_Error[4] := SP[4] - Acc_Roll I[0] := 0 'initialize integral to zero I[1] := 0 I[2] := 0 I[3] := 0 I[4] := 0 Repeat Update 'get sensor values FB[0] := GyroXUnb 'GX FB[1] := GyroYUnb 'GY FB[2] := 0 'GZ FB[3] := Acc_Pitch FB[4] := Acc_Roll Repeat j from 0 to 4 dt[j] := cnt 'get system counter values dt[j] := f.FSub(f.FFloat(dt[j]), pre_dt[j]) 'get difference of previous counter and current counter dt[j] := f.FMul(f.FFloat(dt[j]), HzToSec) 'convert system counts to sec e[j] := SP[j] - FB[j] 'error = set point - feedback I[j] := I[j] + (f.FRound(f.FMul(f.FFloat(e[j]), dt[j]))) 'integral D[j] := f.FRound(f.FDiv(f.FSub(f.FFloat(e[j]), Pre_Error[j]), dt[j])) 'derrivative Pre_Error[j] := e[j] 'previous error pre_dt[j] := dt[j] 'previous time GX_PID := (Kp * e[0]) + (f.FRound(f.FMul(Ki, f.FFloat(I[0])))) + (f.FRound(f.FMul(Kd, f.FFloat(D[0])))) 'multiply by gain values for each GY_PID := (Kp * e[1]) + (f.FRound(f.FMul(Ki, f.FFloat(I[1])))) + (f.FRound(f.FMul(Kd, f.FFloat(D[0])))) 'pid loop GZ_PID := (Kp * e[2]) + (f.FRound(f.FMul(Ki, f.FFloat(I[2])))) + (f.FRound(f.FMul(Kd, f.FFloat(D[0])))) AccX_PID := (Kp * e[3]) + (f.FRound(f.FMul(Ki, f.FFloat(I[3])))) + (f.FRound(f.FMul(Kd, f.FFloat(D[0])))) AccY_PID := (Kp * e[4]) + (f.FRound(f.FMul(Ki, f.FFloat(I[4])))) + (f.FRound(f.FMul(Kd, f.FFloat(D[0])))) ''/////////////////////////Motor Outputs for a + configuration////////////////////////////////////////////// M_A := ((-GY_PID + GZ_PID - AccX_PID - Auto_Pitch + SP_R + Alt + b)#>1100)<#2000 'add all to motor outputs M_B := ((GX_PID - GZ_PID - AccY_PID + Auto_Roll - SP_R + Alt + b)#>1100)<#2000 M_C := ((GY_PID + GZ_PID + AccX_PID + Auto_Pitch + SP_R + Alt + b)#>1100)<#2000 M_D := ((-GX_PID - GZ_PID + AccY_PID - Auto_Roll - SP_R + Alt + b)#>1100)<#2000 'Motor_Run 'output to motors count ++ PUB Update | radius ''/////////////Read in Wii MotionPlus and Wii Nunchuck Raw Values///////////////////// IMU.readData IMU.readData RawAx := IMU.accelX RawAy := IMU.accelY RawAz := IMU.accelZ RawGx := IMU.rotate_x RawGy := IMU.rotate_y RawGz := IMU.rotate_z RawCompass := IMU.Digital_Compass '''////////////////////////convert gyro data to deg/sec, Make sure to select fast mode or slow mode///////////////////// GZ := f.FRound(f.FMul(f.FDiv(f.FSub(f.FFloat(Cgz), f.FFloat(RawGz)), f.FDiv(f.FFloat(Cgz), Deg_Sec) ), G_Mode)) Ax := f.FRound(f.FAdd(f.FMul(f.FFloat(RawAx), aslope), aoffset)) Ay := f.FRound(f.FAdd(f.FMul(f.FFloat(RawAy), aslope), aoffset)) Az := f.FRound(f.FAdd(f.FMul(f.FFloat(RawAz), aslope), aoffset)) radius := ^^((Ax)*(Ax) + (Az)*(Az) + (Ay)*(Ay)) Acc_Pitch := f.FRound(f.FMul(f.Degrees(f.ACos(f.FDiv(f.FFloat(Ay),f.FFloat(radius)))), A_Mode))-AccXCen Acc_Roll := f.FRound(f.FMul(f.Degrees(f.ATan2(f.FFloat(Ax), f.FFloat(Az))), A_Mode))-AccYCen ''///////////////Convert Accelerometer and Gyro readings to radians/////////////////////// fAccelX := f.Radians(f.FAdd(f.FMul(slopeX, f.FFloat(RawAx)), offsetX)) fAccelY := f.Radians(f.FAdd(f.FMul(slopeY, f.FFloat(RawAy)), offsetY)) fGyroX := f.Radians(f.FMul(f.FDiv(f.FSub(f.FFloat(Cgx), f.FFloat(RawGx)), f.FDiv(f.FFloat(Cgx), Deg_Sec) ), G_Mode)) fGyroY := f.Radians(f.FMul(f.FDiv(f.FSub(f.FFloat(Cgy), f.FFloat(RawGy)), f.FDiv(f.FFloat(Cgy), Deg_Sec) ), G_Mode)) 'Compute the time delta CurTime := cnt DeltaTime := CurTime - PrevTime PrevTime := CurTime 'Convert the delta to seconds fDelta := f.FFloat(DeltaTime) fDelta := f.FMul(fDelta, HzToSec) 'Run the filter KalmanPredict( fGyroX, fGyroY, fDelta ) KalmanUpdate( fAccelX, fAccelY ) 'Produce the results xAngleInt := f.FRound(f.Degrees(xAngle)) yAngleInt := f.FRound(f.Degrees(yAngle)) GyroXUnb := f.FRound(f.Degrees(fGyroXUnb)) GyroYUnb := f.FRound(f.Degrees(fGyroYUnb)) return / ........................... / {{&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&''&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&''&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&''&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&''&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&''&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&}} <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "[URL]http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd[/URL]"> <html xmlns="[URL]http://www.w3.org/1999/xhtml[/URL]"> <html> <head> <style type=text/css> DIV {COLOR: #009900; } </style> <TITLE>Universal Ground Station</TITLE> <script type="text/javascript"> function GetDescriptionFor(e) { var result, code; if ((e.charCode) && (e.keyCode==0)) { result = "charCode: " + e.charCode; code = e.charCode; } else { result = "keyCode: " + e.keyCode; code = e.keyCode; } if (code == 97) setdirection(3) else if (code == 98) setdirection(2) else if (code == 99) setdirection(1) else if (code == 100) setdirection(0) else if (code == 101) loadXMLDoc('send.xml') return; } function MonitorKeyPress(e) { if (!e) e=window.event; var cell = document.getElementById("td-keypress"); cell.innerHTML = GetDescriptionFor(e); } document.onkeypress = MonitorKeyPress; var state = 4; function ajax_object() { if (window.XMLHttpRequest) { return new XMLHttpRequest(); } else if(window.ActiveXObject) { return new ActiveXObject("Microsoft.XMLHTTP"); } else { alert("Your Browser does not support AJAX!\nTry Firefox?"); } } //XmlHttpRequest object var directionReq = ajax_object(); function setdirection(directionstate) { state = directionstate; //alert("directionstate: " + directionstate); if (directionReq.readyState == 4 || directionReq.readyState == 0) { //ajax_request('http://192.168.1.120/shp.shp?directionstate=' + directionstate + '&ms=' + new Date().getTime(), null, function(data){ return }); directionReq.open("GET", 'http://192.168.1.120/shp.shp?directionstate=' + directionstate + '&ms=' + new Date().getTime(), true); directionReq.onreadystatechange = handledirectionState; directionReq.send(null); } } function handledirectionState() { if (directionReq.readyState == 4) { var div = document.getElementById('directionStatusIndicator'); var str = directionReq.responseText; //alert("response: " + directionReq); div.innerHTML = str; // if ((typeof(str) == 'undefined') || (str == '')) { //if (state > '0') { // div.innerHTML = "<strong style='color:orange;font-size:26px;'>On</strong>"; // } else { // div.innerHTML = "<strong style='color:gray;font-size:26px;'>Waiting for input</strong>"; //} //} else { // div.innerHTML = str; //var refreshIntervalId = (setInterval("loadXMLDoc('send.xml')",3500)); //} } } var xmlhttp = ajax_object(); function loadXMLDoc(url) { var txt,x,xx,i, j; //ajax_request("send.xml", null, function(data){ return }); xmlhttp.onreadystatechange=function() { if (xmlhttp.readyState==4 && xmlhttp.status==200) { txt="<table border='1'><tr><th>Acceleration X</th><th>Acceleration Y</th><th>Acceleration Z</th><th>Roll Degrees</th><th>Pitch Degrees</th><th>Yaw Degrees</th></tr>"; x=xmlhttp.responseXML.documentElement.getElementsByTagName("DATA"); for (i=0;i<x.length;i++) { txt=txt + "<tr>"; xx=x[i].getElementsByTagName("A_X"); { try { txt=txt + "<td>" + xx[0].firstChild.nodeValue + "</td>"; } catch (er) { txt=txt + "<td> </td>"; } } xx=x[i].getElementsByTagName("A_Y"); { try { txt=txt + "<td>" + xx[0].firstChild.nodeValue + "</td>"; } catch (er) { txt=txt + "<td> </td>"; } } xx=x[i].getElementsByTagName("A_Z"); { try { txt=txt + "<td>" + xx[0].firstChild.nodeValue + "</td>"; } catch (er) { txt=txt + "<td> </td>"; } } xx=x[i].getElementsByTagName("R_D"); { try { txt=txt + "<td>" + xx[0].firstChild.nodeValue + "</td>"; } catch (er) { txt=txt + "<td> </td>"; } } xx=x[i].getElementsByTagName("P_D"); { try { txt=txt + "<td>" + xx[0].firstChild.nodeValue + "</td>"; } catch (er) { txt=txt + "<td> </td>"; } } xx=x[i].getElementsByTagName("Y_D"); { try { txt=txt + "<td>" + xx[0].firstChild.nodeValue + "</td>"; } catch (er) { txt=txt + "<td> </td>"; } } txt=txt + "</tr>"; } txt=txt + "</table>"; document.getElementById('txtDATAInfo').innerHTML=txt; txt="<table border='1'><tr><th>Altitude in Inches</th><th>Behavior</th><th>Heading</th><th>Location</th><th>Battery Life</th><th>Sensor Feedback</th></tr>"; x=xmlhttp.responseXML.documentElement.getElementsByTagName("DATA"); for (j=0;j<x.length;j++) { txt=txt + "<tr>"; xx=x[j].getElementsByTagName("A_I"); { try { txt=txt + "<td>" + xx[0].firstChild.nodeValue + "</td>"; } catch (er) { txt=txt + "<td> </td>"; } } xx=x[j].getElementsByTagName("B"); { try { txt=txt + "<td>" + xx[0].firstChild.nodeValue + "</td>"; } catch (er) { txt=txt + "<td> </td>"; } } xx=x[j].getElementsByTagName("H"); { try { txt=txt + "<td>" + xx[0].firstChild.nodeValue + "</td>"; } catch (er) { txt=txt + "<td> </td>"; } } xx=x[j].getElementsByTagName("L"); { try { txt=txt + "<td>" + xx[0].firstChild.nodeValue + "</td>"; } catch (er) { txt=txt + "<td> </td>"; } } xx=x[j].getElementsByTagName("B_L"); { try { txt=txt + "<td>" + xx[0].firstChild.nodeValue + "</td>"; } catch (er) { txt=txt + "<td> </td>"; } } xx=x[j].getElementsByTagName("S_F"); { try { txt=txt + "<td>" + xx[0].firstChild.nodeValue + "</td>"; } catch (er) { txt=txt + "<td> </td>"; } } txt=txt + "</tr>"; } txt=txt + "</table>"; document.getElementById('txtDATA2Info').innerHTML=txt; } } xmlhttp.open("GET",url,true); xmlhttp.send(); //} //function begin(a) //{ //state = a //if (state == '0') {(setdirection(0));} //else if (state == '1') { // clearInterval(refreshIntervalId); // (setdirection(1)); // } //else if (state == '2') { // clearInterval(refreshIntervalId); // (setdirection(2)); // } //else if (state == '3') { // clearInterval(refreshIntervalId); // (setdirection(3)); // } //else { //var refreshIntervalId = (setInterval("loadXMLDoc('send.xml')",3500)); } //else {} //} </script> </head> <body bgcolor="#000000"> <div align=center><table border="10"cellpadding="0"cellspacing="1"width="640"height="480"><tr><td bgcolor="white"align="center"valign="middle"><img src="[URL="http://192.168.1.101:8070/video.mjpg%22%3E%3C/td%3E%3C/tr%3E%3C/table%3E%3C/div%3E%3Cbr"]http://192.168.1.101:8070/video.mjpg"></td></tr></table></div><br[/URL]> <div align=center> <input type="button" name="Up" value="Up" onclick="setdirection(0)" /><br> <input type="button" name="Left" value="Left" onclick="setdirection(1)" /> <input type="button" name="Right" value="Right" onclick="setdirection(2)" /><br> <input type="button" name="Down" value="Down" onclick="setdirection(3)" /><br> <div id="directionStatusIndicator"><strong style="color:green">Waiting for input.</strong> </div><br> <input type="button" name="Send Data" value="Send Data" onclick="loadXMLDoc('send.xml')" /> </div><br> <div align="center" id="txtDATAInfo"> </div><br> <div align="center" id="txtDATA2Info"> </div> </body> </html> {{&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&''&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&''&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&''&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&''&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&''&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&}} <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "[URL]http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd[/URL]"> <html xmlns="[URL]http://www.w3.org/1999/xhtml[/URL]"> <html> <head> <style type=text/css> DIV {COLOR: #009900; } </style> <TITLE>Universal Ground Station</TITLE> <script language="javascript" src="RXTXajax.js" type="text/javascript"></script> <script type="text/javascript"> var refreshIntervalId = (setInterval("loadXMLDoc('send.xml')",1100)); var state = 4; function ajax_request(url, data, callback) { var xhrobj = ajax_object(); xhrobj.open("GET", url); xhrobj.setRequestHeader("X-Requested-With", "XMLHttpRequest"); xhrobj.onreadystatechange = function() { if (xhrobj.readyState == 4 && xhrobj.status == 200) { if (xhrobj.responseText) { callback(xhrobj.responseText); } } }; xhrobj.send(data); } function begin(a) { state = a if (state == '0') {(setdirection(0));} else if (state == '1') { clearInterval(refreshIntervalId); (setdirection(1)); } else if (state == '2') { clearInterval(refreshIntervalId); (setdirection(2)); } else if (state == '3') { clearInterval(refreshIntervalId); (setdirection(3)); } else { (setInterval("loadXMLDoc('send.xml')",1100)); } //else {} } </script> </head> <body bgcolor="#000000" onLoad="begin(4);"> <div align=center><table border="10"cellpadding="0"cellspacing="1"width="640"height="480"><tr><td bgcolor="white"align="center"valign="middle"><img src="[URL="http://192.168.1.101:8070/video.mjpg%22%3E%3C/td%3E%3C/tr%3E%3C/table%3E%3C/div%3E%3Cbr"]http://192.168.1.101:8070/video.mjpg"></td></tr></table></div><br[/URL]> <div align=center> <input type="button" name="Up" value="Up" onclick="begin(0)" /><br> <input type="button" name="Left" value="Left" onclick="begin(1)" /> <input type="button" name="Right" value="Right" onclick="begin(2)" /><br> <input type="button" name="Down" value="Down" onclick="begin(3)" /> <div id="directionStatusIndicator"><strong style="color:green">Waiting for input.</strong> </div> </div><br> <div align="center" id="txtDATAInfo"> </div><br> <div align="center" id="txtDATA2Info"> </div> </body> </html>I will be happy to forward on the rest of our code per request.
I don't have pictures at work- will have to find more. It's too bad I can't load powerpoint files, or docs.
I have also attached our final project we submitted to our university.
-Albeit this report is geared towards someone unfamiliar with the Spinneret, it still contains the whole scope of what we were able to accomplish.
This is what our Spinneret can host.
-We have full two way communication via wifi.
A user can transmit and receive data to and from our U.A.V.
It also manages our IP video stream.
Control of the craft can be via computer, remote control, or smart phone.
-With simple networking we were able to accomplish this both locally and over the internet.
One of our biggest accomplishments, in conjunction with our Spinneret telemetry, was being able to design and build a high voltage circuit that could capture pulses from a GM tube. This data is also counted within another Propeller μC, transmitted to the Spinneret, and hosted on the webpage.
**We have since added many more commands(buttons), but I wanted to include this image in order to provide a visual of what our Spinneret is hosting.
M.K.,
Go ahead - I'm interested in reading more of your design and code.
Thanks,
John