- 3D-Druck Einstieg und Tipps         
Ergebnis 1 bis 8 von 8

Thema: Problem bei SingleShunt Strommessung für BLDC

  1. #1
    Neuer Benutzer Öfters hier
    Registriert seit
    11.04.2011
    Beiträge
    6

    Problem bei SingleShunt Strommessung für BLDC

    Anzeige

    Powerstation Test
    Hallo zusammen,

    der Beitrag ist recht lang geworden, es würde mich trotzdem freuen, wenn sich jemand die Zeit nimmt ihn zu lesen.
    Ich versuche gerade einen BLDC-Regler mit feldorientierter Regelung und
    singleshunt Strommessung aufzubauen. Allerdings stellen mich die
    Messergebnisse nicht ganz zufrieden. Vielleicht hat ja jemand Erfahrung
    damit und kann mir dabei etwas helfen. Für die Strommessung verwende ich
    einen ACS709 Hall-Effekt-Stromsensor. Im Anhang mal ein Screenshot, wie
    die Ströme aktuell aussehen.
    Klicke auf die Grafik für eine größere Ansicht

Name:	18.01.jpg
Hits:	23
Größe:	40,0 KB
ID:	29648

    Die Ströme werden zweimal pro PWM-Periode gemessen und über das
    Kirchhoffsches Gesetz der jeweils fehlende dritte Strom berechnet.
    Des Prinzip wird auch hier nochmals erklärt: http://ww1.microchip.com/downloads/e...tes/01299A.pdf
    Ich weiß nun nicht, ob der Fehler bereits in der Hardware liegt oder in meiner Software.

    Als Mikrocontroller verwende ich einen STM32F103C8.
    Timer 1 verwende ich zu PWM Erzeugung. Dieser zählt von 0 bis 2048 und
    dann wieder runter auf 0. Timer 3 läuft synchron zählt aber von 0 bis
    4095. Damit triggere ich den ADC. Dabei wird in der ISR von Timer 3 der
    neue Vergleichswert für die Zweite triggerung des ADCs geladen. In der
    ADC-ISR wird dann wieder der Wert für die erste Triggerung geladen.

    Init des Timer 3:
    Code:
    void ADC_Timer_ini()
    {
      RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
      TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    
      TIM_TimeBaseStructure.TIM_Prescaler =  0;
    
      TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
      TIM_TimeBaseStructure.TIM_Period = 4095;
      TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
      TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
    
      TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
      TIM_UpdateRequestConfig(TIM3, TIM_UpdateSource_Global);
      TIM_UpdateDisableConfig(TIM3,DISABLE);
      TIM_Cmd(TIM3, ENABLE);
    }
    
    void ADC_Timer_Compare_ini()
    {
      TIM_OCInitTypeDef TIM_OCInitStructure;
    
      TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;
      TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
      TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;
      TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
      TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;
      TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
      TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Set;
      TIM_OCInitStructure.TIM_Pulse = 2048;
      TIM_OC4Init(TIM3, &TIM_OCInitStructure);
    
      TIM_OCInitStructure.TIM_Pulse = 1024;
    
      TIM_OC1Init(TIM3, &TIM_OCInitStructure);
      TIM_OCInitStructure.TIM_Pulse = 3072;
      TIM_OC3Init(TIM3, &TIM_OCInitStructure);
      TIM_DMACmd(TIM3, TIM_DMA_CC1, ENABLE);
      TIM_DMACmd(TIM3, TIM_DMA_CC3, ENABLE);
    }
    
    void ADC_Timer_Interrupt_ini()
    {
      NVIC_InitTypeDef NVIC_InitStructure;
    
      NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn  ;
      NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
      NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
      NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
      NVIC_Init(&NVIC_InitStructure);
    
      TIM_ITConfig(TIM3, TIM_IT_CC4, ENABLE);
    }
    Ini des Timer 1:
    Code:
    void PWMTimer_ini()
    {
      RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
      TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    
       TIM_TimeBaseStructure.TIM_Prescaler =  0;
    
      TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_CenterAligned1;
      TIM_TimeBaseStructure.TIM_Period = 2048;
      TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
      TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
    
      TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
      TIM1->CR1 |= TIM_CR1_URS;  // Nur Over- bzw. Underflow erzeugt Update event
      TIM_UpdateRequestConfig(TIM1, TIM_UpdateSource_Regular);
      TIM_UpdateDisableConfig(TIM1,DISABLE);
      TIM_Cmd(TIM1, ENABLE);
    
      TIM_DMAConfig(TIM1, TIM_DMABase_CCR1, TIM_DMABurstLength_3Transfers);
    }
    
    void PWMChannel_ini()
    {
      TIM_OCInitTypeDef TIM_OCInitStructure;
      TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;
      TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
      TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;
      TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
      TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_Low;
      TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
        TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Set;
    
        TIM_OCInitStructure.TIM_Pulse = 0;
    
        TIM_OC1Init(TIM1, &TIM_OCInitStructure);
        TIM_OC2Init(TIM1, &TIM_OCInitStructure);
        TIM_OC3Init(TIM1, &TIM_OCInitStructure);
    
        TIM_CtrlPWMOutputs(TIM1, ENABLE);
    
        TIM1->CCMR1 |= TIM_CCMR1_OC1PE | TIM_CCMR1_OC2PE;  // Compare-Werte erst beim Update-Event übernehmen
        TIM1->CCMR2 |= TIM_CCMR2_OC3PE;            // Compare-Werte erst beim Update-Event übernehmen
    }
    ADC Ini:
    Code:
    void ADC_2_ini(void)
    {
      RCC_ADCCLKConfig(RCC_PCLK2_Div6);  // ADC Takt max 14MHz.  72MHz/6 = 12MHz
      RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC2, ENABLE);
    
      ADC_InitTypeDef ADC_InitStructure;
      ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
      ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
      ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
      ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
      ADC_InitStructure.ADC_NbrOfChannel = 1;
      ADC_InitStructure.ADC_ScanConvMode = ENABLE;
      ADC_Init(ADC2, &ADC_InitStructure);
    
      ADC_InjectedSequencerLengthConfig(ADC2, 2);
      ADC_InjectedChannelConfig(ADC2, ADC_Channel_1, 1, ADC_SampleTime_7Cycles5);
      ADC_InjectedChannelConfig(ADC2, ADC_Channel_1, 2, ADC_SampleTime_7Cycles5);
    
      ADC_InjectedDiscModeCmd(ADC2, ENABLE);
      ADC_ExternalTrigInjectedConvCmd(ADC2, ENABLE);
      ADC_ExternalTrigInjectedConvConfig(ADC2, ADC_ExternalTrigInjecConv_T3_CC4);
    
      ADC_Cmd(ADC2, ENABLE);
    
      // Starte Kalibierung
      ADC_ResetCalibration(ADC2);
      while(ADC_GetResetCalibrationStatus(ADC2));
      ADC_StartCalibration(ADC2);
      while(ADC_GetCalibrationStatus(ADC2));
    }
    
    void ADC_2_Interrupt_ini()
    {
      NVIC_InitTypeDef  NVIC_InitStructure;
      NVIC_InitStructure.NVIC_IRQChannel = ADC1_2_IRQn;
      NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
      NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
      NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
      NVIC_Init(&NVIC_InitStructure);
      ADC_ITConfig(ADC2, ADC_IT_JEOC, ENABLE);
    }
    ISR Timer 3:
    Code:
    void TIM3_IRQHandler(void)
    {
      if(TIM_GetITStatus(TIM3, TIM_IT_CC4))
      {
        GPIOB->ODR ^= GPIO_Pin_6;
        TIM_ClearITPendingBit(TIM3, TIM_IT_CC4);
        TIM3->CCR4 =  pwm_aktuell.adc_comp.adc_triggerung_2;
      }
    }
    ISR ADC:
    Code:
    void ADC1_2_IRQHandler(void)
    {
      ADC_ClearITPendingBit(ADC2, ADC_IT_JEOC);
    
    
      ADC_Strom_1 = ADC_GetInjectedConversionValue(ADC2, ADC_InjectedChannel_1);
      ADC_Strom_2 = ADC_GetInjectedConversionValue(ADC2, ADC_InjectedChannel_2);
    
      TIM3->CCR4 =  pwm_aktuell.adc_comp.adc_triggerung_1;
      flags |= adc_messung_fertig;
    
      strom_auswerten();
    }
    Funktion zum Auswerten der Strommesswerte:
    Code:
    void strom_auswerten(void)
    {
      ACS_ref = gleitender_mittelwert(ACS_ref, ADCBuffer[0], 3);
    
      ADC_Strom_1 -= ACS_ref + ACS_0_Strom_offset;
        ADC_Strom_2 -= ACS_ref + ACS_0_Strom_offset;
    
        ADC_Strom_1 = ADC_Strom_1 << 3;
        ADC_Strom_2 = ADC_Strom_2 << 3;
    
      if(flags & erste_adc_messung )
              {
                flags &= ~erste_adc_messung;
                flags &= ~adc_messung_fertig;
              }
              else
              {
                flags &= ~adc_messung_fertig;
    
                if(counter==2)
                {
                if(array_counter==2000)
                {
                  asm("nop");
                }
                else
                {
                    counter = 0;
                  I_U_array[array_counter] = I_U_flt;//I_U_flt;
                  I_V_array[array_counter] = I_V_flt;//I_V_flt;
                  I_W_array[array_counter] = I_W_flt;
    
                  //I_U_array[array_counter] = ADC_Strom_1;//I_U_flt;
                  //I_V_array[array_counter] = - ADC_Strom_2;//I_V_flt;
                  //I_W_array[array_counter] = -ADC_Strom_1 + ADC_Strom_2;
    
                  teta_array[array_counter++] = teta;
                }
                }
                else
                {
                  counter += 1;
                }
    
                 switch (sektor)
                    {
                    case 1:  // 0- 60°
                    {
                      I_W_raw = - ADC_Strom_2;
                      I_V_raw = ADC_Strom_1;
                      I_U_raw = - I_V_raw - I_W_raw;
                      break;
                    }
                    case 2:  // 60-120°
                    {
                      I_U_raw = -ADC_Strom_2;
                      I_W_raw = ADC_Strom_1;
                      I_V_raw = (- I_W_raw - I_U_raw);
                      break;
                    }
                    case 3:  // 120-180°
                    {
                        I_U_raw = - ADC_Strom_2;
                        I_W_raw = ADC_Strom_1;
                      I_V_raw = - I_U_raw - I_W_raw;
                      break;
                    }
                    case 4:  //180-240°
                    {
                      I_U_raw = ADC_Strom_1;
                      I_W_raw = - ADC_Strom_2;
                      I_V_raw = - I_W_raw - I_U_raw;
                      break;
                    }
                    case 5:  //240-300°
                    {
                      I_U_raw = ADC_Strom_1; 
                      I_W_raw = - ADC_Strom_2;
                      I_V_raw = - I_W_raw - I_U_raw;
                      break;
                    }
                    case 6:  //300-360°
                    {
                      I_V_raw = ADC_Strom_1;
                      I_W_raw = - ADC_Strom_2;
                      I_U_raw = - I_V_raw - I_W_raw;
                      break;
                    }
                    default: break;
                  }
              }
    
         I_U_flt = gleitender_mittelwert(I_U_flt, I_U_raw, filter_gewichtung_strom);
      I_V_flt = gleitender_mittelwert(I_V_flt, I_V_raw, filter_gewichtung_strom);
      I_W_flt = gleitender_mittelwert(I_W_flt, I_W_raw, filter_gewichtung_strom);
      return;
    }
    Ich habe nun echt schon viel versucht und gemessen. Wenn ich zum Beispiel nur einen Wechselstrom durch den Hall-Sensor schicken, wird dieser auch korrekt gemessen:
    Klicke auf die Grafik für eine größere Ansicht

