Autonomous RC Racing

Here is a project I have been working with on and off for about a year – Alvin the autonomous RC car. The robot is built to comply with the rules of two Swedish robot competitions, Robot SM and Stockholm Robot Championship, where the objective is to race three other robots around a track without any form of remote control. Rules vary somewhat, but each heat typically lasts until one robot reaches 7 laps, or for max 3 minutes. The robots are then given points according to the number of laps they have completed at this point. The participants can also signal the organizer to flip or turn the robot if it crashes or gets stuck, at the cost of one point.

Here is Alvin in action, racing some other robots from the Norbot team at a recent meetup:

Parts

  • Wltoys A222 RC car
  • Texass Instruments TM4C123G Launchpad microcontroller evaluation board
  • My own custom Launchpad protoboard booster-pack
  • Sharp GP2Y0A21YK0F analog distance sensors from Ebay
  • “10A Brushed ESC Motor Speed Controller for RC Car without Brake” off Ebay
  • A3144 hall effect switch, also from Ebay
  • Rare earth magnets (D4x2mm), Ebay as well

Operation

Since Alvin is built on a RC car, both the steering servo and throttle ESC have a maximum update rate of once per 20 ms, or 50 times per second. For the first implementation, therefore, the processor simply runs the algorithms for calculating new steering and throttle values once every 20 ms and then just waits in between.

For the steering, Alvin uses two Sharp distance sensors to measure the distance to the side walls and a third to detect obstacles in front. To stay in the middle of the track, it simply compares the distance to the walls and compensates the steering to make them equal. This rather simple approach could probably be improved a lot to gain more speed.

Since the track contains a hump, the power to the motor can not be hardcoded – it needs to increase in the uphill. To control the speed, a hall effect sensor is reading two magnets mounted on the drive shaft. The algorithm converting pulses from this sensor to a throttle setting has so far proven to be the hardest to implement, mainly because there are only two pulses per revolution of the drive shaft. This means there are normally just 0-2 new pulses recorded  every time the algorithm runs, making it hard to determine the actual speed. To work around this, the delta in revolutions is instead calculated 10 iterations back in time. The resulting speed value is then used as input to a PI controller which calculates the throttle.

Results

Alvin raced for the first time last year at Stockholm Robot Championship and I was very happy to finish 6th without ever tuning it on a full size track before! I have since worked on the throttle algorithm to make it as responsive as in the video above, so I think it could do even better today.

Future improvements

  • Extend front bumper to go around the wheels to avoid getting stuck against the wall.
  • Add a speed sensor with more pulses per revolution to allow better throttle control.
  • Add more distance sensors to enable a more advanced steering algorithm.
  • Add roll cage or body to protect the electronics and improve the looks.

Conclusion

Autonomous robot racing is a fun and fairly affordable way to put your combined engineering skills to the test, including both mechanical, electrical and software components. Being new in my city, it has also been a way to meet like-minded people and a reason to go down to the local hackerspace.

Finally, here is a playlist from Stockholm Robot Championship 2016 if you want to see some more action!

Periodic Python Scheduler

Since the days were getting  shorter, I thought it was about time to set up the wakeup light in my new apartment. This got me looking at the code and wondering about improvements. One of the first things I wanted to fix was the ugly way it handled fading the light by setting a new intensity once per second:

while(1):
    client.loop()

    # Do next fade step if needed
    if (rgb.fadeState != 0):
        if (time() - lastTime >= rgb.fadeTickSeconds):
            lastTime = time()
            rgb.fade()

At work, I have spent some time programming with TI-RTOS lately. Like any RTOS, it has the ability to set up periodic tasks. TI-RTOS calls them clock objects and the idea is pretty simple; you assign the clock object a period and a callback function and just start it. Clearly there should be a way to do this with a single line of Python? Not that I could find! There is one way to do it, apparently, in something called Celery. Some comments on Stack Overflow convinced me that it is way overkill for what I am trying to achieve though, requiring setting up ques and handlers and stuff.

Python does provide the event scheduler sched. It can schedule a single event to happen some time in the future. Another Stack Overflow comment pointed out you can use sched to recursively schedule new events and thus get a periodic scheduler:

