Pi Controlled NeoPixel Ring

OK, so not 100% accurate; a Pi controlled Adafruit Trinket controlled NeoPixel ring :-D

I got the idea from seeing Dave Whale’s serial based Arduino interface with the Pi. The Trinket doesn’t have serial so I had to use something else to talk to it.

Enter I²C;  on the Trinket side I’m using the TinyWireS library, on the Pi side I’m calling smBus.writeList() with a list of the bytes I wish to send.  You’ll notice in the video there’s an extra breakout in the circuit, this is a bi-directional level converter to allow the 5v Trinket to talk to the 3.3v Pi without releasing any magic smoke.

My aim is to implement the commands in the Neopixel library however at the moment it just calls setPixelColor with the 4 values (LED, Red, Green, Blue) provided by the Pi. I have a special case of LED==0xFF which lights all LEDs the specified colour (a concept I have pinched from David).  I have included the code below in it’s current (probably hacky) state.

One problem I did find is that the Pi randomly “loses” the I²C address of the Trinket and reports it as 0×03 for a second or two.  I’m not sure if the problem is the Pi or Trinket end but it seems to be an issue with Arduinos in general.  The basis of the work around I used in my Python code can be found here. If anyone knows the reason for this I would be most grateful; it’s a horrible hack

Arduino Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#include <TinyWireS.h>
#include <Adafruit_NeoPixel.h>
 
#define PIN 1
#define I2C_SLAVE_ADDRESS 0x04
 
// Parameter 1 = number of pixels in strip
// Parameter 2 = pin number (most are valid)
// Parameter 3 = pixel type flags, add together as needed:
//   NEO_KHZ800  800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
//   NEO_KHZ400  400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
//   NEO_GRB     Pixels are wired for GRB bitstream (most NeoPixel products)
//   NEO_RGB     Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)
Adafruit_NeoPixel strip = Adafruit_NeoPixel(16, PIN, NEO_GRB + NEO_KHZ800);
 
// The default buffer size, Can't recall the scope of defines right now
#ifndef TWI_RX_BUFFER_SIZE
#define TWI_RX_BUFFER_SIZE ( 16 )
#endif
 
int rxIndex = 0; 
 
volatile uint8_t i2c_regs[] =
{
    0x0, // RegisterID
    0x0, // Pin
    0x1, // R
    0x0, // G 
    0x0, // B
};
const byte reg_size = sizeof(i2c_regs);
 
//Handles receiving i2c data.
void receiveEvent(uint8_t howMany)
{
    if (TinyWireS.available()){  
      if (howMany < 1)
      {   // Sanity-check
          return;
      }
      if (howMany > TWI_RX_BUFFER_SIZE)
      {   // Also insane number
          return;
      }
 
      if (howMany == 1)
      {   // This write was only to set the buffer for next read
          return;
      }
      rxIndex = 0;
      while(howMany--)
      {   //Gets i2c data. 
          i2c_regs[rxIndex] = TinyWireS.receive();
          rxIndex++;
          if (rxIndex >= reg_size){
            if (i2c_regs[1] == 0xFF) {
              for (uint8_t p=0;p<strip.numPixels();p++){
                strip.setPixelColor(p,strip.Color(i2c_regs[2], i2c_regs[3], i2c_regs[4]));
              }
            }
            else {
              strip.setPixelColor(i2c_regs[1], strip.Color(i2c_regs[2], i2c_regs[3], i2c_regs[4]));    
            }
            strip.show();
            rxIndex = 0;
          } 
      }
 
    }
}
 
void setup() {
  TinyWireS.begin(I2C_SLAVE_ADDRESS);
  TinyWireS.onReceive(receiveEvent);
 
  strip.begin();
  strip.show(); // Initialize all pixels to 'off'
}
 
void loop() {
  TinyWireS_stop_check();
}

Pi Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
import time
import smbus
import os
import subprocess
 
i2cBus = 0
i2cAddr = 0x04
bus = smbus.SMBus(i2Bus)
debug = False
 
def writeList(reg, list):
    sent = False
    attempt = 0
    while sent==False:
        if debug:
            print "I2C: Writing list to register 0x%02X:" % reg
            print list
        try:
            bus.write_i2c_block_data(i2cAddr, reg, list)
            sent = True
        except IOError:
            #a 'hack' to catch the Arduino disappearing at random intervals
            #runs i2cdetect to refresh the i2c interface, output to /dev/null so we don't see the output
            FNULL = open(os.devnull, 'w')
            retcode = subprocess.call(['i2cdetect', '-y', str(i2cBus)], stdout=FNULL, stderr=subprocess.STDOUT)
            time.sleep(0.1)
            attempt += 1
            if attempt == 10:
                raise Exception('Unable to connect via I2C')
 
def setLED(led, red, green, blue):
    bytes= [led, red, green, blue]
    writeList(0x01, bytes)
 