Name:	16.01.jpg
Hits:	6
Größe:	29,0 KB
ID:	29649
    Nur die Messung in Kombination mit dem SVPWM Modul funktioniert überhaupt nicht Mir fällt nichts mehr ein was ich noch versuchen kann. Deshalb wäre ich über eure Hilfe sehr dankbar.

    Viele Grüße und vielen Dank im Voraus Michael

  2. #2
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    06.08.2008
    Ort
    Graz
    Beiträge
    521
    2 Ideen:
    1) Sind die Timer immer synchron, oder driften sie auseinander?
    2) Der Hallsensor wird durch den Motor und dessen Magnetfeld gestört.

    LG!
    alles über meinen Rasenmäherroboter (wer Tippfehler findet darf sie gedanklich ausbessern, nur für besonders kreative Fehler behalte ich mir ein Copyright vor.)

  3. #3
    Neuer Benutzer Öfters hier
    Registriert seit
    11.04.2011
    Beiträge
    6
    Hallo,

    zuerst danke für die Antwort.
    Zu 1. ich habe das getestet in dem ich mit beiden Timern ein PWM erzeugt habe und die Ausgänge mit dem Oszi gemessen habe. Diese sind synchron und driften auch nicht.
    Zu 2. Der Sensor ist recht weit Entfernt vom Motor, deshalb kann ich mir das nicht so recht vorstellen.

    Viele Grüße Michael

  4. #4
    shedepe
    Gast
    Hey mit welcher Frequenz läuft deine PWM ?
    http://www.allegromicro.com/~/media/...Datasheet.ashx

    Nachdem Datenblatt ist die maximale ungedämpfte Frequenz die damit gemessen werden kann 120 kHz. Je nach Kondensator zwischen dem Filter Pin und GND kann das auch erheblich weniger sein.

    Ich würde vorschlagen du misst testweise mal mit einem herkömmlichen Messshunt. Damit kannst du deinen Quellcode überprüfen und Fehler die durch den Stromsensor entstehen ausschließen.

  5. #5
    Neuer Benutzer Öfters hier
    Registriert seit
    11.04.2011
    Beiträge
    6
    Hallo,

    mein PWM läuft mit 17,6kHz. Ich habe auch schon mit einem Shunt getestet. Dies kann ich aber mit dem aktuellen Code nochmals versuchen.

    Viele Grüße Michael

    EDIT: Ich habe nun nochmal mit dem ACS709 und einem Shunt gemessen. Sieht leider beides gleich schlecht aus :/
    Klicke auf die Grafik für eine größere Ansicht