def periodic(scheduler, interval, action, actionargs=()):
  scheduler.enter(interval, 1, periodic,
                  (scheduler, interval, action, actionargs))
  action(*actionargs)

I went with this idea and added a few features to it. First, I wanted the task to be able to stop itself if it wants to. Second, it should also be possible to stop the task from the callers context. Third, I wanted to be able to schedule only a specific number of periodic events. Fourth, I wanted it to be non-blocking. Sched can run in a non-blocking mode since Python 3.3, but I was using 2.7 so I resorted to wrapping the scheduler in its own thread instead. Here it is (only 44 lines!):
import sched
import time
import thread
import threading

# Periodic task scheduler
class periodicTask:

	def __init__(self, periodSec, task, taskArguments = (), repetitions = 0):
		self.thread = threading.Thread(target = self.threadEntryPoint, 
			args = (periodSec, task, taskArguments, repetitions))
		self.thread.start()

	def threadEntryPoint(self, periodSec, task, taskArguments, repetitions):
		self.repetitions = repetitions
		self.scheduler = sched.scheduler(time.time, time.sleep)
		self.periodic(self.scheduler, periodSec, task, taskArguments)
		self.scheduler.run()

	def periodic(self, scheduler, delaySec, task, taskArguments):
	  	# Schedule another recursive event
	 	self.nextEvent = self.scheduler.enter(delaySec, 
	 		1,
	 		self.periodic,
	 		(self.scheduler, delaySec, task, taskArguments))

	 	# Do task and get return status
		stopTask = task(*taskArguments)

		# Stop task if it returned true
	 	if (stopTask == True):
			self.stop

		self.repetitions = self.repetitions - 1

		# Stop if we ran through all repetitions
		# If repetitions was initialized to 0, run forever 
		# (or at least until integer underflow?)
		if (self.repetitions == 0):
			self.stop()

	def stop(self):
		self.scheduler.cancel(self.nextEvent)
		thread.exit()

Now I can define a task and then run it three times with a 1 second interval in a single line of code(!):
def testTask():
	print "Test"
	return False

myTask = periodicTask(periodSec = 1, task = testTask, repetitions = 3)

I thought this might come in handy for other projects, so I put it in a separate GitHub project. The next step will be to include the scheduler in the wakeup light code. It will probably require adding some more functionality, like separating creating the task and starting it so that it can be re-used, we’ll see.

Learning Proper Coding: For-loop optimization

“Whats wrong with this code?”

for ( int i=0; i<10; i++ )
{
    //do stuff
}

As it turns out, I will soon start working as an embedded software developer.  It seems then, now would be a good time to start learning how to program properly. I’ll be putting up some tidbits here for my own reference and hopefully others to learn something as well!

Several months ago, during a (the) job interview, I was told about reverse loops. Supposedly, computer scientists will scoff at this, but since I never learnt about it until interviewing for my first job after five years of electrical engineering studies and even more time doing hobby-level coding, I thought I might just put one more mention of it on the internetz.

So, if you find yourself writing code for a system with heavy resource constraints, it would seem the school-book example of a for-loop above has some room for improvement. Assuming the loop body does not depend on i  incrementing upwards, it would be better to do this:

for ( int i=10; i>=0; i-- )
{
    //do stuff
}

Why? It all depends on what instructions the code compiles down to. When evaluating whether or not to stay in the loop, the processor has to first put the number 10 into a register, then do a comparison to see which one is larger. The comparison in its turn is usually implemented by subtracting and checking the sign of the result. Since most architectures have a designated “zero register”, the reverse loop may skip loading the value to a register and go straight to comparing. Before we move any further however, there is one more thing we can do:

for ( int i=10; i--; )
{
    //do stuff
}

Since the loop criterion has to be fulfilled in order to stay in the loop, we are looking at the zero register (Z) to find out when to break it. This means we might as well use the decrementing itself as the loop criterion, saving us the whole compare instruction altogether!

Sweet! I was nearly going to leave it at that but of course you should not have to take my word for it. Lets try to verify this on an MSP430 using msp430-gcc. First, lets implement the three loop variants:

#include <msp430.h>

//Normal loop
void loop1()
{
        for ( int i=0; i<10; i++ )
        {
                __delay_cycles( 1 );
        }
}

