Hallo,
da ich jetzt einen Quadrocopter plane, will ich alle Teile von meinem Tri nochmal gut überarbeiten, aber im Groben und Ganzen so belassen (da ich von vornherein alles so gemacht habe, dass man mit wenigen Handgriffen das Ganze auf 4 Motoren einstellen kann). Jetzt stellt sich mir allerdings die Frage, ob es nicht besser wäre, die Kommunikation der beiden AVRs (ATMEGA328P - Master // ATTINY2313 - Slave), welche momentan über UART läuft, auf I2C umzustellen, da ich als Sensor eine Wii Motion Plus verwende und ich somit nur noch einen "Bus" hätte. Außerdem kann ich ja bei I2C nach der Übertragung das ERR-Flag überprüfen, ob die Daten erfolgreich gesendet wurden! (Ist in I2C eig. schon eine Checksumme o.ä. integriert??) Das würde bei UART nur durch eine Rückmeldung funktionieren, welche mir wieder Performance wegnimmt...
Allerdings stellt sich mir die Frage: Was ist den insgesamt (also Geschwindigkeit, Störanfälligkeit, Performance, etc...) besser? Als Levelconverter (5V <--> 3V3) verwende ich 2 Mosfets.
Ich persönlich würde eher zu UART tendieren, da diese auf meinem Tri mit momentan 1.000.000 baud läuft und somit mein Regelkreis mit ca. 500Hz läuft, das wird aber noch viel weiter optimiert! Es werden (kurz getestet, allerdings bis jetzt nur, wenn die Motoren aus waren) 1000 von 1000 Datenpaketen korrekt auf dem Slave (start-byte ; _bl(1-4) ; _crc) empfangen. Eine Datenübertragung dauert bei mir ca. 235µs. Ist das mit I2C (100kHz) zu erreichen? Hab da noch nie wirklich etwas gemacht, außer beim WM+. Deswegen kann ich auch nur mit 100kHz takten, da die I2C Schnittstelle des WM+ nur mit dieser Taktrate richtig funktioniert.... (BTW: Kennt jemand eine erfolgreich-getestete Bascom-Implementation des Passthrough-Modus mit WM+ und Nunchuk?? Habs bis jetzt nur selten in C gesehen, das hab ich aber nicht verstanden...)
Wäre nett, wenn ihr einfach mal ein paar Meinungen postet
Hier noch der Code (Master)
Slave:Code:$regfile = "m328pdef.dat" $crystal = 16000000 $framesize = 200 $hwstack = 200 $swstack = 200 $baud = 1000000 '115200 Open "COMC.3:19200,8,N,1" For Input As #1 Open "COMC.2:19200,8,N,1" For Output As #2 Declare Sub Init_system() Declare Sub Filter_gyro_data() Declare Sub Filter_rx_data() Declare Sub Mixer() Declare Sub Send_data() Declare Sub Pid_regulator() Declare Sub Wmp_init() Declare Sub Send_zero() Declare Sub Read_wmp_data() Declare Sub Set_wmp_offset() $lib "I2C_TWI.LBX" Config Scl = Portc.5 Config Sda = Portc.4 Config Twi = 100000 I2cinit Config Timer0 = Timer , Prescale = 256 On Timer0 Pausedetect Enable Timer0 Config Int0 = Falling On Int0 Measure Enable Int0 Config Pind.2 = Input Portd.2 = 0 Config Portd.4 = Output Led Alias Portd.4 Led = 0 '#################################### '###########KONSTANTEN############### '#################################### Const _maxchannel = 8 Const Start_byte = 127 Const _throttlechannel = 1 Const _rollchannel = 2 Const _pitchchannel = 3 Const _yawchannel = 4 Const _statechannel = 5 Const _datachannel = 6 Const _bl4offset = 0 Const _max_d_state = 3 '################################### '################################### '################################### '################################### '###########PID-PARAMETER########### '################################### Dim _yaw_kp As Single Dim _roll_kp As Single Dim _pitch_kp As Single Dim _yaw_ki As Single Dim _roll_ki As Single Dim _pitch_ki As Single Dim _yaw_kd As Single Dim _roll_kd As Single Dim _pitch_kd As Single '#########PID-Werte############ '( P : 0.675000008 : 1.049999949 I : 0.00139999 : 0.004399952 D: ') '############################## _yaw_kp = 1.5 _roll_kp = 0.675000008 _pitch_kp = 1.049999949 _yaw_ki = 0 _roll_ki = 0.00139999 _pitch_ki = 0.004399952 _yaw_kd = 0 _roll_kd = 0 _pitch_kd = 0.00079995 '################################### '################################### '################################### '################################### '###############TMP################# '################################### Dim _btm222_counter As Byte Dim I As Byte Dim Newvalsreceived As Bit '################################### '################################### '################################### '################################### '#########RC-EMPFÄNGER############## '################################### Dim Bufferbyte As Byte Dim Kanal(_maxchannel) As Word Dim _lp_bandwidth As Byte Dim _hkanal(_maxchannel) As Word Dim _lkanal(_maxchannel) As Word Dim _kanal_filter(_maxchannel) As Word Dim Channel As Byte Dim _bl(4) As Word Dim _crc As Word Dim _sbl(_maxchannel) As Integer Dim _sbl_filter(_maxchannel) As Integer '################################### '################################### '################################### '################################### '###########I2C-Inputs############## '################################### Dim Wmplus_buffer(6) As Byte '################################### '################################### '################################### '################################### '#########GYRO###################### '################################### Dim Yaw As Word Dim Yaw0 As Byte At Yaw + 1 Overlay Dim Yaw1 As Byte At Yaw Overlay Dim Roll As Word Dim Roll0 As Byte At Roll + 1 Overlay Dim Roll1 As Byte At Roll Overlay Dim Pitch As Word Dim Pitch0 As Byte At Pitch + 1 Overlay Dim Pitch1 As Byte At Pitch Overlay Dim _yawoffset As Long Dim _rolloffset As Long Dim _pitchoffset As Long Dim _yawoffset_int As Integer Dim _rolloffset_int As Integer Dim _pitchoffset_int As Integer Dim _yawnow As Integer Dim _rollnow As Integer Dim _pitchnow As Integer '################################### '################################### '################################### '################################## '#########PID-REGLER############### '################################## Dim _d_state As Byte Dim _yaw_kp_err As Single Dim _roll_kp_err As Single Dim _pitch_kp_err As Single Dim _yaw_ki_err As Single Dim _roll_ki_err As Single Dim _pitch_ki_err As Single Dim _yaw_ki_sum As Single Dim _roll_ki_sum As Single Dim _pitch_ki_sum As Single Dim _yaw_kd_err_single As Single Dim _roll_kd_err_single As Single Dim _pitch_kd_err_single As Single Dim _yaw_kd_err(_max_d_state) As Single Dim _roll_kd_err(_max_d_state) As Single Dim _pitch_kd_err(_max_d_state) As Single Dim _yaw_kd_old(_max_d_state) As Single Dim _roll_kd_old(_max_d_state) As Single Dim _pitch_kd_old(_max_d_state) As Single Dim _yaw_pid_int As Integer Dim _roll_pid_int As Integer Dim _pitch_pid_int As Integer Dim _yaw_pid As Single Dim _roll_pid As Single Dim _pitch_pid As Single Dim _yaw_err_int As Integer Dim _roll_err_int As Integer Dim _pitch_err_int As Integer Dim _yaw_err As Single Dim _roll_err As Single Dim _pitch_err As Single '################################# '################################# '################################# Dim _yawstickvel As Integer Dim _rollstickvel As Integer Dim _pitchstickvel As Integer Dim _sbl_old(_maxchannel) As Integer Dim _x1 As Single Dim _x2 As Single Wait 2 Call Init_system() Enable Interrupts Do Call Filter_rx_data() '580 Call Filter_gyro_data() '1900 Call Pid_regulator() '700 Call Mixer() '210 Call Send_data() '470 Loop Sub Filter_gyro_data() Call Read_wmp_data() _yawnow = Yaw - _yawoffset_int _rollnow = Roll - _rolloffset_int _pitchnow = Pitch - _pitchoffset_int End Sub Sub Filter_rx_data() If Newvalsreceived = 1 Then Newvalsreceived = 0 If Kanal(_throttlechannel) >= 60 And Kanal(_throttlechannel) <= 140 Then _sbl(_throttlechannel) = Kanal(_throttlechannel) - 100 _sbl(_throttlechannel) = _sbl(_throttlechannel) * 30 If _sbl(_throttlechannel) > 900 Then _sbl(_throttlechannel) = 900 If _sbl(_throttlechannel) < -1000 Then _sbl(_throttlechannel) = -1000 End If For I = 2 To _maxchannel If Kanal(i) >= 60 And Kanal(i) <= 140 Then _sbl(i) = Kanal(i) - 100 If _sbl(i) > -2 And _sbl(i) < 2 Then _sbl(i) = 0 _sbl(i) = _sbl(i) * 25 End If Next I _sbl_filter(_throttlechannel) = _sbl_filter(_throttlechannel) + _sbl(_throttlechannel) _sbl_filter(_throttlechannel) = _sbl_filter(_throttlechannel) / 2 _sbl(_throttlechannel) = _sbl_filter(_throttlechannel) _sbl_filter(_rollchannel) = _sbl_filter(_rollchannel) + _sbl(_rollchannel) _sbl_filter(_rollchannel) = _sbl_filter(_rollchannel) / 2 _sbl(_rollchannel) = _sbl_filter(_rollchannel) _sbl_filter(_pitchchannel) = _sbl_filter(_pitchchannel) + _sbl(_pitchchannel) _sbl_filter(_pitchchannel) = _sbl_filter(_pitchchannel) / 2 _sbl(_pitchchannel) = _sbl_filter(_pitchchannel) _sbl_filter(_yawchannel) = _sbl_filter(_yawchannel) + _sbl(_yawchannel) _sbl_filter(_yawchannel) = _sbl_filter(_yawchannel) / 2 _sbl(_yawchannel) = _sbl_filter(_yawchannel) _sbl_filter(_statechannel) = _sbl_filter(_statechannel) * 19 _sbl_filter(_statechannel) = _sbl_filter(_statechannel) + _sbl(_statechannel) _sbl_filter(_statechannel) = _sbl_filter(_statechannel) / 20 _sbl(_statechannel) = _sbl_filter(_statechannel) _sbl_filter(_datachannel) = _sbl_filter(_datachannel) + _sbl(_datachannel) _sbl_filter(_datachannel) = _sbl_filter(_datachannel) / 2 _sbl(_datachannel) = _sbl_filter(_datachannel) If _sbl(_statechannel) < 200 Then _sbl(_rollchannel) = _sbl(_rollchannel) / 5 '5 _sbl(_pitchchannel) = _sbl(_pitchchannel) / 5 Elseif _sbl(_statechannel) > 200 Then _sbl(_rollchannel) = _sbl(_rollchannel) / 2 '3 _sbl(_pitchchannel) = _sbl(_pitchchannel) / 3 End If _sbl(_yawchannel) = _sbl(_yawchannel) / 2 _rollstickvel = _sbl(_rollchannel) - _sbl_old(_rollchannel) _rollstickvel = _rollstickvel / 10 _sbl_old(_rollchannel) = _sbl(_rollchannel) _pitchstickvel = _sbl(_pitchchannel) - _sbl_old(_pitchchannel) _pitchstickvel = _pitchstickvel / 10 _sbl_old(_pitchchannel) = _sbl(_pitchchannel) '( _kanal_filter(7) = _kanal_filter(7) * 3 _kanal_filter(7) = _kanal_filter(7) + Kanal(7) Shift _kanal_filter(7) , Right , 2 Kanal(7) = _kanal_filter(7) _kanal_filter(8) = _kanal_filter(8) * 3 _kanal_filter(8) = _kanal_filter(8) + Kanal(8) Shift _kanal_filter(8) , Right , 2 Kanal(8) = _kanal_filter(8) ') '( '#########P-GAIN########### _x1 = Kanal(7) - 100 _x1 = _x1 * 0.075 _x2 = Kanal(8) - 100 _x2 = _x2 * 0.075 _roll_kp = 0 + _x1 _pitch_kp = 0 + _x2 '#########I-GAIN########### _x1 = Kanal(7) - 100 _x1 = _x1 * 0.0002 _x2 = Kanal(8) - 100 _x2 = _x2 * 0.0002 _roll_ki = 0.0 + _x1 _pitch_ki = 0.0 + _x2 '#########D-GAIN########### _x1 = Kanal(7) - 100 _x1 = _x1 * 0.0002 _x2 = Kanal(8) - 100 _x2 = _x2 * 0.0002 _roll_kd = 0.0 + _x1 _pitch_kd = 0.0 + _x2 ') If _sbl(_pitchchannel) > 170 And _sbl(_yawchannel) > 200 And _sbl(_throttlechannel) < -950 And _sbl(_statechannel) < -200 Then Call Set_wmp_offset() Led = 0 If _sbl(_datachannel) > -200 Then Print #2 , "OFFSET neu berechnet!" End If End If End If End Sub Measure: If Channel > 0 And Channel < 9 Then Kanal(channel) = Timer0 End If Timer0 = 6 Incr Channel Return Pausedetect: If Channel <> 0 Then Newvalsreceived = 1 End If Channel = 0 Return Sub Wmp_init() I2cstart I2cwbyte &HA6 I2cwbyte &HFE I2cwbyte &H04 I2cstop End Sub Sub Send_zero() I2cstart I2cwbyte &HA4 I2cwbyte &H00 I2cstop End Sub Sub Read_wmp_data() Gosub Send_zero I2creceive &HA4 , Wmplus_buffer(1) , 0 , 6 Yaw1 = Wmplus_buffer(1) Roll1 = Wmplus_buffer(2) Pitch1 = Wmplus_buffer(3) Shift Wmplus_buffer(4) , Right , 2 : Yaw0 = Wmplus_buffer(4) Shift Wmplus_buffer(5) , Right , 2 : Roll0 = Wmplus_buffer(5) Shift Wmplus_buffer(6) , Right , 2 : Pitch0 = Wmplus_buffer(6) Shift Yaw , Right , 2 Shift Roll , Right , 2 Shift Pitch , Right , 2 End Sub Sub Set_wmp_offset() _yawoffset = 0 _rolloffset = 0 _pitchoffset = 0 For I = 1 To 100 Waitms 5 Call Read_wmp_data() _yawoffset = _yawoffset + Yaw _rolloffset = _rolloffset + Roll _pitchoffset = _pitchoffset + Pitch Toggle Led Next I Led = 0 _yawoffset = _yawoffset / 100 _rolloffset = _rolloffset / 100 _pitchoffset = _pitchoffset / 100 _yawoffset_int = _yawoffset _rolloffset_int = _rolloffset _pitchoffset_int = _pitchoffset End Sub Sub Pid_regulator() '##############FEHLER_BERECHNEN########## '( _yaw_err_int = _sbl(_yawchannel) - _yawnow _yaw_err = _yaw_err_int _roll_err_int = _sbl(_rollchannel) - _rollstickvel _roll_err_int = _roll_err_int - _rollnow _roll_err = _roll_err_int _pitch_err_int = _sbl(_pitchchannel) - _pitchstickvel _pitch_err_int = _pitch_err_int - _rollnow _pitch_err = _pitch_err_int ') _yaw_err_int = _sbl(_yawchannel) - _yawnow _yaw_err = _yaw_err_int _roll_err_int = _sbl(_rollchannel) - _rollnow _roll_err = _roll_err_int _pitch_err_int = _sbl(_pitchchannel) - _pitchnow _pitch_err = _pitch_err_int '##############PROPORTIONAL############## _yaw_kp_err = _yaw_err * _yaw_kp _roll_kp_err = _roll_err * _roll_kp _pitch_kp_err = _pitch_err * _pitch_kp '##############INTEGRAL################## _yaw_ki_err = _yaw_err * _yaw_ki _yaw_ki_sum = _yaw_ki_sum + _yaw_ki_err _roll_ki_err = _roll_err * _roll_ki _roll_ki_sum = _roll_ki_sum + _roll_ki_err _pitch_ki_err = _pitch_err * _pitch_ki _pitch_ki_sum = _pitch_ki_sum + _pitch_ki_err '##############DIFFERENTIAL############# Incr _d_state If _d_state > _max_d_state Then _d_state = 1 _yaw_kd_err(_d_state) = _yaw_err * _yaw_kd _yaw_kd_err(_d_state) = _yaw_kd_err(_d_state) - _yaw_kd_old(_d_state) 'evtl. anders herum!!!!!!!!!! _yaw_kd_old(_d_state) = _yaw_kd_err(_d_state) _roll_kd_err(_d_state) = _roll_err * _roll_kd _roll_kd_err(_d_state) = _roll_kd_err(_d_state) - _roll_kd_old(_d_state) 'evtl. anders herum!!!!!!!!!! _roll_kd_old(_d_state) = _roll_kd_err(_d_state) _pitch_kd_err(_d_state) = _pitch_err * _pitch_kd _pitch_kd_err(_d_state) = _pitch_kd_err(_d_state) - _pitch_kd_old(_d_state) 'evtl. anders herum!!!!!!!!!! _pitch_kd_old(_d_state) = _pitch_kd_err(_d_state) _yaw_kd_err_single = _yaw_kd_err(_d_state) _roll_kd_err_single = _roll_kd_err(_d_state) _pitch_kd_err_single = _pitch_kd_err(_d_state) '##############AUFSUMMIEREN############## _yaw_pid = _yaw_kp_err + _yaw_ki_sum _yaw_pid = _yaw_pid + _yaw_kd_err_single _yaw_pid_int = _yaw_pid _roll_pid = _roll_kp_err + _roll_ki_sum _roll_pid = _roll_pid + _roll_kd_err_single _roll_pid_int = _roll_pid _pitch_pid = _pitch_kp_err + _pitch_ki_sum _pitch_pid = _pitch_pid + _pitch_kd_err_single _pitch_pid_int = _pitch_pid '###############WERTE_BEGRENZEN########## If _yaw_pid_int < -1000 Then _yaw_pid_int = -1000 If _yaw_pid_int > 1000 Then _yaw_pid_int = 1000 If _roll_pid_int < -1000 Then _roll_pid_int = -1000 If _roll_pid_int > 1000 Then _roll_pid_int = 1000 If _pitch_pid_int < -1000 Then _pitch_pid_int = -1000 If _pitch_pid_int > 1000 Then _pitch_pid_int = 1000 End Sub Sub Mixer() _bl(1) = 62667 - _sbl(_throttlechannel) _bl(2) = _bl(1) _bl(3) = _bl(1) _bl(4) = 62667 _bl(4) = _bl(4) + _bl4offset If _sbl(_statechannel) > -200 Then _bl(1) = _bl(1) + _pitch_pid_int _bl(2) = _bl(2) - _roll_pid_int _bl(3) = _bl(3) + _roll_pid_int _pitch_pid_int = _pitch_pid_int / 2 _bl(2) = _bl(2) - _pitch_pid_int _bl(3) = _bl(3) - _pitch_pid_int _bl(4) = _bl(4) - _yaw_pid_int Led = 1 Elseif _sbl(_statechannel) < -200 Then _bl(1) = 63800 _bl(2) = 63800 _bl(3) = 63800 For I = 0 To _max_d_state _yaw_kd_err(i) = 0 _yaw_kd_old(i) = 0 _roll_kd_err(i) = 0 _roll_kd_old(i) = 0 _pitch_kd_err(i) = 0 _pitch_kd_old(i) = 0 Next I _yaw_kp_err = 0 _yaw_ki_sum = 0 _yaw_kd_err_single = 0 _yaw_ki_err = 0 _roll_kp_err = 0 _roll_ki_sum = 0 _roll_kd_err_single = 0 _roll_ki_err = 0 _pitch_kp_err = 0 _pitch_ki_sum = 0 _pitch_kd_err_single = 0 _pitch_ki_err = 0 _yaw_pid_int = 0 _roll_pid_int = 0 _pitch_pid_int = 0 _yaw_pid = 0 _roll_pid = 0 _pitch_pid = 0 Led = 0 End If End Sub Sub Send_data() _crc = Crc16(_bl(1) , 4) Printbin Start_byte Incr _btm222_counter If _btm222_counter = 20 Then _btm222_counter = 0 If _sbl(_datachannel) > -200 Then 'Print #2 , _roll_kp ; ":" ; _pitch_kp 'Print #2 , _roll_ki ; ":" ; _pitch_ki 'Print #2 , _roll_kd ; ":" ; _pitch_kd 'Print #2 , _sbl(_throttlechannel) ; ":" ; _sbl(_rollchannel) ; ":" ; _sbl(_pitchchannel) ; ":" ; _sbl(_yawchannel) ; ":" ; _sbl(_statechannel) ; ":" ; _sbl(_datachannel) End If End If Printbin _bl(1) ; _bl(2) ; _bl(3) ; _bl(4) ; _crc End Sub Sub Init_system() _sbl_filter(_throttlechannel) = -1000 _sbl_filter(_rollchannel) = 0 _sbl_filter(_pitchchannel) = 0 _sbl_filter(_yawchannel) = 0 _sbl_filter(_statechannel) = -600 _sbl_filter(_datachannel) = -600 Reset Newvalsreceived _yawnow = 0 _rollnow = 0 _pitchnow = 0 Call Wmp_init() Wait 1 For I = 1 To 50 Call Read_wmp_data() Next I Wait 1 Call Set_wmp_offset() For I = 1 To 5 Led = 1 Waitms 20 Led = 0 Waitms 100 Next I End Sub End
Vielen Dank & GrußCode:$regfile = "attiny2313.dat" $crystal = 16000000 $framesize = 30 $hwstack = 32 $swstack = 30 $baud = 1000000 '115200 Config Timer1 = Timer , Prescale = 8 Timer1 = 62535 On Timer1 Servoirq Enable Timer1 Config Servos = 1 , Servo1 = Portd.5 , Reload = 10 Config Portd.2 = Output Config Portd.3 = Output Config Portd.4 = Output Config Portd.5 = Output Dim Kanal As Byte Dim _servo(4) As Word Dim _bl(4) As Word Dim I As Word Dim _crc As Word Dim _start As Byte 'min: 63800, mitte: 62667.5 , max: 61535 --> 2265 Schritte Const _servo_teiler = 20 Const Start_byte = 127 Const Min_servo = 63800 Const Max_servo = 61535 Const Diff_servo = Max_servo - Min_servo For I = 1 To 3 _bl(i) = Min_servo _servo(i) = _bl(i) Next I Servo(1) = 100 Enable Interrupts Wait 3 Do If Ischarwaiting() > 0 Then Inputbin _start If _start = Start_byte Then Inputbin _bl(1) , _bl(2) , _bl(3) , _bl(4) , _crc If _crc = Crc16(_bl(1) , 4) Then For I = 1 To 4 If _bl(i) < Max_servo Then _bl(i) = Max_servo If _bl(i) > Min_servo Then _bl(i) = Min_servo _servo(i) = _bl(i) Next I _servo(4) = _servo(4) - 61535 _servo(4) = _servo(4) / _servo_teiler Servo(1) = 50 + _servo(4) End If End If End If Loop Servoirq: If Kanal = 0 Then If Portd.2 = 0 Then 'wenn port low Timer1 = _servo(1) 'dann timer auf entsprechende verzögerung Portd.2 = 1 'und port anschalten Else 'das hier passiert erst bei dem darauf folgenden interrupt Portd.2 = 0 'dann port wieder ausschalten Incr Kanal 'und den nächsten kanal bearbeiten End If End If If Kanal = 1 Then If Portd.3 = 0 Then Timer1 = _servo(2) Portd.3 = 1 Else Portd.3 = 0 Incr Kanal End If End If If Kanal = 2 Then If Portd.4 = 0 Then Timer1 = _servo(3) Portd.4 = 1 Else Portd.4 = 0 Incr Kanal End If End If If Kanal = 3 Then Timer1 = 65535 Kanal = 0 End If '( If Kanal = 3 Then If Portd.5 = 0 Then Timer1 = _servo(4) Portd.5 = 1 Else Portd.5 = 0 Incr Kanal End If End If If Kanal = 4 Then Timer1 = 40000 '65535 | eine pause von ca. 12ms bis zum nächsten interrupt. Bei guten Servos oder Brushlessreglern kann man hier bis auf 65530 gehen ==> ansteuerfrequenz von ~ 200Hz Kanal = 0 End If ') Return End
Chris
EDIT: Kann man in Bascom überhaupt einen Slave (Hardware I2C) vernünftig konfigurieren? Also mit Interrupt usw... Oder denkt ihr, UART ist einfacher?







Zitieren

Lesezeichen