Name:	ACS_709.jpg
Hits:	12
Größe:	36,1 KB
ID:	29655Klicke auf die Grafik für eine größere Ansicht

Name:	Shunt.jpg
Hits:	10
Größe:	34,0 KB
ID:	29656

    Viele Grüße Michael
    Geändert von EOS400DMAN (24.01.2015 um 15:23 Uhr)

  6. #6
    shedepe
    Gast
    Könntest du zu dem Diagramm bitte die Beschriftung noch mal extra dazu schreiben. Die ist leider so klein geworden, dass man sie kaum lesen kann.
    Zu den Messwerten. Wenn ich grade keinen Denkfehler drin habe würde ich die Messwerte so als realistisch einschätzen. Es wird nacheinander ein Stromfluss durch die einzelnen Motorspulen festgestellt der auch umgetastet worden ist.

  7. #7
    Erfahrener Benutzer Lebende Robotik Legende Avatar von PICture
    Registriert seit
    10.10.2005
    Ort
    Freyung bei Passau in Bayern
    Alter
    72
    Beiträge
    11.077
    Hallo!

    Sorry, dass ich kurz unterbreche, aber ich bewundere oft zahlreiche Disskusionen über undefinierte Sachen. Beispielweise hier: um was für ein Strom (Spitze, Mittel, RMS, usw.) es genau geht ?
    MfG (Mit feinem Grübeln) Wir unterstützen dich bei deinen Projekten, aber wir entwickeln sie nicht für dich. (radbruch) "Irgendwas" geht "irgendwie" immer...(Rabenauge) Machs - und berichte.(oberallgeier) Man weißt wie, aber nie warum. Gut zu wissen, was man nicht weiß. Zuerst messen, danach fragen. Was heute geht, wurde gestern gebastelt. http://www.youtube.com/watch?v=qOAnVO3y2u8 Danke!

  8. #8
    Neuer Benutzer Öfters hier
    Registriert seit
    11.04.2011
    Beiträge
    6
    Guten Tag,

    es geht um die Momentanwerte des Stroms.
    Mittlerweile bin ich ganz zufrieden mit den Ergebnissen. Baue ich die Sternschaltung des Motors aus drei Leistungswiderständen nach, dann bekomme ich folgenden Verlauf:
    Klicke auf die Grafik für eine größere Ansicht

