Android Hello World

Here a quick documentation on how to build a C program using the Android NDK for Linux. The program can be run with the Android Terminal.

Here’s the Makefile.

NDK = $(HOME)/android-ndk-r8b
TOOLCHAIN = /tmp/ndk-hello
SYSROOT = $(TOOLCHAIN)/sysroot
GCC = $(TOOLCHAIN)/bin/arm-linux-androideabi-gcc
STRIP = $(TOOLCHAIN)/bin/arm-linux-androideabi-strip
CFLAGS = -march=armv7-a -mfloat-abi=softfp -I$(SYSROOT)/usr/include
LDFLAGS = -Wl,--fix-cortex-a8 -L$(SYSROOT)/usr/lib

all: $(TOOLCHAIN) hello

hello: hello.o
	$(GCC) $(LDFLAGS) -o $@ hello.o
	$(STRIP) -s $@

.c.o:
	$(GCC) $(CFLAGS) -o $@ -c $<

clean:
	rm -f hello *.o .*.un~

$(TOOLCHAIN):
	$(NDK)/build/tools/make-standalone-toolchain.sh --install-dir=$@

And here’s the C program hello.c.

#include <stdio.h>

int main(int argc, char** argv) {
   printf("Hello world!!!\n");
   return 0;
}

Running make should cross-compile the program.

Racket on Android

A smart smartphone

The recent smartphones have quite impressive specs. E.g. the Samsung Galaxy S III comes with a 1.5 GHz quad-core processor and a GPU. It would be interesting though to run a real programming language on one of those phones. I am quite interested in the Racket programming language (also see Wikipedia) which offers full meta-programming and compile-time macros. I managed to cross-compile Racket to run on an Android phone HTC Desire S. I’ll describe the steps here. Hopefully I’ll find time to improve things and package it in some way.

Build

To cross-compile Racket for ARM you first need to compile Racket for the host system. The GCC cross-compiler and the Racket interpreter are then used during the cross-compilation.

#!/bin/sh
ARCHIVE=$HOME/Documents/programming/racket-5.2.1-src-unix.tgz
rm -Rf /tmp/build
mkdir -p /tmp/build/host
cd /tmp/build/host
tar xzf $ARCHIVE
BUILD_HOST=/tmp/build/host/racket*
cd $BUILD_HOST/src
./configure
make install
mkdir -p /tmp/build/cross
cd /tmp/build/cross
tar xzf $ARCHIVE
BUILD_CROSS=/tmp/build/cross/racket*
cd $BUILD_CROSS/src
./configure --host=arm-linux-gnueabi
make \
  RUN_THIS_RACKET_CGC=$BUILD_HOST/src/racket/racketcgc \
  RUN_THIS_RACKET_MMM=$BUILD_HOST/src/racket/racket3m \
  RUN_THIS_RACKET_MAIN_VARIANT=$BUILD_HOST/src/racket/racket3m \
  HOSTCC=/usr/bin/gcc \
  HOSTCFLAGS="-g -O2 -Wall -pthread -I./include" \
  STRIP_DEBUG="arm-linux-gnueabi-strip -S" 
make \
  RUN_THIS_RACKET_CGC=$BUILD_HOST/src/racket/racketcgc \
  RUN_THIS_RACKET_MMM=$BUILD_HOST/src/racket/racket3m \
  RUN_THIS_RACKET_MAIN_VARIANT=$BUILD_HOST/src/racket/racket3m \
  HOSTCC=/usr/bin/gcc \
  HOSTCFLAGS="-g -O2 -Wall -pthread -I./include" \
  STRIP_DEBUG="arm-linux-gnueabi-strip -S" \
  install
cd $BUILD_CROSS/src/racket
arm-linux-gnueabi-gcc -static -o racket3m  gc2/main.o libracket3m.a  -ldl -lm  -ldl -lm -rdynamic

The last command is used to replace the racket3m binary with a statically linked version.

Installation

First I installed Android Terminal Emulator. I also installed Kevin Boone’s kbox_shell which allows you to run BusyBox without requiring to jailbreak the phone (I don’t think BusyBox is required to run Racket but it is nice to have the various Linux shell utilities). I really recommend to install Hacker’s Keyboard to have a full PC keyboard on your phone.

Android Terminal Emulator

Then one needs to copy the following files to the mobile phone:

  • The racket3m binary is copied to the mobile in a location where it can be accessed from the terminal (e.g. /data/data/jackpal.androidterm/shared_prefs/kbox/bin/racket if you have kbox_shell installed).
  • Several Racket modules located in /tmp/build/cross/racket-5.2.1/collects/… need to be copied to $HOME/.racket/5.2.1/collects on the mobile phone. The libraries are
    • racket
    • syntax
    • setup
    • config
    • compiler
    • planet
    • mzlib
    • scheme
    • unstable
    • mzscheme

Racket on Android Unfortunately the full Racket language takes 90 seconds (!) to load on the HTC Desire S. Once loaded, the REPL is very responsive though.

Racket interpreter running on Android

Hopefully I get ffi and the readline library working to have an improved command line.

Any comments and suggestions are welcome

Update

It is possible to only load the Racket base language. Running the following command

racket -I racket/base

brings up the REPL in 7 seconds. Thanks Robby for the helpful comment!

