Ball launcher

My friends studying Industrial Design are currently doing a “smart product” project where they have to make an active 2-player game out of LEGO using the NXT and a launcher of some sort.

If I had to make such a game, I’d probably make a Twister robot that carefully calculates impossible positions and shoots at you while you’re struggling. Sounds fun, right?

But I don’t have to make such a game, so I can just have some fun making a launcher.

Theremin

I made another silly thing. I came across a musical instrument called a Theremin. The real deal uses a really cool concept where your body and 2 antennas act as a capacitor in an LC circuit. By changing the distance between your body and the antennas, the capacitance changes, which changes the resonance frequency and modifies the pitch and amplitude of the output signal.

This thing is much more silly. It uses the IR sensor to measure the distance to your hand and generates a tone based on that. It works nothing like the real thing.

The sound quality of the EV3 is terrible, because it’s just a small speaker attached to a PWM port with a low-pass filter.

The IR sensor is slow, inaccurate and discrete. So you can do none of the slides and vibrato you can do with a Theremin. At first I tried to smooth the input to get a more natural sound, but that made it even slower and impossible to tune. So in the end I mapped the discrete input steps to discrete notes, so that it at least sounds in tune. You still can’t play anything on it though.

I wrote the code for this in C on ev3dev. I use ev3c to talk to the sensors and libasound to generate the sound. This took a while to get working.

#include "ev3c.h"
#include <stdio.h>
#include <math.h>
#include <stdint.h>
#include "alsa/asoundlib.h"

static char *device = "default";                        /* playback device */
snd_output_t *output = NULL;
unsigned char buffer[800];                          /* some random data */

