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

Programmera UBW32 - Stegmotor
Lite stegmotorteori
En stegmotor består enkelt uttryckt av en snurrande magnet. Runt om sitter elektromagneter vilka magnetiseras enligt ett mönster som driver runt axeln med magneten.

Det finns olika komplicerade stegmotorer med olika många elektromagneter. Ju fler lindningar desto fler faser och desto jämnare och kontrollerad rörelse. Ju färre lindningar desto färre faser och "hackigare" rörelse - men billigare stegmotor.

Skillnaden mellan unipolär och bipolär är att när man driver unipolära behöver man aldrig vända på polariteten för en elektromagnet och drivelektroniken blir därför enklare. Med bipolär blir stegmotorn enklare men drivelektroniken mer komplicerad.

vanligaste stegmotorerna

Nedan följer ett exempel med en unipolär stegmotor och därefter ett exempel med en 2-fas bipolär som jag driver med en L293.

Stegsekvensen
Arbetet att driva runt stegmotorn handlar alltså om att aktivera elektromagneterna i stegmotorn enligt ett mönster som driver runt axeln. Jag har en stegmotor här som enligt dokumenteringen drivs runt med hjälp av nedanstående sekvens. Det är en 5-trådars unipolär stegmotor.

stegsekvensen
Om man tänker sig att man tar de 4 första bitarna på port A - A0, A1, A2 och A3 så skall man alltså upprepande mata ut mönstret 0001, 0010, 0100, 1000, ... med lämplig hastighet. Dvs siffrorna 1, 2, 4, 8. Skickar man bara ut detta borde resten handla om att koppla rätt, så borde det fungera.

Driva stegmotorn
Utgångarna på UBW32 är rätt så kraftiga för att vara utgångar på en microprocessor - men de räcker inte för att driva lindningarna på stegmotorn. Eller snarare; jag har hört talas om folk som direkt drivit mycket små stegmotorer med andra PIC-kretsar så det är tydligen inte omöjligt. Men jag tänker inte testa. Principen är som nedan. Någon typ av slutsteg.
driva stegmotorn
Jag råkar nu äga ett kretskort med en stegmotor på (se bild längst ner) där det redan finns drivelektronik (nedan) i form av vanliga BC547-transistorer. Så det blir den jag använder.

stegmotor drivsteg bc547
När man tittar på ovanstående schema och även det med ULN2803, så kan man få intrycket att signalen inverteras och att man därför måste skicka in en inverterad signal för att det skall bli "rätt". Att signalen inverteras stämmer, men det blir rätt ändå. Lindningarnas gemensamma anslutning på stegmotorn går till 5 eller 12 volt, så det är just när lindningens andra anslutning "nollas" som den blir aktiv (flyter en ström). Så en hög signal in betyder fortfarande att elektromageten i stegmotorn är aktiv och vice versa.

Programmet - med riktning och fartreglering
Navet i programmet som får stegmotorn att snurra runt ser ut ungefär som exemplet med rinnande ljus på UBW32. Man kan utgå ifrån det programmet och tom låta de rinnande ljusen vara kvar. De fyra faserna skall sedan skriva siffrorna 1, 2, 4, 8 på Port A. Till dessa pinnar på port A (A0, A1, A2, A3) kopplar man sedan stegmotorn.

void tickStepper(void)
{
	cnt++;
	cnt%=4;
	switch(cnt)
	{
		case 0:mLED_4_Off(); mLED_1_On(); PORTA=1; break;
		case 1:mLED_1_Off(); mLED_2_On(); PORTA=2; break;
		case 2:mLED_2_Off(); mLED_3_On(); PORTA=4; break;
		case 3:mLED_3_Off(); mLED_4_On(); PORTA=8; break;
	}
}
Nu vill jag iofs också kunna ändra riktningen på stegmotorn samt dessutom kunna ändra farten.

Alltså. Medurs: 1,2,4,8,1,2,4,8,1,2,4,8,... Moturs: 8,4,2,1,8,4,2,1,8,4,2,1,...
void tickStepper(int dir)
{
	cnt+=dir;
	cnt=(dir>0)?(cnt%4):((cnt<0)?3:cnt);
	LATE|=0x0F; //släcker alla lysdioder E0,E1,E2,E3
	switch(cnt)
	{
		case 0: mLED_1_On(); PORTA=1; break;
		case 1: mLED_2_On(); PORTA=2; break;
		case 2: mLED_3_On(); PORTA=4; break;
		case 3: mLED_4_On(); PORTA=8; break;
	}
}
Sådär ja. Ett anrop tickStepper(1) kommer nu få stegmotorn (och lysdioderna) att stega fram och ett anrop tickStepper(-1) kommer få stegmotorn (och lysdioderna) att gå bakåt. Fartregleringen löser jag genom att förändra hur ofta tickStepper(riktning) anropas.

Analog indata
spänningsdelareFör att fysiskt kunna reglera hastigheten på stegmotorn behövs en potentiometer som jag kopplar till någon av Pic32'ans ADC. Jag tänker mig att om potentiometern står i mitten, då står motorn stilla. Beroende åt vilket håll och hur mycket man vrider så snurrar motorn åt det hållet med vald hastighet. Ja, som en balanskontroll på förstärkaren ungefär.

Klart som korvspad. Återstår bara att koppla ihop det elektriskt och knacka lite kod. Spänningsdelaren i form av en potentiometer kopplas till U=3.3 volt. Det är max spänning in på analoga ingångarna. Regleringen blir då mellan o volt och 3.3 volt.

