Liste der Anhänge anzeigen (Anzahl: 5)
Keiner ne Meinung zu dem Regelungs-Problem?
Na gut.
Werd mich da schon durchwursteln, da gibts ein paar halbe Ideen zu.
Inzwischen bin ich so weit, dass ich den Roller per Fernsteuerung einigermassen gezielt fahren kann: Fahrsteuerung vor-und rückwärts und auch ne rudimentäre Lenkung sind bereits programmiert.
Rudimentär deshalb, weil lediglich das kurvenäussere Rad beschleunigt wird. Während der Fahrt reicht das im Grunde aus, aber ich mach das natürlich noch ordentlich.
Ausserdem kann er, mit dieser Lösung, im Stand praktisch kaum drehen: zwar funktioniert es auch dann, aber durch Korrekturen der Balanceregelung dreht er natürlich sofort zurück. Da kommt ne andere Strategie.
Aber: ich habs geschafft, in meiner engen Bastelbude hier gestern ne 8 zu fahren- unfallfrei. ;)
Heute will ich mal auf den Wäscheboden, da ist mehr Platz. Die Keycam kommt mit, ich hoffe, die kriegt da was brauchbares hin.
Inzwischen nen paar aktuelle Fotos von vor ner Stunde:
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo,
ich habe mir Gestern diese Excel-Simulation hier nach gebaut um mal zu sehen welcher Wert welche Auswirkungen hat. Ich fand`s ganz hilfreich um das ganze besser zu verstehen. Damit lässt sich auch das von RoboHolIC angesprochene "Überkorrigieren" gut darstellen.
Ich glaube bei mir liegt es zur Zeit am zu großen Spiel in den LEGO-Zahnrädern, die Drehrichtungsänderung ist einfach zu "ruppig".
Bei mir ist das aber auch so, dass das Verhalten besser wird wenn P=kleiner ist, I=größer, und D=0.
Anbei mein Arbeitsstand.
Code:
'*******************************************************************************
'*******************************************************************************
'**************************** BALANCE BOT V1.0 *********************************
'*******************************************************************************
'************************** 18.03.2014 by CYBORG *******************************
'*******************************************************************************
'*******************************************************************************
'****************************** Allgemein **************************************
$regfile = "m88adef.dat"
$crystal = 8000000
$hwstack = 48
$swstack = 48
$framesize = 48
$baud = 500000
'**************************** MPU-6050 GYRO ************************************
Config Scl = Portc.5 'Configure i2c SCL
Config Sda = Portc.4 'Configure i2c SDA
Declare Sub Mpu6050_write(byval Regadr As Byte , Byval Wert As Byte)
Declare Function Mpu6050_read(byval Regadr As Byte) As Byte
Declare Function Mpu6050_temp() As Single
Declare Function Mpu6050_accel(byval Mpu6050_const_h As Byte , Byval Mpu6050_const_l As Byte) As Single
Declare Function Mpu6050_gyro(byval Mpu6050_const_h As Byte , Byval Mpu6050_const_l As Byte) As Single
Dim Mpu6050_h As Byte
Dim Mpu6050_l As Byte
Dim Mpu6050_int As Integer
Dim Mpu6050_real As Single
Dim Mpu6050_chip As Byte
Dim Mpu6050_in As Byte
Dim Mpu6050_tmp(6) As Byte
Const Mpu6050_adr = &HD0 '&H68 ist 7-Bit-I2C-Adresse
Const Mpu6050_adr1 = &HD1
Const Mpu6050_who_am_i = &H75
Const Mpu6050_pwr_mgmt_1 = &H6B
Const Mpu6050_temp_h = &H41
Const Mpu6050_temp_l = &H42
Const Mpu6050_accx_h = &H3B
Const Mpu6050_accx_l = &H3C
Const Mpu6050_accy_h = &H3D
Const Mpu6050_accy_l = &H3E
Const Mpu6050_accz_h = &H3F
Const Mpu6050_accz_l = &H40
Const Mpu6050_gyrox_h = &H43
Const Mpu6050_gyrox_l = &H44
Const Mpu6050_gyroy_h = &H45
Const Mpu6050_gyroy_l = &H46
Const Mpu6050_gyroz_h = &H47
Const Mpu6050_gyroz_l = &H48
Dim Mpu6050_stemp As Single
Dim Mpu6050_accx As Single
Dim Mpu6050_accy As Single
Dim Mpu6050_accz As Single
Dim Mpu6050_gyrox As Single
Dim Mpu6050_gyroy As Single
Dim Mpu6050_gyroz As Single
'****************************** MOTOR - PWM ************************************
Config Timer1 = Pwm , Pwm = 10 , Compare_a_pwm = Clear_up , Compare_b_pwm = Clear_up , Prescale = 64
Motor_a_front Alias Portb.0 'Motor1 vorwärts
Motor_a_back Alias Portd.7 'Motor1 rückwärts
Motor_b_front Alias Portd.6 'Motor2 vorwärts
Motor_b_back Alias Portd.5 'Motor2 rückwärts
Config Motor_a_front = Output
Config Motor_a_back = Output
Config Motor_b_front = Output
Config Motor_b_back = Output
Motor_a_front = 0
Motor_a_back = 0
Motor_b_front = 0
Motor_b_back = 0
Wait 1
Dim Pwm_middle As Single
Dim Pwm_start As Single
Dim Pwm_limit As Integer
Dim Accel_middle As Single
Dim Accel_step As Single
Dim Accel_filter As Single
Dim Accel_revfilter As Single
Dim Gyro_middle As Single
Dim Gyro_step As Single
Dim Gyro_filter As Single
Dim Gyro_revfilter As Single
Dim Main_middle As Single
Pwm_middle = 0
Pwm_start = 0 '220
Pwm_limit = 1023
Accel_step = 200 '200
Accel_filter = 10 '10
Accel_revfilter = Accel_filter - 1
Gyro_step = 20 '20
Gyro_filter = 60 '60
Gyro_revfilter = Gyro_filter - 1
'****************************** PID - REGLER ***********************************
Declare Function Pid(byval Pid_ist As Single) As Single
Const P = 0.15
Const I = 0.7
Const D = 0.0
Dim Pid_soll As Single
Dim Pid_error(3) As Single
Dim Pid_ist As Single
Pid_soll = Pwm_middle
'****************************** Hauptprogramm **********************************
Mpu6050_chip = Mpu6050_read(mpu6050_who_am_i) 'Wer ist es?
If Mpu6050_chip = &H68 Then
Print " mpu6050 gefunden... "
End If
Call Mpu6050_write(mpu6050_pwr_mgmt_1 , 0) 'aus dem sleep-modus holen
Dim S As Single
Print " Neustart... "
Wait 1
Dim Z As Integer
Do
'ACCEL FILTER
Accel_middle = Accel_middle * Accel_revfilter
Mpu6050_accx = Mpu6050_accel(mpu6050_accx_h , Mpu6050_accx_l)
Mpu6050_accx = Mpu6050_accx * Accel_step
Accel_middle = Accel_middle + Mpu6050_accx
Accel_middle = Accel_middle / Accel_filter
'GYRO FILTER
Gyro_middle = Gyro_middle * Gyro_revfilter
Mpu6050_gyroy = Mpu6050_gyro(mpu6050_gyroy_h , Mpu6050_gyroy_l)
Mpu6050_gyroy = Mpu6050_gyroy * Gyro_step
Gyro_middle = Gyro_middle + Mpu6050_gyroy
Gyro_middle = Gyro_middle / Gyro_filter
'ACCEL + GYRO
Main_middle = Accel_middle - Gyro_middle
'PID
'Print "Ist " ; Main_middle ; " Soll " ; PID_ist
Main_middle = Pid(main_middle)
'PWM ermitteln
Z = Abs(main_middle)
Z = Z + Pwm_start
If Z > Pwm_limit Then
Z = 0
End If
'Drehrichtung festlegen
If Main_middle < Pwm_middle Then
Motor_a_front = 1
Motor_a_back = 0
Motor_b_front = 1
Motor_b_back = 0
Pwm1a = Z
Pwm1b = Z
Elseif Main_middle > Pwm_middle Then
Motor_a_front = 0
Motor_a_back = 1
Motor_b_front = 0
Motor_b_back = 1
Pwm1a = Z
Pwm1b = Z
End If
Loop
'**************************** MPU-6050 Functions *******************************
'****************************** MPU-6050 WRITE *********************************
Sub Mpu6050_write(regadr As Byte , Byval Wert As Byte)
I2cstart
I2cwbyte Mpu6050_adr
If Err = 0 Then
I2cwbyte Regadr
I2cwbyte Wert
End If
I2cstop
End Sub
'****************************** MPU-6050 READ **********************************
Function Mpu6050_read(regadr As Byte) As Byte
Mpu6050_in = 0
I2cstart
I2cwbyte Mpu6050_adr
If Err = 0 Then 'ACK empfangen
I2cwbyte Regadr
I2cstart
I2cwbyte Mpu6050_adr1
I2crbyte Mpu6050_in , Nack
End If
I2cstop
Mpu6050_read = Mpu6050_in
End Function
'****************************** MPU-6050 TEMP **********************************
Function Mpu6050_temp() As Single
Mpu6050_h = Mpu6050_read(mpu6050_temp_h)
Mpu6050_l = Mpu6050_read(mpu6050_temp_l)
Mpu6050_int = 256 * Mpu6050_h
Mpu6050_int = Mpu6050_int + Mpu6050_l
Mpu6050_real = Mpu6050_int * 0.294117647058823529411764705882 'vgl. S. 31 von RM_MPU-6000A.pdf
Mpu6050_real = Round(mpu6050_real)
Mpu6050_real = Mpu6050_real * 0.01
Mpu6050_real = Mpu6050_real + 36.53
Mpu6050_temp = Mpu6050_real
End Function
'***************************** MPU-6050 ACCEL **********************************
Function Mpu6050_accel(mpu6050_const_h As Byte , Mpu6050_const_l As Byte) As Single
Mpu6050_h = Mpu6050_read(mpu6050_const_h)
Mpu6050_l = Mpu6050_read(mpu6050_const_l)
Mpu6050_int = 256 * Mpu6050_h
Mpu6050_int = Mpu6050_int + Mpu6050_l
'1 g entspricht 2^14 = 16384 bei Standard-Range 2g; also Beschl = accel_x_int*9.81/16384
Mpu6050_accel = Mpu6050_int * 0.00059875
End Function
'***************************** MPU-6050 GYRO ***********************************
Function Mpu6050_gyro(mpu6050_const_h As Byte , Mpu6050_const_l As Byte) As Single
Mpu6050_h = Mpu6050_read(mpu6050_const_h)
Mpu6050_l = Mpu6050_read(mpu6050_const_l)
Mpu6050_int = 256 * Mpu6050_h
Mpu6050_int = Mpu6050_int + Mpu6050_l
'1 g entspricht 2^14 = 16384 bei Standard-Range 2g; also Beschl = accel_x_int*9.81/16384
Mpu6050_gyro = Mpu6050_int * 0.00763358778625954198473282442748
End Function
'***************************** MPU-6050 READ ***********************************
Read_gyro:
I2cstart
I2cwbyte Mpu6050_adr
I2cwbyte Mpu6050_gyrox_h
I2crepstart
I2cwbyte Mpu6050_adr1
I2crbyte Mpu6050_tmp(1) , Ack
I2crbyte Mpu6050_tmp(2) , Ack
I2crbyte Mpu6050_tmp(3) , Ack
I2crbyte Mpu6050_tmp(4) , Ack
I2crbyte Mpu6050_tmp(5) , Ack
I2crbyte Mpu6050_tmp(6) , Nack
I2cstop
Return
'******************************* PID Functions *********************************
'******************************** PID -Regler **********************************
Function Pid(pid_ist As Single ) As Single
Local P_temp As Single
Local I_temp As Single
Local D_temp As Single
'P-Anteil
P_temp = P * Pid_error(3)
P_temp = P_temp + Pid_ist
'I-Anteil
I_temp = Pid_error(3) - Pid_error(2)
I_temp = I_temp * I
'D-Anteil
D_temp = Pid_error(3) + Pid_error(2)
D_temp = D_temp + Pid_error(1)
D_temp = D_temp * D
'PID-Errors
Pid_error(1) = Pid_error(2)
Pid_error(2) = Pid_error(3)
Pid_error(3) = Pid_soll - Pid_ist
'Print "Err1" ; PID_error(1) ; " Err2 " ; PID_error(2) ; " Err3 " ; PID_error(3)
'PID-Anteil
Pid = P_temp + I_temp
Pid = Pid + D_temp
'Print "PID " ; PID ; " IST " ; PID_ist
End Function
mfG
Mario