//Slightly optimized
void loop2()
{
        for ( int i=10; i>=0; i-- )
        {
                __delay_cycles( 1 );
        }
}

//Super optimized!
void loop3()
{
        for ( int i=10; i--; )
        {
                __delay_cycles( 1 );
        }
}

void main()
{
        loop1();
        loop2();
        loop3();
}

 

Next, I compiled the code and fed it through msp430-objdump to get the assembly output. Note that compiler optimizations were set to the lowest level with the -O0  flag and variable declaration inside the for-statement was made possible with -std=c99  (let’s not get into that today):

$ msp430-gcc -O0 -std=c99 main.c -mmcu=msp430g2553 -o main.elf
$ msp430-objdump -DS main.elf > main.lst

Now this is where it gets interesting. Watch what happens in the relevant parts of the output:
0000c058 <loop1>:
    c058:       04 12           push    r4
    c05a:       04 41           mov     r1,     r4
    c05c:       24 53           incd    r4
    c05e:       21 83           decd    r1
    c060:       84 43 fc ff     mov     #0,     -4(r4)  ;r3 As==00, 0xfffc(r4)
    c064:       03 3c           jmp     $+8             ;abs 0xc06c
    c066:       03 43           nop
    c068:       94 53 fc ff     inc     -4(r4)          ;0xfffc(r4)
    c06c:       b4 90 0a 00     cmp     #10,    -4(r4)  ;#0x000a, 0xfffc(r4)
    c070:       fc ff
    c072:       f9 3b           jl      $-12            ;abs 0xc066
    c074:       21 53           incd    r1
    c076:       34 41           pop     r4
    c078:       30 41           ret

0000c07a <loop2>:
    c07a:       04 12           push    r4
    c07c:       04 41           mov     r1,     r4
    c07e:       24 53           incd    r4
    c080:       21 83           decd    r1
    c082:       b4 40 0a 00     mov     #10,    -4(r4)  ;#0x000a, 0xfffc(r4)
    c086:       fc ff
    c088:       03 3c           jmp     $+8             ;abs 0xc090
    c08a:       03 43           nop
    c08c:       b4 53 fc ff     add     #-1,    -4(r4)  ;r3 As==11, 0xfffc(r4)
    c090:       84 93 fc ff     tst     -4(r4)          ;0xfffc(r4)
    c094:       fa 37           jge     $-10            ;abs 0xc08a
    c096:       21 53           incd    r1
    c098:       34 41           pop     r4
    c09a:       30 41           ret

0000c09c <loop3>:
    c09c:       04 12           push    r4
    c09e:       04 41           mov     r1,     r4
    c0a0:       24 53           incd    r4
    c0a2:       21 83           decd    r1
    c0a4:       b4 40 0a 00     mov     #10,    -4(r4)  ;#0x000a, 0xfffc(r4)
    c0a8:       fc ff
    c0aa:       01 3c           jmp     $+4             ;abs 0xc0ae
    c0ac:       03 43           nop
    c0ae:       5f 43           mov.b   #1,     r15     ;r3 As==01
    c0b0:       84 93 fc ff     tst     -4(r4)          ;0xfffc(r4)
    c0b4:       01 20           jnz     $+4             ;abs 0xc0b8
    c0b6:       4f 43           clr.b   r15
    c0b8:       b4 53 fc ff     add     #-1,    -4(r4)  ;r3 As==11, 0xfffc(r4)
    c0bc:       4f 93           tst.b   r15
    c0be:       f6 23           jnz     $-18            ;abs 0xc0ac
    c0c0:       21 53           incd    r1
    c0c2:       34 41           pop     r4
    c0c4:       30 41           ret

See that? The most optimised loop, loop3(), has the most instructions! How can that be!? Lets try again with -Os for size optimization:
0000c054 <loop1>:
    c054:       3f 40 0a 00     mov     #10,    r15     ;#0x000a
    c058:       03 43           nop
    c05a:       3f 53           add     #-1,    r15     ;r3 As==11
    c05c:       fd 23           jnz     $-4             ;abs 0xc058
    c05e:       30 41           ret

0000c060 <loop2>:
    c060:       3f 40 0b 00     mov     #11,    r15     ;#0x000b
    c064:       03 43           nop
    c066:       3f 53           add     #-1,    r15     ;r3 As==11
    c068:       fd 23           jnz     $-4             ;abs 0xc064
    c06a:       30 41           ret

0000c06c <loop3>:
    c06c:       3f 40 0b 00     mov     #11,    r15     ;#0x000b
    c070:       01 3c           jmp     $+4             ;abs 0xc074
    c072:       03 43           nop
    c074:       3f 53           add     #-1,    r15     ;r3 As==11
    c076:       fd 23           jnz     $-4             ;abs 0xc072
    c078:       30 41           ret

Sorry, loop3() is still loosing!!

So what have we learned from this exercise? Unless I’m missing something, this seems to be a typical case of what shall henceforth be known as “the-people-who-wrote-the-compiler-were-smarter-than-you”. Even on the lowest optimisation setting, the compiler is already reversing the loop, as it detects the loop variable is not used. Supposedly, a more complex loop body would change this. Still, I’m not sure why they don’t all compile down to the same code then. Maybe one day I will have become smart enough to fix it!

While the theory behind the reverse loop as I presented it above seems sound, it appears the compiler optimizes the “normal” code best anyway, at least on this one platform with this one compiler. Until I actually have a resource constrained system to shoehorn into a low-power device, I’ll just keep writing my loops as I used to. This also has another major advantage: readability. A traditional loop statement is simply easier to understand. Also, I don’t feel like explaining that my loops are not broken, but brilliant. Especially when they are, in fact, not even brilliant.

 

 

 

 

Wake-up Light Part 3: Hardware

This is the third part (part 1, part 2) of my write-up on building a Raspberry Pi-based wake-up light. At this point, the Pi was capable of switching 433 MHz remote controlled outlets and can be scheduled to do this at certain times.

I had a few ideas on how to roll my own light for the project. In the end, I went for 10 m of RGB-LED strip on Ebay and four pieces of quarter round rod from the department store. I think these pictures speak for themselves:

2014-02-03 21.00.58 2014-02-08 21.51.332014-02-03 20.14.41 2014-02-08 19.51.592014-02-03 20.14.32 2014-02-03 20.36.15 2014-02-03 20.14.562014-02-08 22.42.13

To get off the ground quickly, I whipped out an Arduino and soldered three MOSFET transistors to a protoboard. My initial idea was to hook it up to the Pi via I2C, but as I had the 433 MHz receiver left over from the kit I bought, and also already being familiar with the library as I used it to find what codes to use for my outlets, I figured I might as well make it wireless. This also has the added bonus of making it possible to control the light directly with my existing remote.

2014-02-08 21.46.16

To test things out, I hastily modified the rc-switch library example. The code is available over on my Github account, although for the time being it really is not very pretty and does contain bugs! I made the A-channel on my remote turn the light on and off and used B to set the brightness. I also wrote a small state machine to dim the light from blue through red and orange and up to white at full brightness over the course of 15 minutes. This would be my wake-up sequence. The “E” channel does not have any buttons on my remote (only A-D). It is, however, no problem to send on and off commands on it using the commands on the Raspberry Pi. Making the Arduino listen to channel “E” of my outlet remote system meant I did not have to waste one of the four channels on the actual remote. To the Pi it was all the same, I just changed what channel it should power on in the crontab. Here is an attempt to catch a sped-up version of the light sequence on camera. You get the idea.

2014-03-04 21.02.06

Sweet, at this point the project was really starting to get somewhere! The wake-up sequence is good enough for now, and the extra feature of being able to toggle the light on and off along with my other lamps in the evening is very convenient. With the right setup, ssh, nano and cron can be quite ok for setting the alarm. However, I was hoping to do something more portable and… modern, like an MQTT message server perhaps?

Next time: Software!

Wake-up Light Part 2: Scheduling

Last time, we had managed to get a command for controlling the lights up and running on the Raspberry Pi. The obvious choice for scheduling such a command in Linux is Cron. To automatically turn on the lights using Cron, we need to edit the root-user’s crontab:

$ sudo crontab -e

This will launch a text editor inside the terminal. Lets scroll down to the end using the arrow keys and add the following lines:
45 6 * * 1,2,3,4,5 send 11111 3 1
50 6 * * 1,2,3,4,5 send 11111 4 1

