Start

Förstasidan
Statistik

Social robot

Robotens syn
Modell/simulator
Levande modell


Arduino

Starta upp Arduino
DCcduino UNO
Pro Mini

Raspberry pi

Om Raspberry

Pic32

Om Pic32
Konstruktionen
Praktisk kom-igång
Starta upp UBW32
Installera MPLAB
Rinnande ljus
Stegmotor
Display
RS232 Pic32 - terminal
Luffarschack

Servo

Överblick
Isärmonterat servo
Styrning av servo
Mini Maestro
Bygga ett servo

Elektronik

Open Collector
Kontaktstuds
Drivsteg på utgångarna
Halleffektsensor/switch
MLX90316 (halleffekt)
Pulsbreddsmodulering

Open CV

Om OpenCV

Matematik

Linjär algebra
Olinjär länkmekanism

PWM - Pulsbreddsmodulation
Lite allmänt kring PWM
Det finns flera poänger med att använda PWM, pulsbreddsmodulering. Dels är det hårdvarumässigt ett enkelt och energieffektivt koncept för att styra hastigheten på motorer (och andra apparater). Dels får man även, för ett servo, åtråvärda egenskaper, som t.ex. hög styrka och hög hastighet med en ganska enkel styrning.

Alternativet till pulsbreddsmodulering är att låta en dator styra en spänningsnivå med en regulator. Det innebär att man, såtillvida regulatorn inte är extremt avancerad, eldar upp energi i en kylfläns för att få rätt utspänning. Det innebär också en del elektronik för att vända polariteten vid behov, dvs man måste använda t.ex. en H-brygga enbart för detta. Allting kokar ner till att pulsbreddsmodulering klarar sig med mindre elektronik.

pulsbreddsmodulering
PWM är - tvärtemot vad det låter som - rätt så enkelt ur ett tekniskt perspektiv. Vad det handlar om är att slå på och slå av spänningen för motorn, med en lagom hög frekvens. Dvs, vi startar och stoppar motorn fast vi gör det så snabbt att det inte märks. Ju högre hastighet desto längre låter man spänningen vara påslagen. Vid full hastighet är spänningen påslagen konstant. Dvs, vi varierar alltså pulsen längd (bredd) beroende på hur snabbt vi vill att motorna ska gå; därav namnet plusbredds-modulering.

pmw exempel
Vid en lägre hastighet kan det se ut som ovan.

pmw exempel Vid en högre hastighet kan vi låta pulserna vara lite längre.

Vad är en lämplig frekvens? En lämplig frekvens kanske kan vara t.ex. 100-1000 Hz.

En pulsbreddsmodulering inom det hörbara frekvensområdet (20-20000 Hz) kommer generera en bakrundston på denna frekvens. Det får man stå ut med om man väljer denna metod. (När motorn inte ska röra sig kan man ju låta den vara avslagen)

L293 datablad
Drivkrets L293D
För att skapa pulserna med rätt längd och frekvens använder jag en microprocessor.

Det behövs en lämplig drivkrets, effektsteg, mellan microprocessorn och DC-motorerna. Jag kommer här att använda L293D. Det är en krets från SGS-Thomson Microelectronics som orkar driva ungefär 600 mA per kanal med en peak på det dubbla. Den består av två stycken H -bryggor för att enkelt vända polariteten. Den har vissa finesser som en enable-funktion som gör att man kan stänga av krets & motor, överhettningsskydd och inbyggda skyddsdioder. Dvs, L293D med "D" på slutet har inbyggda skyddsdioder. Andra varianter av L293 förutsätter att du monterar dit externa skyddsdioder, som då måste hantera åtminståne motorns ström (dioden kortsluter motorn under av-cykeln). Kretsen kan användas både för att driva stegmotorer och vanliga DC-motorer.