setLED(0xFF, 0, 0, 0)
time.sleep(0.5)
setLED(0xFF, 32, 32, 32)
time.sleep(0.5)
setLED(0xFF, 0, 0, 0)
 
try:
    while True:
        for p in range(0, 16):
            setLED(p, 32, 0, 0)
            time.sleep(0.1)
        for p in range(0, 16):
            setLED(p, 0, 32, 0)
            time.sleep(0.1)
        for p in range(0, 16):
            setLED(p, 0, 0, 32)
            time.sleep(0.1)
        for p in range(0, 16):
            setLED(p, 0, 0, 0)
            time.sleep(0.1)
except KeyboardInterrupt:
        pass
 
setLED(0xFF, 0, 0, 0)
Posted in Arduino, NeoPixel, Projects, Raspberry Pi, Trinket | Leave a comment

Baby steps into Arduino

I have always programmed in VB (5, 6, .NET even VBA!), I’m also starting to look at C# again after a brief dalliance 5 years ago, and of course I have a passable knowledge of Python from working with the Raspberry Pi.

Ever since picking up and playing with the Pi I have become aware of these Arduino thingies. What really peaked my interest were the wearables like GEMMA and FLORA and the work of Charlotte Godley. They’re small, uncomplicated (in theory) devices to hack about on fairly easily.

Fast forward to the beginning of the month at the July CamJam and I was enticed by The PiHut and their wares, eventually crumbling and buying an Adafruit Trinket along with a NeoPixel ring (mmmm 16 LEDs!). After getting the IDE and drivers setup (more on that later) I loaded the obligatory blink sketch, which is the Arduino equivalent of ‘hello world’.

Flushed with success (or something like that) I moved on to the NeoPixel ring, wired it up and loaded the Larson Scanner sample. It needed a couple of tweaks; namely the data pin and the number of pixels, but it worked very well.

Ultimately it was time to write my first ever bit of Arduino (or C for that matter) code, cribbing from and building on the examples I had come across thus far.

The embedded video shows alternating green and purple filling up the ring, followed by yellow and red. I was working on this while helping run Pi sessions the tech zone at Gilwell 24 so the patterns arise from the Scout brand colours and the colours of my Scout scarf respectively. My code, for what it’s worth, is below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include &lt;Adafruit_NeoPixel.h&gt;
 
#define PIN 1
 
// Parameter 1 = number of pixels in strip
// Parameter 2 = pin number (most are valid)
// Parameter 3 = pixel type flags, add together as needed:
//   NEO_KHZ800  800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
//   NEO_KHZ400  400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
//   NEO_GRB     Pixels are wired for GRB bitstream (most NeoPixel products)
//   NEO_RGB     Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)
Adafruit_NeoPixel strip = Adafruit_NeoPixel(16, PIN, NEO_GRB + NEO_KHZ800);
 
void setup() {
  strip.begin();
  strip.show(); // Initialize all pixels to 'off'
}
 
void loop() {
  // Scout green and purple
  spin(strip.Color(132/4, 164/4, 11/4),strip.Color(77/4, 33/4, 119/4));
  // BWV Explorers red and yellow
  spin(strip.Color(255/4,0, 0), strip.Color(255/4,255/4, 0));
}
 
void spin(uint32_t c1, uint32_t c2){
  uint32_t c;
 
  // fill in reverse, so highest pixel number first
  for(int8_t p=strip.numPixels() - 1; p&gt;=0; p--){
    // set even pixels to colour 'c1', odd to 'c2'
    if (p%2==0){
      c = c1;  
    }
    else{
      c = c2;
    }
    cycle(0,p,c);
  }
  delay(100);
}
 
void cycle(int8_t f, int8_t l, uint32_t c){
 
  for(uint8_t i=f;i&lt;=l;i++)
  {
      // clear last pixel, set current pixel
      strip.setPixelColor(i-1, 0);
      strip.setPixelColor(i, c);
      strip.show();
      delay(100);
  }
}

Things I Learnt

The USB is temperamental – After much faffing and cursing I discovered in the Adafruit FAQ about reducing the chip_erase_delay. This made things much happier on my laptop!

Updating AVRDUDE helped too – After working well on another laptop my home one refused to work again. A few Google searches later and the AdaFruit forum came to the rescue with AVRDUDE v1.15.13

Commands in C must end with ‘;’ – Obvious I know but the number of times I forgot!

For loops work differently – I’m used to a For … Until construct (i.e. For n = 0 to 15 or for n in range(0 to 16)). It took me ages to work out why my for (n= 15; p=0; p--) didn’t work correctly!

Debugging is hard – The Trinket has no serial console so you can’t see what the code is doing. To resolve one issue I ended up downloading Tiny C Complier (TCC) and creating test code to see what I was doing wrong. For reference a uint_8 of 0 minus 1 is 255 not -1 because it’s unsigned – doh!