int main(void)
{
  int err;
  unsigned int i;
  snd_pcm_t *handle;
  snd_pcm_sframes_t frames;
  if ((err = snd_pcm_open(&handle, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
          printf("Playback open error: %s\n", snd_strerror(err));
          exit(EXIT_FAILURE);
  }
  if ((err = snd_pcm_set_params(handle,
                                SND_PCM_FORMAT_U8,
                                SND_PCM_ACCESS_RW_INTERLEAVED,
                                1,
                                8000,
                                1,
                                500000)) < 0) {   /* 0.5sec */
          printf("Playback open error: %s\n", snd_strerror(err));
          exit(EXIT_FAILURE);
  }

  const double interval = pow(2, 1.0/12.0);
  const double R=8000; // sample rate (samples per second)
  double F=440; // frequency of middle-C (hertz)
  double Fp = F;
  double V=127; // a volume constant
  double t; // doudle counter, yeaaaa


  //Loading all sensors
  ev3_sensor_ptr sensors = ev3_load_sensors();
  ev3_sensor_ptr prox1 = sensors;
  ev3_mode_sensor(prox1,0);
  ev3_open_sensor(prox1);
  while(1)
  {
    ev3_update_sensor_val(prox1);
    Fp = F;
    F=220*pow(interval, prox1->val_data[0].s32/4);
    t*=Fp/F; // scale time with frequency change
    // this is to maintain a continuous sine

    fprintf(stderr, "%d, %f\n", prox1->val_data[0].s32, F);
    
    for ( i=0; i<800; i++ ) {
      t+=1;
      buffer[i] = (sin(t*2*M_PI*F/R)+1)*V;
    }

    //printf("%d\n", snd_pcm_avail(handle));
    frames = snd_pcm_writei(handle, buffer, sizeof(buffer));
    if (frames < 0)
            frames = snd_pcm_recover(handle, frames, 0);
    if (frames < 0) {
            printf("snd_pcm_writei failed: %s\n", snd_strerror(frames));
            break;
    }
    if (frames > 0 && frames < (long)sizeof(buffer))
            printf("Short write (expected %li, wrote %li)\n", (long)sizeof(buffer), frames);
  }
  //Let's delete the list in the very end. It will also close the
  //sensors
  ev3_delete_sensors(sensors);
  snd_pcm_close(handle);
  return 0;
}

Chandelier bot

I wanted to invite someone over to watch a movie, but realised that my energy saving light bulb isn’t the most cozy environment ever. The light they give of always feels a bit cold.

To remedy this I went to the store to buy some candles (and forgot to buy matches). But just plain candles seemed so boring, so I wanted to do something special with them.

I remembered from years back this Tai Chi practice where you put glasses of water or candles on your hands and rotate them over and under your shoulder. It creates this beautiful spiral movement. So I thought it would be nice to make a robot that moves my candles around.

The robot is done. Now to wait for the movie.

Improved Mars Rover

I noticed one particular gear causing a lot of slipping, the large one driving the bogie. It misbehaved in two ways:

The large gear was pushed sideways by the force of the motor, pushing apart the frame and causing the top gear to slip.

The large gear exerted force on the bogie, pushing one wheel off the ground under force.

To solve these issues, I used a smaller gear and reinforced the frame. This helps keep all the gears together and all the wheels on the ground. The robot can now climb much bigger obstacles.

IMG_20150326_153433

EV3 Mars Rover

I have tried before to make a Rocker-Bogie robot, similar to NASA’s Mars rovers. But with the NXT I always had a shortage of structural parts, leading to incomplete and unstable constructions.

With the EV3 it works surprisingly well, and I was able to power all the wheels with two motors, and leave enough parts to make a robotic arm.

It looks lovely, and the principle works, but the actual capabilities are slightly disappointing as the torque is very limited. Climbing any large obstacles pushes the bogie off the ground and rattles some of the many gears.

CD spinner

I know this is a rather silly robot. It does nothing at all, and it’s not very beautiful either. I guess I just want to remind you that it’s important to just play without expectations or goals.

According to John Cleese, it is very useful to attempt something impossible sometimes. This often puts your mind in a new perspective, leading to new ideas.

Reading a CD with a light sensor is obviously not going to work, but maybe there are other ways to read data with the EV3?

EV3 Sumo Robot

After a long period of silence, I finally made some things with my EV3. Last time the tools where not really ready, but now everything works great.

I used ev3dev and python-ev3 to build this bulldozer. Watching sumo matches at LEGO World, I saw a few things that do and don’t work.

A lot of people seem to go for blades and hammers, but unless you actually want to destroy the robot, they are useless. Treads sound like a good idea, but wheels have more grip in practice. Make sure the wheels don’t fall off. Encased wheels are the best.

The goal is to push the other robot off the table, so the more powered rubber the better. Four wheel drive is better than rear wheel drive, but rear wheel drive is still much better than front wheel drive.

It’s all about pushing. The only useful thing besides pushing forward is pushing up or sideways. Pushing up is the easiest, because you have the floor to back you up. It also pushes the opponent’s wheels off the ground. This lead me to the following design.

I used two pairs of driven rear wheels on a pivot, so even if I’m lifted, all four remain in contact with the ground. They are geared down, which means I’m slow, but powerful. All the weight of the motors and EV3 is directly above the wheel, for maximum grip.

On the front there is a lift arm, using a worm wheel and a very solid construction. I went through several iterations, improving the strength each time. On the first iteration, it was to weak, but its wedge shape still lifted my opponent a little.

The code is quite simple. Push forward. When you reach the edge, turn around. When something hits the bumper, raise the arm.

from ev3 import lego
import time
import select
import os

# Utility for waiting on the motor.
p = select.poll()
callbacks = {}

def poll():
    for fd, mask in p.poll(0):
        os.lseek(fd, 0, os.SEEK_SET)
        state = os.read(fd, 16)
        if state == "idle\n":
            p.unregister(fd)
            os.close(fd)
            callbacks.pop(fd)()

def on_completion(motor, callback):
    fd = os.open(motor.sys_path + '/state', os.O_RDONLY)
    callbacks[fd] = callback
    os.read(fd, 16)
    p.register(fd, select.POLLPRI)

# Initiate all sensors and motors
l = lego.LargeMotor("A")
r = lego.LargeMotor("D")
lift = lego.MediumMotor()

dist = lego.InfraredSensor()
line = lego.ColorSensor()
touch = lego.TouchSensor()

# reset the motors
l.reset()
r.reset()
lift.reset()

try:
    # run forwards
    l.run_forever(100, regulation_mode=False)
    r.run_forever(100, regulation_mode=False)
    # main loop
    while True:
        poll()
        if touch.is_pushed and lift.state == "idle":
            # we hit something, raise the arm!
            lift.run_position_limited(-3000, 1000)
            on_completion(lift, lambda: lift.run_position_limited(0, 1000))
        elif line.reflect < 20 and l.duty_cycle > 0 and r.duty_cycle > 0:
            # we reached the edge, back up and scan for opponent
            l.run_time_limited(1000, -100)
            on_completion(l, lambda: l.run_forever(100))
            r.run_forever(-100)
        elif dist.prox < 50:
            # found opponent, charge!!!
            r.run_forever(100)
            l.run_forever(100)
finally:
    # stop motors and lower arm
    l.stop()
    r.stop()
    lift.run_position_limited(0, 1000)

Excavator wheel base

Today I took out the RCX and made a wheelbase for the NXT excavator arm I made earlier.

I am satisfied with the look and maneuverability, the only problem remains where to put the RCX. Maybe I can put both the NXT and the RCX on the arm, or make some room in the wheelbase.

It will also be interesting to control the whole maschine. The NXT and RCX can’t really talk to each other, but both can talk to the computer over Bluetooth and Infrared respectivly. So maybe I wil make a command centre on the computer to control both devices.

Excavator

Today I spent some time building an excavator. I had to choose between controlling all parts of the arm and letting some parts move together mechanically.

I chose to do the former, which means I don’t have any motors left for the chassis, but can freely move all parts of the arm.

Maybe another NXT or RCX kit could serve as the base, which also needs 3 motors: 2 to drive and 1 for the rotating platform.