Konfigurera ADC
Jag använder metoden som manualen kallar manuell sampling. Man startar en sampling genom att sätta SAMP-biten i AD1CON1. Efter att ha väntat lite startar man konverteringen genom att nolla samma bit varpå man sedan får ut värdet ur DAC'n när DONE -biten i samma register säger att konverteringen är färdig. Då kan man läsa data't där 0-3.3 volt på ingången blir ett värde mellan 0-1024 (dvs 10 bitars upplösning). Därefter kan man starta en ny sampling genom att sätta SAMP-biten i AD1CON1. Så håller det på. Det finns en hel del fullt fungerande exempel i manualen för ADC (kapitel 17). Den händige finner säkert något som inspirerar att grotta djupare i detta.

/********************************************************************
* Stegmotor 1 på UBW32               -    http://www.robotsteel.com *
* Justera hastighet och riktning med potentiometer                  *
********************************************************************/

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

#define SYS_FREQ 			(80000000L)
#define TOGGLES_PER_SEC		1000
#define CORE_TICK_RATE	    (SYS_FREQ/2/TOGGLES_PER_SEC)

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

volatile static uint32 NextStepCounter=100;
uint32 WaitNextStep = 100;
int cnt = 0;
int ADCValue;

int main(void)
{   
	SYSTEMConfigPerformance(80000000L);
 	mJTAGPortEnable(0);
	mInitAllLEDs();
	TRISA = 0; // port A som ut-port (stegmotor A0,A1,A2,A3)

	AD1PCFG = 0xFFFB;  
	AD1CON1 = 0x0000;
	AD1CHS  = 0x00020000; // Connect RB2/AN2 as CH0 input
	AD1CSSL = 0;      // no input scan
	AD1CON3 = 0x0002; // ADC clk period=6 PB clk periods=75 ns
	AD1CON2 = 0;      // no input scan

	// don't turn on the ADC until all other configuration
	AD1CON1SET = 0x8000;  // turn ADC ON
	AD1CON1SET = 0x0002;// set SAMP bit. starts sampling

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

	return 0;
}

void tickStepper(int dir)
{
	cnt+=dir;
	cnt=(dir>0)?(cnt%4):((cnt<0)?3:cnt);
	LATE|=0x0F; //släcker alla lysdioder E0,E1,E2,E3
	switch(cnt)
	{
		case 0: mLED_1_On(); PORTA=1; break;
		case 1: mLED_2_On(); PORTA=2; break;
		case 2: mLED_3_On(); PORTA=4; break;
		case 3: mLED_4_On(); PORTA=8; break;
	}
}

void __ISR(_CORE_TIMER_VECTOR, ipl2) CoreTimerHandler(void)
{
	mCTClearIntFlag();
	NextStepCounter--;
	if(NextStepCounter<1)
	{
		AD1CON1CLR = 0x0002;  // conv. starts when SAMP bit clr
		while (!(AD1CON1 & 0x0001));  // check the DONE bit
		ADCValue = ADC1BUF0;  //when done value in ADC1BUF0
		WaitNextStep=513-ABS(ADCValue-512);
		AD1CON1SET = 0x0002;  // start new sampling
		tickStepper((ADCValue>512)?1:-1);
		NextStepCounter=WaitNextStep;
	}
	UpdateCoreTimer(CORE_TICK_RATE);
}
En viktig kommentar till koden här ovan. Efter att man startat samplingen genom att sätta bit 1 (SAMP) i AD1CON1 måste man vänta tills samplingen blivit klar innan konverteringen kan startas genom att clear:a bit 1 i samma register. Man måste vänta 200 ns eller mer.
	AD1CON1SET = 0x0002;  // Startar sampling

	...Vänta 200 ns...

	AD1CON1CLR = 0x0002;  // Startar konvertering
Jag har löst detta genom att helt enkelt starta samplingen det sista jag gör i interruptfunktionen. Nästa gång interruptet genereras är samplingen klar och det första jag gör är att konvertera och läsa denna sampling. Det verkar fungera utmärkt.

inkopplad stegmotor

Bipolär stegmotor
stegmotorBipolär bygger på att man ibland vänder på polerna för elektromagneterna så att de ömsom repellerar (stöter ifrån) och attraherar (dra till sig). Eftersom varje magnet därför gör dubbelt jobb får man egentligen 4 faser trots att det bara är två magneter och formellt 2 faser.

Drivsteget för en bipolär stegmotor blir lite mer komplicerat. För en unipolär som den ovan räcker det med en transistor på varje igång men för en bipolär måste man vi ha en elektronik som fixar att vända polariteten. Det går att använda L293'ans H-brygga till detta. L293'an använde jag på ett annat ställe för pulsbreddsmodulering så jag råkar ha en del sådana i mitt komponentskåp så därför är det intressant testa om det fungerar för att styra denna stegmotor.

2 fas bipolär stegmotor
Man kan tänka sig ovanstående koppling. Kan det fungera?

stegmotor sekvens För att driva runt en 2-fas bipolär med två elektromagneter kopplar vi in strömmen enligt tabellen till vänster. Plus (+) och minus (-) för att visa polariteten. Eftersom 1B alltid är inversen på 1A och 2B alltid inversen på 2A kan man förenkla styrsignalerna precis som jag gjort i ovanstående ritning (notera de 2 logiska inverterarna).

Sekvensen in på [AB] ovan som driver runt stegmotorn medurs blir då [AB]= [11], [01], [00], [10] och sekvensen som driver moturs borde då bli [AB]= [10], [00], [01], [11].

Uppkoppling
Kommer inom kort!

Kod
Kommer inom kort!





Robot och elektronik -sidan byter namn till electro.st

Senast läst 21:36:51 28/5 2017 Texten uppdaterad 17/9 2014
footer sign