Kraftigare drivkrets än L293 ska inte behövas för dessa motorer som sitter i robotens huvud och nacke. Observera att det går att använda lite alla möjliga olika kretsar för detta ändamål t.ex. ULN2003A som är mycket billigare men klarar bara halva strömmen. Det går ju också att bygga denna drivare med transistorer, motstånd och dioder. Men jag tycker L293D verkar praktiskt och ändamålsenlig.

Vss är kretsens drivspänning
Vs är motorns drivspänning

Drivspänningen kan variera från några volt upp till 37 volt. I min applikation kommer motorns drivspänning vara ca 6 volt. Kretsens drivspänning kommer antagligen vara 5 volt. En L293 kan driva 2 dc-motorer.

Expriment
För att labba lite praktiskt med pulsbreddsmodulering investerade jag en hundring i kretskortet till höger. Det har förutom en DC-motor kopplad till ovan beskrivna L293 dessutom 2 stycken optiska sensorer med vars hjälp man kan mäta rotationshastigheten med t.ex. en frekvensräknare, vilket jag upptäckte - av en tillfällighet, att min multimeter råkade innehålla.

pwm Sedan behövs ett datorprogram som genererar lämpliga pulser och styrsignaler.

Ett testprogram för pulsbreddsmodulering kan se ut ungefär som mitt program för styra stegmotorer, när det gäller upplägg och fartreglering. Fast istället för att snickra ihop pulser till stegmotorn så snickrar man ihop en puls med lite högre frekvens lämplig till DC-motorn. Dessutom behövs lite styrsignaler för att kontrollera riktningen.

pwm

Ovanstående signaler styr medurs och moturs rotation samt stop och nedan är ritningen för kretskortet.

pwm

Programkod
Koden nedan genererar PWM som utdata på A0 och A1. Motorns hastighet och riktning styrs med potentiometern precis som förklarat i exemplet med stegmotorstyrning. Frekvensen kan ändras i koden genom att ändra FREK. Lysdioderna rinner åt ena eller andra hållet beroende på vilket håll motorn snurrar. Bra som feedback att programmet fungerar.
/********************************************************************
PWM1  på UBW32                   -          http://www.robotsteel.com
********************************************************************/

#include "plib.h"
#include "HardwareProfile.h"

#define FREK            10
#define SYS_FREQ 			(80000000L)
#define TOGGLES_PER_SEC		5120
#define CORE_TICK_RATE	    (SYS_FREQ/2/(TOGGLES_PER_SEC*FREK/100))

#define ABS(a) (((a) < 0) ? -(a) : (a))

int cnt = 0, ledCnt=50;
int puls=0;
int ADCValue;

int main(void)
{   
	SYSTEMConfigPerformance(80000000L);
 	mJTAGPortEnable(0);
	mInitAllLEDs();
	TRISA = 0;

	AD1PCFG = 0xFFFB;    
	AD1CON1 = 0x0000;     
	AD1CHS  = 0x00020000; 
	AD1CSSL = 0;        
	AD1CON3 = 0x0002;   
	AD1CON2 = 0;       
	AD1CON1SET = 0x8000;  
	AD1CON1SET = 0x0002;  

	OpenCoreTimer(CORE_TICK_RATE);
	mConfigIntCoreTimer((CT_INT_ON|CT_INT_PRIOR_2|CT_INT_SUB_PRIOR_0));
	INTEnableSystemMultiVectoredInt();

	return 0;
}

void tickLED(int dir)
{
	cnt+=dir;
	cnt=(dir>0)?(cnt%4):((cnt<0)?3:cnt);
	LATE|=0x0F;
	switch(cnt)
	{
		case 0: mLED_1_On(); break; 
		case 1: mLED_2_On(); break; 
		case 2: mLED_3_On(); break; 
		case 3: mLED_4_On(); break; 
	}
}

