Wishful Coding

Didn't you ever wish your
computer understood you?

Crazy Seq

crazy-seq, the solution to all your head-holding induced memory problems.

(defn crazy-seq [head f]
  (reify
    clojure.lang.ISeq
    (first [_] head)
    (more [_] (crazy-seq (f head) f))
    (next [this] (rest this))
    (seq [this] this)
    (equiv [_ _] false)))

(def s (crazy-seq 0 inc)) ; hold head
(dorun (take 100000000 s)) ; low fat
(nth s 10) ; recomputes
;=> 10

A normal lazy seq is made up of a car and a function that returns the cdr, which is then cached.

This means that if you store the first item and walk to the millionth, it will keep all these million items in memory.

What crazy-seq does, is that it simply does not cache the value. So you can walk to the millionth item, and it will only store the first and the current, the others are GC’d.

This means that walking twice will cost more CPU cycles, and it means that you get in trouble if the fn is not side-effect free.

Have fun.

Published on

RCX Snow Plow

Over here in the Netherlands we usually have just a few days or weeks of snow per year. When the time comes, there are three things that absolutely have to happen.

  1. Go sledging
  2. Go ice skating
  3. Build a robot to drive in the snow

I wont bother you with the first two items, but I thought you might like number three.

I was surprised that I couldn’t find a single video of  a snow plow, plowing real snow. There are robots pushing LEGO around, and static models of a snow plow. This is what I made.

The robot is a regular half-track, but uses a triangular tread configuration to keep the motor out of the snow. It also has a rotation sensor on the unpowered front wheels, to detect the robot isn’t moving.

I’m not sure if you are interested in the software or building instructions, because it uses the RCX with parts from Ultimate Accessories and Ultimate Builders sets, as well as miscellaneous red parts. Are you?

Published on

Sciento CS-113

After my success with the Cyber arm, I had to try my luck at the Sciento one.

This time I was out of luck with Dutch or English documentation, but my brother found a Spanish PDF, from which I was able to get the needed information using Google Translate.

Unlike the Cyber, the Sciento is controlled by sending actual ASCII commands, rather than stepping the motors directly.

It is a lot smarter than the other arm, as it can remember its position. A list of commands:

  • “Z” Sets the reference point
  • “N” Go to the reference position
  • “C”/”O” Close/open the claw
  • “M100,0,-250,0,0,0” Move the motors for the specified steps.
  • “H7” Save the current position in the specified register(1-100)
  • “P5,500,200,-5,0,0,0” Save the specified position in the specified register(first number, 1-100)
  • “G1” Move to the location in the specified register
  • “S5” Set the motor speed(1-5)
  • “D1” Wait for x seconds. Useless?
  • “L1” Check the limits of the motors. Recommended for testing, off by default.

Note that numbers are represented as ASCII text and that commands are upper-case. All commands are terminated by a carriage return.

A downside to this arm is that in comparison to the one-byte commands for the Cyber, it takes ages to send an ASCII command across, making this arm unsuitable for smooth control with a gamepad.

I programmed a coarse and ugly controller, with buttons for storing positions and moving to them. In the video I’m just stepping through the motions I stored earlier.

The controller is a real mess, based on the Cyber code, and not very interesting.

The code for the arm itself is nice though. Note the use of the actual strobe line, as opposed to the strobe bit in the Cyber code.

import parallel
from time import sleep

p = parallel.Parallel()

def write(s):
    bs = map(ord, s)
    bs.append(13)
    for b in bs:
        p.setData(b)
        p.setDataStrobe(1)
        p.setDataStrobe(0)
        sleep(0.001)

def command(cmd, *params):
    write(cmd+",".join(map(str, params)))

def move(m1=0, m2=0, m3=0, m4=0, m5=0, m6=0):
    "Move a number of steps"
    command("M", m1, m2, m3, m4, m5, m6)

def here(n):
    "Save current position in slot n 1-100"
    command("H", n)

def position(n, m1, m2, m3, m4, m5, m6):
    "Save the specified position in slot n 1-100"
    command("P", n, m1, m2, m3, m4, m5, m6)

def zero():
    "Set the reference point"
    command("Z")

def goto(n):
    "Go to position in slot n 1-100"
    command("G", n)

def home():
    "Return to the reference"
    command("N")

def open():
    "open the claw"
    command("O")

def close():
    "Close the claw"
    command("C")

def speed(n):
    "Set the speed 1-5"
    command("S", n)

def delay(n):
    "Wait for n seconds"
    command("D", n)

def limit(b):
    "enable/disable limits"
    commands("L", b)