The values, in turn, represent minute, hour, day of month, month and day of week. That is, the first command fires 06:45 every month, Monday through Friday. The send command is the same as before; turn group 11111, light 3 and 4, on (1). There is lots you can do with Cron and it has been around forever. If you have not used it before there are lots of extensive guides out there to get you started so I will not bother. This setup took me through most of the winter. The Pi turned on the lights just before my alarm went off at 07:00 and the results were imminent – waking up was a lot easier and “softer” as the light eased the body into the idea of waking up before it was blasted by the sound of an alarm. It was good, but not what I had planned for. This was only fading in two discrete steps, and even though I could just have added a few more outlets like this, I really wanted a singe, more powerful, custom light. Plus, the relays in the outlets make a loud and annoying clicking sound when they turn on. On the software side things were working fine, but logging onto the Pi and setting the alarm in the terminal was not really optimal. Next time: Building some hardware!

Wake-up Light Part 1: Flipping switches

2014-02-08 22.45.39 2014-02-08 22.45.20 2014-02-08 22.45.31

I’ve had the idea to build my own wake-up light for quite some time. This winter i finally got around to it. This is the first part of my write-up of the project.

In simple terms, the point of a wake-up light is to gently wake you up by slowly turning up the light before the alarm goes off in the morning. There are several commercial products available that do this already, all of which I think are either ugly, too small or simply not practical enough for my use case. Some of the things I wanted that are commonly not available in these products are:

  • Big, powerful light. Usually, products are night stand-size alarm clocks with a few measly watts of power.
  • RGB controllable light. My living room is also my bedroom. If I’m going to make the wake-up light big and powerful, I also want to be able to set it to a cosy warm evening-setting. Plus, this would make it able to do a more sunrise-like color fade in the morning.
  • Powerful scheduling options. I’m a student and don’t get up at regular hours every day. I want the wake-up time to be easily settable, preferably synchronized to my alarm or even my schedule.

Flipping some switches

I figured I could use my Raspberry Pi as the central point for the system. It’s hanging off the back off my TV, running Raspbmc and is on 24/7 anyway, so a simple start would be to add a cronjob to simply turn on some lights in the morning. I already had 433 MHz light switches connected to three ambient lights in my room, so I started out with by hooking up a transmitter to the Pi.

2013-10-12 22.51.17

Having someone in Shenzen send me a transmitter/receiver pair for 433 MHz on Ebay set me back about the same amount sending a normal letter home to my mother would. Mine was titled “RF Wireless Transmitter & Receiver Kit Module 433Mhz for Arduino/ARM/MCU WL”.

rf

Obviously, someone on the Internetz already wrote the code to talk to my outlets using Arduino. And someone else also ported it to Raspberry Pi. Sweet! The project I’m using is called rcswitch-pi. According to the readme, it depends on the (seemingly useful) wiringpi project, so first we need to get that (assuming you have git installed):

$ cd
$ git clone git://git.drogon.net/wiringPi
$ cd wiringPi
$ ./build

Wiringpi is used for the gpio calls inside rc-switch and is sort of replacing the Arduino’s digitalWrite() and the like. Now let’s install rcswitch-pi:

$ cd
$ git clone https://github.com/r10r/rcswitch-pi.git
$ cd rcswitch-pi
$ make

The program is hardcoded to have the transmitter connected to Wiringpi pin 0, which corresponds to pin 11 of the GPIO header on the Pi. If you want, you can change this by editing send.cpp and running the make command again.

Hooking up the receiver to my Arduino and using the original rc-switch library, I figured out what group and channel corresponded to the buttons on my remote.

2013-10-12 22.50.14

I could now control the lights from the Pi using these commands:

$ cd ~/rcswitch-pi
$ sudo ./send 11111 3 1 #Press "C on"
$ sudo ./send 11111 3 0 #Press "C off"
$ sudo ./send 11111 4 1 #Press "D on"
$ sudo ./send 11111 4 0 #Press "D off"

A small explaination to all these numbers: my outlets have “group switches” allowing different remotes to control  different sets of outlets. I have mine set to 11111. The buttons on the remote are labeled A-D. I have some lights hooked up to C (3) and D (4). All this I learned by loading the example sketch from the rc-switch library onto my Arduino and observing the serial output as I pushed some buttons on the remote.

Once I knew the send command was working, I linked it into /usr/bin/. This makes it possible to run the command without having to cd into the folder every time, which will be convenient for scheduling later.

$ sudo ln -s ~/rcswitch-pi/send /usr/bin/send
$ cd
$ sudo send 11111 3 1
$ sudo send 11111 3 0

Next time: Scheduling!

Hi, I’m Albert

This is where I post projects from the past and present in the hope that someone else (my future self included) will find them useful. Also, one day I really would like to be featured on Hackaday and become internet-famous. You can contact me on social media, or at “mail” on this domain.


Kör Control Center till TI eZ430-Chronos på Mac

5226.8103.chron.png-550x0

I slutet av november kunde man köpa en eZ430-Chronos-klocka från Texas Instruments webshop för halva priset. Här kommer en snabb förklaring hur man får igång deras Control Center som används för att ta emot data och programmera om klockan, på macen.

Vi börjar med en kort bakgrund: jag läste ett inlägg av en annan kille som hade köpt en likadan klocka. I förbifarten uppfattade jag att Control Center-programmet var skrivet i Tcl/Tk. Jag hade ingen aning om vad det var då, men lite efterforskningar visade att det borde gå bra att köra samma kod även under OS X.

  1. Det första som behövs är en mac-version av Tcl/Tk. Det finns att ladda ner här: http://www.activestate.com/activetcl/downloads. Efter installationen finns ett nytt program som heter Wish.app i /Program/Verktygsprogram/
  2. Nu behöver vi själva tcl-skriptet. Det finns i två versioner, en för Windows och en för Linux. Dumt nog har TI låst in dem i arkiv som bara går att packa upp på respektive operativsystem. Jag fick ut filerna genom att installera arkivet på en virtuell linuxmaskin som jag körde i Virtualbox. Koden flyter även runt på internet, till exempel här: https://github.com/bhutley/Chronos-Control-Center. Ladda ner filerna eller extrahera dem ur arkivet.
  3. Till sist behöver vi ändra raden som anger vilken komport som är USB-dongeln. Öppna eZ430-Chronos CC 1_2.tcl och ändra rad 66 från:
    set com "/dev/cu.usbmodem001"

    till:

    set com [glob /dev/cu.usbmodem*]

    De tre siffrorna på slutet i den ursprungliga raden varierar från dator till dator (och ibland från gång till gång). Skriptet ska nu välja första bästa komport med lämpligt namn så att namnet inte behöver hårdkodas.

  4. För att använda programmet, koppla in USB-dongeln, öppna en terminal, navigera till mappen med tcl-skripten och skriv:
    tclsh eZ430-Chronos CC 1_2.tcl
  5. Klart! Programfönstret dyker upp och det ska gå att se accelerometerdata precis som i Windows. Notera att avläsning av knapparna inte fungerar i OS X – om man trycker på någon av knapparna på klockan så genereras ett fel och ingenting händer. Återkommer eventuellt med lösning på detta!

Skärmavbild 2013-12-28 kl. 20.20.00

Uppdaterad: Programmera MSP430 Lauchpad med en Mac

Launchpad

Här om dagen insåg jag att jag inte programmerat MSP430 Launchpad sedan jag installerade om datorn till Mountain Lion (OS X 10.8) tidigare i år. 2011 skrev jag ihop en guide om vad man behöver installera för att komma igång och eftersom det har ändrats lite tänkte jag att det vore på sin plats med en uppdatering.

  1. Ladda ner och installera MSP430LPCDC, det är en drivrutin som gör att datorn kan hitta launchpaden. Installationen kräver av någon anledning  att du startar om datorn efteråt.
  2. Installera Macports (eller Fink om du föredrar det). Det är en pakethanterare som gör det enkelt att installera program via terminalen.
  3. Installera själva kompilatorn MSPGCC och debuggern MSPDebug som används för att föra över koden till mikrokontrollern genom att köra följande kommando i terminalen. (Om använder Fink, byt ut “port” mot “fink”).

    sudo port install msp430-gcc msp430-libc mspdebug

  4. Klart!

I den gamla guiden finns ytterligare några steg (4-8) som visar hur man kan ladda ner ett färdigt program och testa så att allt fungerar. Lycka till!