void __ISR(_CORE_TIMER_VECTOR, ipl2) CoreTimerHandler(void)
{
	mCTClearIntFlag();
	if(puls>0)
	{
		PORTA=((ADCValue>512)?2:1);
	}
	else
	{
		PORTA=0;
	}
	puls--;
	if(ledCnt<0)
	{
		AD1CON1CLR = 0x0002;         // konvertera
		while (!(AD1CON1 & 0x0001)); // vänta tills DONE
		ADCValue = ADC1BUF0;         // läs värdet
		puls=ABS(ADCValue-512)/(FREK/10);
		AD1CON1SET = 0x0002;         // ny sampling
		tickLED((ADCValue>512)?1:-1);
		ledCnt=50;
	}
	ledCnt--;
	UpdateCoreTimer(CORE_TICK_RATE);
}


expriment med pwm

Mätningar
Jag har mätt varvtalet med en frekvensräknare och sedan kopplat in logikanalysatorn. Nedan är mätningar för 10 Hz och 100 Hz. Det är lätt ändra frekvensen i koden genom att ändra FREK längst upp i koden.

10 Hz
Med en frekvens på 10 Hz såg pulsbredden ut som nedan vid varvtalen 20, 100 och 178 varv per sekund. Någonstans kring 180 varv per sekund verkar vara motorns maxprestanda. Vid låga varvtal (under 20 varv per sekund) gick motorn mycket ojämt.
pwm
pwm
pwm


100 Hz
Med en frekvens på 100 Hz såg pulsbredden ut som nedan vid varvtalen 0.36, 100 och 180 varv per sekund. Med högre frekvens gick motorn genast mycket jämnare, speciellt på lägre varvtal. Högre varvtal höll en mer exakt hastighet än vid 10 Hz.
pwm
pwm
pwm


Många sätt skapa pulståg
I Pic32'an finns 5 oscillatorer färdiga att använda för PWM. Nedan följer ett exempel hur det kan se ut. Nu kommer jag behöva styra 11 motorer så det räcker inte på långa vägar med dessa inbyggda. Men ska man styra någon enstaka motor och vill spara några rader kod kan man göra som nedan.
/********************************************************************
PWM2  på UBW32                   -          http://www.robotsteel.com
********************************************************************/

#include "plib.h"
#include "HardwareProfile.h"

#define FREK            100
#define SYS_FREQ 			(80000000L)
#define ABS(a) (((a) < 0) ? -(a) : (a))

int i,ADCValue,pWidth;

int main(void)
{   
	SYSTEMConfigPerformance(80000000L);
 	mJTAGPortEnable(0);
	mInitAllLEDs();
	TRISA = 0;

	AD1PCFG = 0xFFFB;     
	AD1CON1 = 0x0000;    
	AD1CHS  = 0x00020000; 
	AD1CSSL = 0;          
	AD1CON3 = 0x0002;     
	AD1CON2 = 0;         
	AD1CON1SET = 0x8000;  
	AD1CON1SET = 0x0002; 

	OpenOC1( OC_ON | OC_TIMER2_SRC | OC_PWM_FAULT_PIN_DISABLE, 0, 0);
	OpenTimer2( T2_ON | T2_PS_1_1 | T2_SOURCE_INT, 0xFFFF);

	while(1)
	{
		AD1CON1SET = 0x0002;         // ny sampling
		for(i=0;i<=200;i++) ;	     // vänta > 200nS
		AD1CON1CLR = 0x0002;         // konvertera
		while (!(AD1CON1 & 0x0001)); // vänta tills DONE
		ADCValue = ADC1BUF0;         // läs värdet
		PORTA=((ADCValue>512)?2:1);  // sätt riktning A0,A1
		pWidth=ABS(ADCValue-512);    // räkna ut pulslängd
		SetDCOC1PWM(PR2*pWidth/513); // sätt PWM utdata
	}
	return 0;
}




Robot och elektronik -sidan byter namn till electro.st

Senast läst 23:32:29 27/5 2017 Texten uppdaterad 17/9 2014
footer sign