All in all it’s been a very fun learning curve and I’m looking forward to trying out a few more AdaFruit examples. Oh wait, what’s that in the next article?

Posted in Arduino, NeoPixel, Trinket | Leave a comment

Gilwell 24 Worksheets

So this weekend I’m running my first ever Pi session…. with 6 Pis and somewhere in the region of 3500 Explorer Scouts (14-18yo) for 24hrs! OK, so not all 3500 will visit but hopefully a few will!

2014-07-11 21.58.36

This is a lesson in how an offer of doing “a little something” with two Pis rapidly expands into a setup of 6 alongside some Arduino hacking, soldering, and amateur radio.

Below are the four worksheets I’ve cobbled together from various sources (all cited at the end of the documents). The format is not great, and I ended up printing two pages to a sheet (i.e. A5). I shall report back as to how it went.

Worksheet-Minecraft

Worksheet-PiCamera

Worksheet-SonicPi

Worksheet-PiBrella

Posted in Raspberry Pi, Scouts | Leave a comment

Steady Hand / Live Wire Game & PiBrella

I’m currently writing some Pi activity packs to use at a big Scout event on Saturday. One of them uses the excellent PiBrella to allow easily accessible physical computing via the GPIO interface.

After taking the reader/coder through the basics (lights, buzzer and the big red button!) I put together an extension task to make a Steady Hand/Live Wire game. Here’s the setup and introduction

Steady Hand setup

Steady Hand description

The code they are given is shown below

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
import pibrella
import time
 
state = 'end'
startTime = 0
endTime = 0
touch = 0
 
while True:
 
    #start position touched
    if pibrella.input.a.read():
        if state != 'reset':
            startTime = 0
            touch = 0
            state = 'reset'
            print 'Home and reset'
 
    #copper wire touched
    elif pibrella.input.b.read():
        if state == 'started':
            print 'Touch!'
            touch += 1
            state = 'touch'
            pibrella.light.on()
 
    #end position touched
    elif pibrella.input.c.read():
        if state == 'started':
            endTime = time.time()
            state = 'end'
            print 'You made it in', endTime - startTime, 'seconds!'
            print 'You had', touch, 'touches of the wire'
 
    elif not pibrella.input.a.read():
        # we've started
        if state == 'reset':
            print 'Timer started - Good luck!'
            state = 'started'
            touch = 0
            startTime = time.time()
 
        # we've stopped touching the wire
        elif state == 'touch':
            state = 'started'
            pibrella.light.off()
 
    time.sleep(0.1)

and that’s it. If you saw me at CamJam, the one I had there was a pimped up version. It had an LCD attached to show the fastest time and lives remaining. The buzzer on the Pibrella was also used, while the LEDs counted down your three lives. But those, dear reader, are YOUR extension tasks :-)

Posted in Add-On, Projects, Raspberry Pi | Leave a comment

7 Seg for Raspberry Pi

A while back I saw a project on IndieGoGo by a teenager, Tom Garry.  The project was called 7 Seg for Raspberry Pi.  Having never backed anything like this I thought I’d give it a try, at £10 it’s not a lot to loose.

Fast forward about 6 weeks (5th May for those of you who care) and a brown jiffy bag landed on my door mat.  I love brown jiffy bags as they usually contain goodies!  This one did not disappoint.

7Seg of Raspberry Pi delivery

 

So what did I get for my £10

  • A well produced purple PCB
  • Several bags of components – a nice touch was extra resistors of each value
  • Two 7seg displays; one red the other green.  This is so you can choose your colour
  • A warm fuzzy feeling :-)

When I eventually got round to soldering it up it was quite straight forward, it is also well documented on the 7seg.co.uk website.  Another week later I managed to find some time to test it!  Thankfully I managed to solder everything in the right places and it worked first time.

I ran a test python program using the Simple Counter example from the website.  I augmented it to count down as well as up by referencing pin 11 of the GPIO which controls the decrement function.  In the quick video below I repeated the for loop changing the upPin variable to downPin which references pin 11.

The build and the packaging are great but (sorry Tom, there’s a but), it’s a limited function device; i.e. it can only count from 0 to 9 and back again (unless I’ve missed something?).  The device has three jumpers that are closed (i.e. connected) and these relate to the reset count up and count down pins on the GPIO.  I suspect this has been done to allow leads to be attached to different pins on the header should the user wish to change the numbering.  The one I haven’t figured out yet is the open jumper at the top as I can’t seem to find any tracks leading to/from them.  However, I have yet to unpack the multimeter and go a hunting. [UPDATE: Tom pointed me at the schematic here]

If this were to go to a Rev 2 I would like to see the Borrow and Carry function made available from the 40110 chip. This could allow either feedback into the Pi via further GPIO pins or allow the daisy chaining of two or more boards

All in all it’s a tidy little add-on board which looks the part.  Top job Tom!

Posted in Add-On, Raspberry Pi | 1 Comment