Currently on Core Dump

OpenCyclingComputer update

OpenCyclingComputer is finally reaching the "road ready" stage:

OpenCyclingComputer, Sep 2018

What works:

  • BLE connection with heart rate sensor. Also automatic re-connection and graceful quiet handling of all errors from bluez stack.
  • BLE connection with speed and cadence sensor. It's really wheel revolution and cadence sensor, but given wheel size it works as speed sensor.
  • Pressure sensor. Iit will be used as an altimeter in the near future. Coded with Kalman filter
  • Temperature sensor
  • GPS module - I still need to do some debugging here, but the drivers were tested on raspberry A+ and worked great.
  • YAML layouts. It's very easy to change the default layout - it's simply a text file + some background images.
  • Saving / reading config file. Also YAML,  so it's a human editable.
  • "Animated" heart rate and cadence icons showing that the related sensors are "alive" and keep sending notifications.
  • All settings can be edited from the OCC screen

Things that need polishing:

  • Calculating averages (speed, heart rate, etc)
  • Implementing Kalman filters where suitable
  • BLE scanning and selecting devices from the OCC screen
  • Calculating altitude and all related parameters like slope, pressure at sea level and others
  • BLE status icon works, but it doesn't show exactly what's happening with the connection
  • Implementing Low Battery warning/shut down (hardware is ready)
  • Improving ride log. Currently the format of the log is hard coded

Code develpoment:

  • defining sensor API for future extensions
  • plugging accelerometer into the current system
  • implementing inertion+gps navigation with multi input Kalman filter
  • code cleaning and refactoring

Very simple way of accessing PiTFT 240x320 display from python with cairo

I used to use pygame, but outdated SDL problems resulting in malfunctioning touchscreen forced me to use a different solution. Touchscreen works with python-evdev and I needed graphics. Cairo is the obvious choice for 2D and after a few days of playing with different solutions I came up with this:

#Very simple way of accessing PiTFT 240x320 display from python with cairo

import mmap
import cairo

# 320 * 240 * 2 bytes per pixel = 153600
PiTFT_mem_size = 153600

# Framebuffer file, might be /dev/fb0
fb_fd  = open("/dev/fb1", "r+")

#Map the framebuffer to memory
fb_map = mmap.mmap(fb_fd.fileno(), PiTFT_mem_size)

#Create cairo surface. If you get "Function not implemented" error, you need a newer cairo
surface = cairo.ImageSurface.create_for_data(fb_map, cairo.FORMAT_RGB16_565, 240, 320)

#Create cairo context
cr = cairo.Context(surface)

# Paint the surface black
cr.set_source_rgba (0.0, 0.0, 0.0, 1.);
cr.paint_with_alpha (1.0);

for i in range(0, 10):
    c = i / 10.0
    cr.set_source_rgb (1.0 - c, 1.0 - c, 1.0)
    cr.rectangle(15 * i + 10, 15 * i + 20, 100, 100)
    cr.fill ()

#Close the mapped framebuffer

That's how it looks on the piTFT:

piTFT and cairo graphics, Jul 2018


Open Cycling Computer will be Pi Zero W based

Pi Zero W is the new brain of the Open Cycling Computer. PiTFT 2.8" capacitive dosn't work out-of-the-box, but required modification are very simple.

Modifications required in /boot/config.txt

1. Uncomment dtparam=spi=on

2. Add dtoverlay=pitft28-capacitive,rotate=90,speed=32000000,fps=20

Modifications required in /boot/cmdline.txt

1. Add after rootwait (the end of line) fbcon=map:10 fbcon=font:VGA8x8 logo.nologo

That's it! No other modifications are required.

P.S. 31-Mar-2017: Do not install adafruit kernel as it doesn't support bluetooth/wifi on Pi Zero W yet.

Lezyna Speed & Cadence sensor: Lezyne S&C 249 and