Update

Racket 5.3.0 furthermore needs the following module to be installed:

  • s-exp

Update

I haven’t managed to build Racket with the Android NDK (see my thread on the Racket mailing list). Building Racket with the Android NDK would be preferable because otherwise it is impossible to dynamically load Android libraries in order to access Android specific functionality.

Clojure for Schemers

Recently I found a video of an interesting presentation by David Nolen (homepage, blog) (comparing the Clojure programming language with Scheme (Racket). Some important points made in the talk are:

  • The Little Schemer, The Seasoned Schemer, and The Reasoned Schemer are great Q&A-style books for getting to grips with the Scheme programming language.
  • Clojure does not support optimisation of tail-recursion leading to stack overflows. However one can use lazy sequences instead.
  • Clojure does not support continuations.
  • The frequent destructuring of data using car and cdr in Scheme is cumbersome. Clojure on the other hand has syntax support for various immutable data structures (lists, vectors, hashes, and sets) which makes for more readable code.
  • Clojure is a great platform for exploring concurrency (atoms, refs, agents, promises, and futures).

David Nolen concludes that it is not a question of either/or.

See also:

Law of attraction

Can we attract good and bad things with our mind? - No!

This is one piece of certified bullshit which I have encountered one time too many.

There seem to be quite a number of people who chose to belief that you somehow can attract good stuff (health, love, money, …) by positive thinking (previously known as wishful thinking).

Initially there was the (comparatively harmless) concept of positive thinking. I.e. some psychology experts observed that successful people seem to generally have an optimistic attitude. So they came up with the notion that you could be successful in life by thinking positive thoughts.

This is simply a confusion of cause and effect. But this didn’t stop some people from taking this idea further and coming up with the law of attraction. It finally culminated with a movie called the The Secret. According to this movie, mankind (except for a select few such as Rhonda Byrne of course) has somehow missed out on the fact that it is possible to attract wealth, health, and happiness by changing one’s thoughts and feelings.

So what’s the harm? Well, this is not about threading a fine line between healthy optimism and wishful thinking. This is serious bullshit. There are people trying to cure dangerous diseases using positive thoughts. For example a recent article suggests that Steve Jobs tried to fight cancer using magical thinking.

Here’s a nice artist’s animation based on a talk by Barbara Ehrenreich. Barbara Ehrenreich points out that positive thinking might even be the root cause for the financial meltdown.

The full talk (35 minutes) is available here: http://youtu.be/PJGMFu74a70

Chequerboard Corner Detection

Camera calibration is a fundamental problem in computer vision. In the third episode of the Computer Vision for the Robotic Age podcast I am demonstrating a robust algorithm for identifying the corners of a chequerboard pattern. Identifying the corners of a calibration grid is the initial step for camera calibration.

require 'rubygems'
require 'hornetseye_ffmpeg'
require 'hornetseye_xorg'
include Hornetseye
class Node
  # Non-maxima suppression for corners
  def nms(threshold)
    # compare image with dilated image and threshold
    self >= dilate.major(threshold)
  end
  # Find a component with 'n' corners
  def have(n, corners)
    # compute number of corners for each component
    hist = mask(corners).histogram max + 1
    # compare number of corners with desired number
    msk = hist.eq n
    if msk.inject :or
      # get label of connected component
      id = argmax { |i| msk.to_ubyte[i] }.first
      # get component mask
      eq id
    else
      # return nil
      nil
    end
  end
  def corners(sigma = 5.0, size = 21)
    size2 = size / 2
    # generate chequer pattern
    f1 = finalise(size, size) do |i,j|
      x, y = i - size2, j - size2
      x * y * Math.exp( -(x ** 2 + y ** 2) / sigma ** 2)
    end
    # generate chequer pattern rotated by 45°
    f2 = finalise(size, size) do |i,j|
      x, y = i - size2, j - size2
      0.5 * (x ** 2 - y ** 2) * Math.exp( -(x ** 2 + y ** 2) / sigma ** 2)
    end
    # apply filter pair and compute corner strength
    Math.hypot convolve(f1), convolve(f2)
  end
end
# relative threshold for corner image
CORNERS = 0.6
# absolute threshold for greylevel image
THRESHOLD = 90
# width and height of calibration grid
W, H = 8, 5
W2, H2 = 0.5 * (W - 1), 0.5 * (H - 1)
N = W * H
# dilation constant
GRID = 7
# open input video
input = AVInput.new 'calibration.avi'
width, height = input.width, input.height
X11Display.show do
  # read colour image
  img = input.read_ubytergb
  # convert to greyscale
  grey = img.to_ubyte
  # call method for computing corner image
  corners = grey.corners
  # call method for non-maxima suppression
  nms = corners.nms CORNERS * corners.max
  # threshold image
  binary = grey > THRESHOLD
  # find edges using dilation and erosion
  edges = binary.dilate(GRID).and binary.erode(GRID).not
  # find connected edges
  components = edges.components
  # check for edge region with 'N' corners
  grid = components.have N, nms
  if grid
    # visualise calibration grid
    grid.and(nms).dilate.conditional RGB(255, 255, 0), img
  else
    # visualise detected corners
    nms.dilate.conditional RGB(255, 0, 0), img
  end
end

You can download a better quality version of the video here

See also: