EnglishSvenska

HIL testing in Arduino

I am trying out Hardware-in-the loop simulation on a new Arduino project for a client. Test driven development is unfortunately not very big in the Arduino community (yet) so I decided to implement something by myself. The setup is simple:

  1. One Arduino is running the application software.
  2. Another Arduino connects to inputs and outputs on the first Arduino. This Arduino will include all the test code.

2015-05-14 16.08.09

A test case could for example be, when the user presses a button a LED should light up. The second Arduino will output a signal to the button input on the first Arduino, and then check if the LED pin output is high. Example code is shown below.

void loop() {
  // Simulate that user presses button
  digitalWrite(BUTTON_PIN, 1);

  // check that the LED lights up
 assert(LED_PIN, 1);

 delay(500)

  // check that some actuator starts running
  assert(ACTUATOR_PIN, 1);

  // Simulate that user releases button
 digitalWrite(BUTTON_PIN, 0);

  // Led and actuator should turn off
 assert(LED_PIN, 1);
 assert(ACTUATOR_PIN, 1);

  // stop execution
 while (1) {}
}

bool assert(uint8_t pin, bool expectedState) {
 bool state = digitalRead(pin);
  if (state != expectedState) {
   Serial.print("## FAILURE: pin ");
   Serial.print(pin);
    Serial.print(" == ");
   Serial.print(state);
    Serial.print(" != ");
   Serial.print(expectedState);
    Serial.println();
   return false;
 }
 else {
    Serial.print("## OK: pin ");
    Serial.print(pin);
    Serial.print(" == ");
   Serial.print(state);
    Serial.println();
   return true;
  }

}

Why the hassle?

It might seem unnecessary, (and it is for simple problems), but it does increase code quality and decreases the risk of bugs being introduced when writing new features to the code.

Making it better

I would like to write my test code in Python on a laptop and control an Arduino (via Firmata for example). Then I would have proper tools for testing and generating test reports. For now the Arduino solution is sufficient though.

Taggad med:

Självbalanserande ARM (uppdaterad och bättre)

Simplicity is the ultimate sophistication. I den förra versionen av den självbalanserande roboten använde jag totalt 3 mikroprocessorer men har nu designat och programmerat om den på en större ARM mikroprocessor. Med mer kräm i processorn ges en mängd fördelar:

  • Färre komponenter
  • Enklare kretsschema
  • Robust mekanisk design på grund av färre kablar
  • Ingen kommunikation mellan processorer är nödvändig vilket ger en mycket enklare kod
  • Ett litet RTOS sköter trådhanteringen (vilket inte gick på AVR)



Så bygger man en likadan (eller bättre)

Komponenter

Mekanisk design

Läs de äldsta inläggen på projektsidan för att se foton från hur man bygger ihop den. Det enda som behöver tillverkas är de tre plattorna för vilka det finns CAD och ritningar.

Kretsschema

Många har frågat om kretsschema så jag gjorde ett i Altium Designer.

Mjukvara

All kod ligger på Github.

Reglerteknik

Kort använder jag kaskadåterkopplade PID-regulatorer. Den yttre loopen reglerar hastigheten på roboten vilket mäts på tachometrar på motorerna. Den intre loopen reglerar robotens vinkel vilket mäts med en IMU. Den yttre loopen har långsam dynamik och den intre loopen är mycket snabbare. Rent teoretiskt ska det gå att göra en självbalanserande robot med endast den inre loopen men man får väldigt lätt ett beteende av att roboten långsamt rör sig framåt eller bakåt över golvet eftersom återkopplingen från hjulens hastighet saknas.

För att få ytterliggare bättre prestanda används gain scheduling på den inre loopen vilket innebär att regulatorparamterarna ändras beroende på robotens vinkel. En liten vinkel nära jämviksläget innebär konservativa regulatorparametrar där endast små justeringar görs för att hålla roboten stående. Är vinkeln stor är roboten nära att ramla och de aggressiva paramterinställningarna aktiveras med syfte att göra allt för att återfå stabilitet.

Information flow

Information flow

Cascade PID implementation theory

Cascade PID implementation theory

Ändra parametrar

Troligtvis kommer alla parametrar inte fungera utan att de justeras något. I koden finns en struct som kan sättas i setConfiguration(). Smartare är dock är att använda en seriell terminal för att ändra parametrar samtidigt som koden körs. På så sätt behöver man inte programmera om processorn varje gång man vill ändra en parameter. Öppna Serial Monitor i Arduino. Testa att skriva "print configuration" till Arduinon. Om allt fungerar som det ska kommer den svara med att skriva ut alla parametrar. Alla variabler i structen Configuration kan sättas från terminalen. Skriv bara "set" följt av variabelnamn och värde. Exempelvis "set speedPIDKp 1.5". För att aktivera debug skriver du "set debugLevel 2". Om du vill debugga IMU skriver du därefter "set angleRawDebug 1". För att stänga av en debug-variabel skiver du exempelvis "set angleRawDebug 0".

Att hitta rätt regulatorparametrar

Använd en realtidsplotter när du ställer in dina regulatorparametrar så går det enklare.

Taggad med: , , , ,

Ska jag ta med paraplyet?

Att bo i Göteborg innebär att man många morgnar ställer sig själv frågan "behövs ett paraply idag?". För att överlämna fler små beslut till datorer programmerade jag en mikroprocessor som svarar med att tända en lysdiod om paraply rekommenderas.

Spark Core as Umbrella reminder

Idéen är väldigt enkel. Mikroprocessorn läser väderprognosen från yr.no för de kommande 10 timmarna (vilket är ungefär den tiden jag väntas vara hemifrån). Om någon av dessa timmar innehåller regn (högre än några få mm) så tänder den lysdioden. Släckt lysdiod innebär givetvis inget regn.

Hur det fungerar

Hårdvara

  • Spark Core
  • Breadboard
  • Lysdiod
  • Resistor
  • Usb-kabel för strömförsörjning

Väderprognos med php och yr.no

Jag kör ett php-skript som hämtar kommande prognos från yr.no. Den är publicerad på https://sebastiannilsson.com/will-it-rain/ och är relativt enkel att använda.

  1. Leta reda på den stad som du vill ha prognos för och kopiera urlen. Exempelvis för Göteborg är den http://www.yr.no/sted/Sverige/V%C3%A4stra_G%C3%B6taland/G%C3%B6teborg/ eller för Kolbäck http://www.yr.no/sted/Sverige/V%C3%A4stmanland/Kolb%C3%A4ck/
  2. Gå till https://sebastiannilsson.com/will-it-rain/index.php?debug=1&threshold=0.2&yr_url=<URL HÄR>

Exempel: Prognosen för Göteborg med ett gränsvärde för regn vid 0.5 mm ser ut såhär:
https://sebastiannilsson.com/will-it-rain/index.php?debug=1&threshold=0.5&yr_url=http://www.yr.no/sted/Sverige/V%C3%A4stra_G%C3%B6taland/G%C3%B6teborg/

Kod för skriptet som visar hur man använder yr.no som ett väder-API.

Kod på mikroprocessorn

Spark Core är en mikroprocessor som ansluter till Wifi. Man laddar över kod till den över deras molntjänst.

  1. Skaffa en Spark Core eller liknande och koppla upp den mot wifi.
  2. Kopiera in min kod för Spark Core. Det enda som behövs ändras är variabeln för url.
  3. Ladda upp
Taggad med:

Arduino-bibliotek för motordrivare L29x

l298n arduino library
Jag håller på att bygga om min självbalanserande robot och behövde då ett smidigt sätt att styra motordrivaren L298n. Eftersom jag styr roboten med PID-regulatorer ville jag att mitt bibliotek ska ta flyttal som både är negativa och positiva. Resultatet blev ett motordrivar-bibliotek som är väldigt enkelt att använda:

/* This example shows how to set motor speed in percentage where a negative
   value will run the motor backwards.
   This is very usuful in control applications. For example the output
   from a PID controller is most often a float and can be integrated with
   this library easily. 
*/
#include <L29x.h>
L29x motorLeft(9, 22, 23); // enable (PWM), motor pin 1, motor pin 2
L29x motorRight(8, 24, 29); // enable (PWM), motor pin 1, motor pin 2

void setup() {
  // put your setup code here, to run once:

}

void loop() {
  motorLeft.setSpeedPercentage(-12.34);
  motorRight.setSpeedPercentage(-10);      
  delay(3000);
  motorLeft.setSpeedPercentage(100);
  motorRight.setSpeedPercentage(90);      
  delay(3000);
}
Taggad med:

Ersättare för EEPROM på Arduino Due

När jag fick min Arduino Due upptäckte jag att den inte har EEPROM vilket kan användas för att spara icke-flyktig data. Vanligtvis på en mikroprocessor så arbetar man med RAM-minnet vilket fungerar bra så länge man inte vill spara data mellan gångerna som processorn startar. Om man vill spara en variabel som ska vara kvar även när processorn förlorar ström behöver man en annan lösning där den vanligaste är att spara ner till EEPROM. På Arduino Due finns tyvärr inte detta minne men den har däremot ett riktigt stort flash-minne som kan konfigureras till att fungera på ett liknande sätt. Jag skrev därför ett bibliotek som gör just detta. Det är tänkt att kunna användas som en rak ersättare till EEPROM. DueFlashStorage är publicerad på Github.
Exempel:

// write the value 123 to address 0
dueFlashStorage.write(0,123);

// read byte at address 0
byte b = dueFlashStorage.read(0);

Eller hela exempelkoden:

/* This example will write 3 bytes to 3 different addresses and print them to the serial monitor.
Try resetting the Arduino Due or unplug the power to it. The values will stay stored. */

#include DueFlashStorage dueFlashStorage;

void setup() {
Serial.begin(115200);
byte b1 = 3;
uint8_t b2 = 1;
dueFlashStorage.write(0,b1);
dueFlashStorage.write(1,b2);
//dueFlashStorage.write(2,b2);
}

void loop() {
  /* read from flash at address 0 and 1 and print them */
  Serial.print("0:");
  Serial.print(dueFlashStorage.read(0));
  Serial.print(" 1:");
  Serial.print(dueFlashStorage.read(1));  

  /* read from address 2, increment it, print and then write incremented value back to flash storage */
  uint8_t i = dueFlashStorage.read(2)+1;
  Serial.print(" 2:");
  Serial.print(dueFlashStorage.read(2)); 
  dueFlashStorage.write(2,i);

  Serial.println();
  delay(1000);
}

Serial monitor:
arduino due flash example serial monitor 1

Men säg att man vill spara undan en hel konfiguration och inte bara några få bytes. Jag skrev biblioteket för att kunna hantera detta också:

// say you want to store a struct with parameters:
struct Configuration {
  uint8_t a;
  uint8_t b;
  int32_t bigInteger;
  char* message;
  char c;
};
Configuration configuration;

/* then write it to flash like this: */
byte b2[sizeof(Configuration)]; // create byte array to store the struct
memcpy(b2, &configuration, sizeof(Configuration)); // copy the struct to the byte array
dueFlashStorage.write(4, b2, sizeof(Configuration)); // write byte array to flash at address 4

/* and read from flash like this: */
byte* b = dueFlashStorage.readAddress(4); // byte array which is read from flash at adress 4
Configuration configurationFromFlash; // create a temporary struct
memcpy(&configurationFromFlash, b, sizeof(Configuration)); // copy byte array to temporary struct

Se hela koden på Github för ett fungerande exempel.

Taggad med:

Tillbaka till robotbyggande

Efter ett års uppehåll (främst på grund av den tid som jag spenderat med Formula Student) är jag tillbaka till robotbyggande. Projektet nu är att bygga om den självbalanserande roboten och göra ett antal förbättringar.

  • Atmel ARM32 Arduino Due istället för 3 små micro controllers. Bättre design.
  • LCD display
  • Förbättrad IMU
  • Mer robusta kontaktdon och snyggare kabeldragning
  • Bluetooth
  • Trådlös programmering
  • Realtidsoperativsystem (RTOS) för att schemalägga trådar på processorn. Bättre än nuvarande lösning där trådarna delades upp på flera processorer.

 

Taggad med: ,

Den självbalanserande roboten fungerar ganska bra




I videon kan man se att roboten håller sig på någorlunda samma ställe på golvet och klarar av att ta emot lättare stötar. För att uppnå detta kaskadkopplade jag två PID-regulatorer och la till lågpassfilter på både hjulens rotationshastighet och robotens lutning.

Mikroprocessorer

Eftersom en Arduino inte har väldigt mycket processorkraft valde jag att använda totalt 3 mikroprocessorer:

  1. En standalone Arduino Uno tar pulser från varvtalsmätaren på varje hjul och omvandlar detta till en hastighet. Hastigheten skickas till huvuddatorn.
  2. En till standalone Arduino Uno för att visa och justera parametrar. Driver också displayen. Parametrarna skickas till huvuddatorn.
  3. Arduino Leonardo är huvuddatorn. Den tar emot information från konsolen och motorhastighetsmätaren via I2C.

Reglerteknik

Två kaskadkopplade PID-regulatorer. Den första har hastighet som setpoint (alltid 0 i det här fallet) och lutning som output. Om roboten rullar framåt kommer regulatorn att få ett positivt är-värde och skicka ut en negativt utsignal. Detta innebär att roboten kommer att vilja luta bakåt för att bromsa upp hastigheten.

PID-regulatorn nummer 2 tar hand om robotens vinkel relativt golvet. Börvärdet är utsignal från den tidigare PID-regulatorn. Normalt kommer börvärdet att variera från -3 till 3. Noll motsvarar att roboten ska stå helt rakt upp. Utsignalen kopplas till motorstyrningen och varierar från -100 till 100. -100 motsvarar full spänning till motorerna i bakåtriktning.

För att få renare insignaler används FIR-filter på både vinkel och hjulens hastighet. Lågpassfilter gör att snabba förändringar (exempelvis sensorbrus) inte släpps igenom.

Till vinkeln relativt golvet används en IMU med accelerometer och gyro. Ett komplementärfilter kombinerar signalerna från dessa och ger en utsignal som går att använda.

Källkod

Jag hade som mål att all kod till detta projekt ska vara öppen och finnas att hämta på github. I readme finns länkar till bibliotek jag använt.

Förbättringar som skulle kunna göras

  • Bättre parametrar till FIR-filter. Mycket skulle nog kunna göras på hjulhastigheten för att inte få en lika hackig gång.
  • On-the-fly-programmering över luften med Xbee. Detta gör att man kan skicka helt ny kod till roboten utan usb-kabel. Gör programmeringen smidigare.
  • Radiostyrning vore kul.

Foton

Komponenter

Lägger också upp cad och ritningar.

Taggad med: , ,

Framsteg med roboten

Min självbalanserande robot visar nu tydliga tendenser till att faktiskt kunna stå. Se själv:




Problemet ser ut att vara att den inte bromsas upp helt när den väl börjat luta. Jag ska testa att återkoppla hjulens hastighet för att på så sätt få en svag översvängning vilket borde bromsa upp roboten.

Taggad med: ,

Tidigt test av självbalanserande robot


Jag kommer behöva justera PID för att få den självbalanserande. Det är för stora översvängningar och den beter sig väldigt oroligt. Uppdaterar när jag får bättre stabilitet.

Taggad med: , ,

Förbättrad hårdvara för att styra Roomba

Förbättrade nyligen hårdvaran för att fjärrstyra min dammsugare över internet. Tidigare använde jag ett helt Arduino Uno-kort vilket är overkill. Bättre och snyggare blir det att göra det direkt på en breadboard. Video när det fungerar (med lite annan hårdvara).

1. Koppla upp Atmega328 på breadboard för att få en Arduino Uno.

2. Dra kablar från varje knapp på fjärrkontrollen.

3. Sätt dit ett gäng transistorer. En för varje knapp du vill fjärrstyra. Kom ihåg att kombinera jord för breadboard och fjärrkontrollen. Jag satte också dit några lysdioder för att lättare se vilket kommando som skickas.

4. Tejpa kablarna så att de sitter på plats.

5. Tejpa fast breadboard på fjärrkontrollen. Detta gör den mer intakt och risken för att kablar lossnar minskar.

6. Koppla in till datorn och konfigurera eventghost till att styra roomba.

Taggad med: , ,