$ ./ fd:df:0e:4e:76:cf random
Connecting to: fd:df:0e:4e:76:cf, address type: random
Service <uuid=Generic Access handleStart=1 handleEnd=7> :
    Characteristic <Device Name>, hnd=0x2, supports READ WRITE 
    -> 'Lezyne S&C 249'
    Characteristic <Appearance>, hnd=0x4, supports READ 
    -> '\x85\x04'
    Characteristic <Peripheral Preferred Connection Parameters>, hnd=0x6, supports READ 
    -> '\x80\x02H\x03\x00\x00\x90\x01'
Service <uuid=Cycling Speed and Cadence handleStart=12 handleEnd=22> :
    Characteristic <CSC Measurement>, hnd=0xd, supports NOTIFY 
    Characteristic <CSC Feature>, hnd=0x10, supports READ 
    -> '\x07\x00'
    Characteristic <Sensor Location>, hnd=0x12, supports READ 
    -> '\x04'
    Characteristic <SC Control Point>, hnd=0x14, supports INDICATE WRITE 
Service <uuid=Generic Attribute handleStart=8 handleEnd=11> :
    Characteristic <Service Changed>, hnd=0x9, supports INDICATE 
Service <uuid=00001530-1212-efde-1523-785feabcd123 handleStart=30 handleEnd=65535> :
    Characteristic <00001532-1212-efde-1523-785feabcd123>, hnd=0x1f, supports WRITE NO RESPONSE 
    Characteristic <00001531-1212-efde-1523-785feabcd123>, hnd=0x21, supports NOTIFY WRITE 
    Characteristic <00001534-1212-efde-1523-785feabcd123>, hnd=0x24, supports READ 
    -> '\x01\x00'
Service <uuid=Battery Service handleStart=23 handleEnd=26> :
    Characteristic <Battery Level>, hnd=0x18, supports NOTIFY READ 
    -> 'd'
Service <uuid=Device Information handleStart=27 handleEnd=29> :
    Characteristic <Manufacturer Name String>, hnd=0x1c, supports READ 
    -> 'Lezyne'

Nautilus: batch thumbnail generation for remote location

I have a fairly large photo collection on a raspberry pi based NAS. Unfortunately RPI ethernet port is not fast enough (100MB/s) for comfortable remote operation, so to be able to use that collection I have to keep local thumbnail directory on my linux box. Gnome nautilus is my tool of choice, but nautilus generates thumbnails only after entering a directory. To make that setup workable I had to:

1. Make sure gnome allows big thumbnails and doesn't expire them: dconf-editor, go to org->gnome->desktop->thumbnail-cache and set maximum-age and maximum-size to -1

2. Generate the thumbnails

Nautilus thumbnails are saved in png files with name like this: 00067ecff5de0e48602327bc987f6d9a.png. The name is md5sum of image path with spaces replaced by %20.  The path is not an absolute path in the system! So for example I have a photo at /run/user/1000/gvfs/sftp:host=,user=pi/mnt/PhotoArchive/Dump/a_photo.jpg, but the path nautilus uses to generate thumbnail name is sftp://pi@ (it can be checked in nautilus - just right click on an image and check location). Local files have prefix file://