Name:	Strommessung_an_drei_Leistungswiderständen.jpg
Hits:	9
Größe:	39,9 KB
ID:	29659
    Das sieht schon sehr nach Sinus Verläufen aus.

    Messe ich am Motor bekomme ich folgende Ergebnisse:
    Klicke auf die Grafik für eine größere Ansicht

Name:	Strommessung_am_Motor.jpg
Hits:	10
Größe:	40,2 KB
ID:	29660
    Diese sehen zwar nicht so nach Sinus aus, dies liegt aber vermutlich daran, dass der Motor zwangskommutiert läuft. Da sehen die Ströme meines Wissens nach nicht so schön aus. Das ist ja auch der Grund warum man den Aufwand einer FOC betreibt.

    Viele Grüße Michael

Ähnliche Themen

  1. Tiefpass bei Strommessung
    Von .:markus:. im Forum Elektronik
    Antworten: 5
    Letzter Beitrag: 15.12.2010, 17:34
  2. Antworten: 13
    Letzter Beitrag: 27.08.2010, 21:59
  3. Problem bei Strommessung/Temperaturdrift
    Von ssalbach im Forum Sensoren / Sensorik
    Antworten: 12
    Letzter Beitrag: 11.06.2009, 14:20
  4. Antworten: 26
    Letzter Beitrag: 30.07.2008, 17:45
  5. Antworten: 13
    Letzter Beitrag: 27.05.2008, 11:41

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •  

Solar Speicher und Akkus Tests