I had some problems with getting reliable results for a find command run on a remote system, so I decided to create 2 scripts to generate the thumbnails. The first script scans ( remote location for images, generates md5sum for the image path and, if there is no thumbnail stored locally, writes the file path to a pipe. Another script ( waits for whatever shows up in the pipe and generates the thumbnail. An example usage:

./ /run/user/1000/gvfs/sftp:host=,user=pi mnt/ sftp://pi@

and in a separate terminal:

./ /run/user/1000/gvfs/sftp\:host\=\,user\=pi/ sftp://pi@


/run/user/1000/gvfs/sftp\:host\=\,user\=pi/ <-- I have my NAS mounted at that point ($ROOT_DIRECTORY)

mnt/ <--the scripts scan should scan that directory and all subdirectories ($IMAGE_DIRECTORY)

sftp://pi@ <-- path prefix used by nautilius for that location to generate md5sum ($PREFIX)

I used those 2 script to generate over 65.000 (6 GB) of thumbnails. The directory where thumbnails are saved is hardcoded in (THUMBNAIL_DIR=/home/przemo/.cache/thumbnails/large/) - please update before using the script!

Raspberry Pi model A+ high resolution photos and 3D model


Raspberry Pi Model A+

Bluetooth BLE, gatttool and (almost) all those numbers .... explained

It's a short guide to practical side of bluetooth LE using gatttool. How to read characteristics, turn on notifications and where to find more info about all those BLE numbers.

I was strugging for a while to read data from a BLE heart rate strap. It was working flawlessly with android apps, but I needed it to use it with raspberry pi and python. So, I had to dig a bit deeper under the surface of BLE. The results are below.


1. A computer with bluetooth v4.0 card or dongle

2. gatttool (part of bluez). Fedora users might have to compile bluez as there is no gatttool in bluez-5.23-1.fc21 bugreport: [1].

3. A BLE (bluetooth Low Energy, Bluetooth Smart) device - I use a Tacx heart rate belt [2]

An example command line session (red - important or info for later use, blue - value from previous steps, green - comment):

$ hciconfig
hci0:    Type: BR/EDR  Bus: USB
^^ hci0: that's our hci device
    BD Address: C4:85:08:06:9F:C7  ACL MTU: 310:10  SCO MTU: 64:8
    RX bytes:10243057 acl:34567 sco:0 events:5307 errors:0
    TX bytes:46612 acl:737 sco:0 commands:2685 errors:0

$ sudo hciconfig hci0 up
$ sudo hcitool -i hci0 lescan
LE Scan ...   <-- LE Scan was not showing anything, so Ctrl-C and hci0 reset
$ sudo hciconfig hci0 reset
$ sudo hcitool -i hci0 lescan
LE Scan ...
D6:90:A8:08:F0:E4 Tacx HRB 04741
^^ D6:90:A8:08:F0:E4 that's BLE device address
D6:90:A8:08:F0:E4 (unknown)
D6:90:A8:08:F0:E4 Tacx HRB 04741
D6:90:A8:08:F0:E4 (unknown)

$ sudo gatttool -i hci0 -b D6:90:A8:08:F0:E4 -t random -I
^^ if you can't connect try to use "-t random"
[D6:90:A8:08:F0:E4][LE]> connect
Attempting to connect to D6:90:A8:08:F0:E4
Connection successful

Reading velue of battery level characteristic
[D6:90:A8:08:F0:E4][LE]> primary
attr handle: 0x0001, end grp handle: 0x0007 uuid: 00001800-0000-1000-8000-00805f9b34fb
attr handle: 0x0008, end grp handle: 0x000b uuid: 00001801-0000-1000-8000-00805f9b34fb
attr handle: 0x000c, end grp handle: 0x0011 uuid: 0000180d-0000-1000-8000-00805f9b34fb
attr handle: 0x0012, end grp handle: 0x0015 uuid: 0000180f-0000-1000-8000-00805f9b34fb
^^^ 180f is "Battery Service", see link [3]
attr handle: 0x0016, end grp handle: 0xffff uuid: 0000180a-0000-1000-8000-00805f9b34fb
[D6:90:A8:08:F0:E4][LE]> characteristics 0x0012 0x0015
handle: 0x0013, char properties: 0x12, char value handle: 0x0014, uuid: 00002a19-0000-1000-8000-00805f9b34fb
^^ 2a19 is Battery Level, links [4] and [5]
char properties 0x12: supports NOTIFICATION 0x10 and READ 0x02 (0x10 | 0x02 = 0x12)

[D6:90:A8:08:F0:E4][LE]> char-read-hnd 0x0014
^^ Reading handle value
Characteristic value/descriptor: 64           
^^ value of battery level is 64, but it's hex, so 0x64 = 100. It's in %, link [4]
Reading heart rate
[D6:90:A8:08:F0:E4][LE]> primary
attr handle: 0x0001, end grp handle: 0x0007 uuid: 00001800-0000-1000-8000-00805f9b34fb
attr handle: 0x0008, end grp handle: 0x000b uuid: 00001801-0000-1000-8000-00805f9b34fb
attr handle: 0x000c, end grp handle: 0x0011 uuid: 0000180d-0000-1000-8000-00805f9b34fb
^^ 180d is "Heart Rate" service, link [3]
attr handle: 0x0012, end grp handle: 0x0015 uuid: 0000180f-0000-1000-8000-00805f9b34fb
attr handle: 0x0016, end grp handle: 0xffff uuid: 0000180a-0000-1000-8000-00805f9b34fb
[D6:90:A8:08:F0:E4][LE]> characteristics 0x000c 0x0011
handle: 0x000d, char properties: 0x10, char value handle: 0x000e, uuid: 00002a37-0000-1000-8000-00805f9b34fb
^^ 2a37 is Heart Rate characteristic, links [5] and [6]
char properties: 0x10: supports NOTIFICATION
handle: 0x0010, char properties: 0x02, char value handle: 0x0011, uuid: 00002a38-0000-1000-8000-00805f9b34fb
^^ 2a38 is Body Sensor Location, links [6] and [7]
char properties: 0x02: supports READ
[D6:90:A8:08:F0:E4][LE]> char-read-hnd 0x0011
^^ Reading Body Sensor Location
Characteristic value/descriptor: 01
^^ 0x01 it's "Chest", see link [7] for more options
We need more info to switch on NOTIFICATION of heart rate
[D6:90:A8:08:F0:E4][LE]> char-desc 0x000d 0x000f
^^ range of handles for heart rate: 0x000d is start of the range obtained with 'characteristics 0x000c 0x0011'
0x0010 is start of next characteristic minus 1: 0x0010 - 0x1 = 0x000f
handle: 0x000d, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x000e, uuid: 00002a37-0000-1000-8000-00805f9b34fb
handle: 0x000f, uuid: 00002902-0000-1000-8000-00805f9b34fb
^^ 2902 it is Client Characteristic Configuration, link [8]
[D6:90:A8:08:F0:E4][LE]> char-write-cmd 0x000f 01
^^ 01 comes from link [8], NOTIFICATIONS enabled
Notification handle = 0x000e value: 00 3e        <-- heart rate, 0x003e is 63 BPM
Notification handle = 0x000e value: 00 3d        <-- heart rate, 0x003d is 62 BPM
Notification handle = 0x000e value: 00 3d        <-- heart rate, 0x003d is 62 BPM
Notification handle = 0x000e value: 00 3c        <-- heart rate, 0x003c is 61 BPM
[D6:90:A8:08:F0:E4][LE]> char-write-cmd 0x000f 00
^^ 00 comes from link [8], NOTIFICATIONS disabled
[D6:90:A8:08:F0:E4][LE]> disconnect              <-- end of connection









How to make MMA8451 working with raspberry pi over I2C

MMA88451 doesn't work with raspbterry pi out of the box. It needs I2C with repeated start. Test program in python:

import smbus
bus = smbus.SMBus(1)
ret = bus.read_byte_data(DEVICE_ADDRESS, MMA8451_REG_WHOAMI)
print ret

Shows zero instead of expected 26 (0x1A in hex)

pi@occberry ~/OpenCyclingComputer $ sudo python src/

Solution that I found here solves the problem:

sudo chmod 666 /sys/module/i2c_bcm2708/parameters/combined
sudo echo -n 1 > /sys/module/i2c_bcm2708/parameters/combined

and now the python test code shows, as expected:

pi@occberry ~/OpenCyclingComputer $ sudo python src/



Python library for Raspberry PI for Ultimate GPS based on MTK3339 with serial interface as sold by Adafruit

Python library for Raspberry PI for Ultimate GPS based on MTK3339 with serial interface as sold by Adafruit. The library helps to set different chip parameters in a sane way. Currently supports minimum functional set of commands:

CMD_HOT_START - hot_start()

CMD_WARM_START - warm_start()

CMD_COLD_START - cold_start()

CMD_FULL_COLD_START - cold_reset()

SET_NMEA_UPDATERATE - set_nmea_update_rate()

SET_NMEA_BAUDRATE - set_baudrate()

API_SET_FIX_CTL - set_fix_update_rate()

API_SET_NMEA_OUTPUT - set_nmea_output()

SET_NAV_SPEED_TRESHOLD - set_nav_speed_threshold()

All functions are preforming basic range check to make sure values areaccepted by MTK3339 as there is no check if a call was successfull or not.

Example usage:

import mkt3339

gps = mt3339("/dev/ttyAMA0")






gps.set_nmea_output(gll = 0, rmc = 1, vtg = 0, gga = 5, gsa = 5, gsv = 5)

That library is part of Open Cycling Computer project

Battery backup for Adafruit Ultimate GPS Breakout - 66 channel w/10 Hz updates - Version 3

I was testing that [1] gps chip for a last few weeks - it was great, but it was preforming "cold start" every time it was turned on. Today I finally soldiered the battery holder and slided a CR1220 battery in. If you're using the same board without the battery get one immediately. Time to fix is now a few seconds (used to be up to 15 minutes) and it gets the fix fairly quickly indoor as well!!

I'm planning to use that board in the Open Cycling Computer project. More to come.


PiTFT capacitive calibration for vertical layout

PiTFT capacitive doesn't require calibration according to Adafruit, but for some reason I couldn't make it work properly with vertical layout and the default values suggsted here [1].

The default values are:

320 65536 0 -65536 0 15728640 65536

I needed to use the screen with Adafruit logo at the bottom [fbtft_device.rotate=90] and with the default /etc/pointercal values I had x axis swapped with y axis.

Explanation how the pointercal values works is here [2]. Some matrix math:



x,y - the touchscreen coordinates returned by the kernel driver

a,b,c,d,e,f,s - pointercal values

u,v - the screen coordinates

The above equation converts to:

u = (x*a + y*b +1*c)/s

v = (x*d + y*e +1*f)/s

For the default values:

a = 320, b = 65536, c = 0 d = -65536, e = 0, f = 15728640, s = 65536

u = (x*320 + y*65536 + 0) / 65536

v = (x*(-65536) + y*0 + 15728640) / 65536

I wanted to flip x<->y, so

u = (x*(-65536) + y*0 + 15728640) / 65536

v = (x*320 + y*65536 + 0) / 65536

and now a = -65536, b = 0, c = 15728640 d = 320, e =65536 , f = 0,  s = 65536.

However when I tried to use those values in the pointercal file:

-65536 0 15728640 320 65536 0 65536

I found out that x axis is OK, but y axis is still flipped. To fix it we have to change sign of v and add a shift.

v = -(x*320 + y*65536 + 0) / 65536 +320

v = (x*(-320) + y*(-65536) +0)/65536 + 320

v= (x*(-320) + y*(-65536) +0)/65536 + 320*65536/65536

v= (x*(-320) + y*(-65536) +320*65536)/65536

v= (x*(-320) + y*(-65536) + 20971520)/65536

so d = -320, e = -65536 and f = 20971520

Proper pointercal values for vertical layout [fbtft_device.rotate=90] are:

-65536 0 15728640 -320 -65536 20971520 65536

Bosch BMP183 with SPI by Adafruit in python on Raspberry PI

How to measure temperature and pressure with raspberry pi and BMP183


- raspberry Pi
- BMP183 with SPI by Adafruit
- 6 wire female-to-female cable or any other to connect 6 pins between RPI and BMP183


Temperature: 18.9 deg C

Pressure: 1013.39 hPa

RPI + BMP183: rpi_a_and_bmp183.jpg

Schematic (png): rasperry_pi_and_bmp183_sensor.png

That entry is the first part of Open Cycling Computer project

Schematic (QElectroTech): rasperry_pi_and_bmp183_sensor.qet

BMP183 at Adafruit

All files on github

BMP183 datasheet

i4oled-gui is ready!

Now there is a way of setting OLED icons on Wacom Intuos4 tablets using simple GUI:

The source code can be downloaded from GitHub.

It requires gnome & dconf, but it doesn't require root access rights as it works by writing to dconf. I hope that some of the ideas tested in i4oled-gui will be used in gnome.

Installing on Fedora 20:

1. Install required packages: sudo yum install git autoconf automake gcc gtk3-devel dconf-devel

2. Clone the repository

git clone

3. Enter & build

cd i4oled-gui




sudo make install

If there is a message about missing gtk+-3.0 during configure stage it means that there is no gtk3-devel package. Same for dconf - it means that there is no dconf-devel package. Ubuntu uses different names: gtk3-dev and dconf-dev.

i4oled-gui looks for icons in 3 locations:




The first two are shown when "System" button is pressed, The last path is linked with "User" button.

Icons have to be PNG files, 64 x 32, 8-bit/color RGBA, non-interlaced There is a script in data/pixmaps/svg/ that converts SVG to the desired format. Also all icons generated by i4oled can be used. Text entry fields also accepts base64 strings generated by i4oled, but it's not yet a fully finished feature (stop & start of i4oled-gui is required to see the icon)

Known limitations: i4oled-gui works on first usb tablet found in dconf user file, so if you have more than one tablet .. tough luck (at least untill i4oled-gui lands in gnome). There is no bluetooth support yet. Also there is no live preview of rendered text in the icon field.

If you read this entry this far (well done!!) it means that you're interested in using i4oled-gui, so if you want to send me a feedback use GitHub or przemo (at) firszt (dot) eu

OLEDs-over-bluetooth are on the way to gnome

Hopefully soon gnome users will be able to fully utilise OLED displays on wacom Intuos4 wireless tables. More (technical) details here:

i4oled v1.2 is out

Version 1.2 of OLED handling tool for Wacom Intuos4 Wireless is out! Most important changes are that now i4oled allows to use base64 encoded strings as input or output and it allows multiple outputs at the same time. The base64 strings can be used with gnome dconf-editor to show an icon instead of text. The base64: string should be pasteed into oled-label field instead of normal description. Gnome-settings-daemon will do the rest and convert it back into nice icon on the tablet. The version 1.2 can be downloaded here.

Using Wacom Intuos4 Wireless in unusual way

How to make clock out of your wacom tablet (with OLEDs obviously)?


There is one thing required - it's i4oled

The "clock" can be set up over usb or bluetooth link. The example below uses bluetooth

1. Connect tablet. 2. Change permissions for OLEDs as we want to use i4oled without root access.

sudo chmod a+w /sys/bus/hid/drivers/wacom/0005\:056A\:00BD.0001/oled?_img

3. Change permissions for LED selector - it's brightness is linked to OLEDs

sudo chmod a+w /sys/bus/hid/drivers/wacom/0005\:056A\:00BD.0001/leds/0005\:056A\:00BD.0001\:selector\:0/brightness

4. Change the brightness

echo 200 > /sys/bus/hid/drivers/wacom/0005\:056A\:00BD.0001/leds/0005\:056A\:00BD.0001\:selector\:0/brightness

Now we're ready to test i4oled:

i4oled -b -t TEST -d /sys/bus/hid/drivers/wacom/0005\:056A\:00BD.0001/oled7_img

If text TEST shows up next to the bottom button it means that everything works fine and we can set up the clock:

while [ 1 ]; do i4oled -d /sys/bus/hid/drivers/wacom/0005\:056A\:00BD.0001/oled7_img -b -t $(date +%D+%T); sleep 1; done

The above command converts current date & time into image and sends it to the OLED screen:

How to change OLED label on Intuos4 tablets on gnome

If you have that tablet you probably want to have full control of what is being displayed on those little OLED screens on the tablet. Currently gnome doesn't give option to change it - you just have to accept whatever was generated for you. Or, do you?

This is a workaround and I hope in long run we wont need it.

Hit Alt-F2 and type "dconf-editor" Go to org -> gnome -> settings-daemon -> peripherials -> wacom

You should see there a ID string that look very user unfriendly, like here:


Open the item and find buttons section and edit OLED label:


That's it! You should see this on your tablet:


i4oled - bluetooth support

i4oled just got bluetooth support. Wacom Intuos4 WL supports 4-bit images over USB connection, but only 1-bit when connected over bluetooth. i4oled now supports both with --bluetooth switch. Example usage:

i4oled -d /sys/class/hidraw/hidraw0/device/oled5_img -t "Alt+Ctrl" --bluetooth
i4oled -d /sys/class/hidraw/hidraw0/device/oled7_img -i help.png -b

And that's how it looks on the device:

Wacom OLEDs ovet bluetooth

Galaxy S4 3D printed car holder

S4 holder

S4 holder closeupS4 holder with phoneS4 holder in car

The cradle for S4 is based on an old S2 car holder:S2 holder

S2 holder part 2

All designed using FreeCAD and Blender 3D.

S4 holder.blend

The model _will_ require some cutting after printing otherwise it won't fit the phone. Additional cutting might be required if battery cover has been replaced.

OpenSCAD - first battle

My first attempts to use OpenSCAD:

module hc_hexagon(size, height) {
box_width = size/1.75;
for (r = [-60, 0, 60]) rotate([0,0,r]) cube([box_width, size, height],
module hc_column(length, height, cell_size, wall_thickness) {
no_of_cells = floor(1 + length / (cell_size + wall_thickness)) ;
for (i = [0 : no_of_cells]) {
translate([0,(i * (cell_size + wall_thickness)),0])
hc_hexagon(cell_size, height + 1);
module honeycomb (length, width, height, cell_size, wall_thickness) {
no_of_rows = floor(1.75 * length / (cell_size + wall_thickness)) ;
tr_mod = cell_size + wall_thickness;
tr_x = sqrt(3)/2 * tr_mod;
tr_y = tr_mod / 2;
off_x = -1 * wall_thickness / 2;
off_y = wall_thickness / 2;
cube([length, width, height]);
for (i = [0 : no_of_rows]) {
translate([i * tr_x + off_x, (i % 2) * tr_y + off_y, (height) / 2])
hc_column(width, height, cell_size, wall_thickness);
//honeycomb(length, width, height, cell_size, wall_thickness);
honeycomb(140, 80, 20, 5, 1);

Formatting doesn't look very good in narrow blog, it looks better here: honeycomb.scad

Honeycomb - blender render

And more files: honeycomb.csg , honeycomb.stl and blender model honeycomb.blend

P.S. Thanks to help from OpenSCAD forum I have a new, improved & much faster honeycomb script:

module hc_column(length, cell_size, wall_thickness) {
        no_of_cells = floor(length / (cell_size + wall_thickness)) ;

        for (i = [0 : no_of_cells]) {
                translate([0,(i * (cell_size + wall_thickness)),0])
                         circle($fn = 6, r = cell_size * (sqrt(3)/3));

module honeycomb (length, width, height, cell_size, wall_thickness) {
        no_of_rows = floor(1.2 * length / (cell_size + wall_thickness)) ;

        tr_mod = cell_size + wall_thickness;
        tr_x = sqrt(3)/2 * tr_mod;
        tr_y = tr_mod / 2;
        off_x = -1 * wall_thickness / 2;
        off_y = wall_thickness / 2;
        linear_extrude(height = height, center = true, convexity = 10, twist = 0, slices = 1)
                        square([length, width]);
                        for (i = [0 : no_of_rows]) {
                                translate([i * tr_x + off_x, (i % 2) * tr_y + off_y,0])
                                        hc_column(width, cell_size, wall_thickness);

//honeycomb(length, width, height, cell_size, wall_thickness);
honeycomb(140, 80, 20, 5, 1);

- page 1 of 2