2012-08-26

Raspberry Pi controlled lamp

I'm a software guy and I'm scared of electronics. At the same time I find it exciting when software actually does something in the real world. (That's why I love Lego Mindstorms.) Home automation is my lifelong dream. I'd like to be able to use my computer to turn the lights on and off, roll up the window blinds and remotely control everything else that can be controlled.

That dream will have to wait, but today I used my Raspberry Pi to make a small proof of concept.



One of the many cool things about the Raspberry Pi is that it has some general purpose I/O pins exposed that can be used to communicate with the outside world using various protocols. The simplest thing you can do is to set a single pin to a high or low state. When combined with something called a relay, that is enough to control an electrical device plugged into a wall socket (or at least to turn it on and off). I used this relay from Seeedstudio. The relay has three pins (actually four, but one is unused), labeled VCC, GND and SIG. I connected VCC to the 5V pin on the Pi and GND to the ground pin. The SIG pin must be connected to one of several GPIO pins available. You can find a detailed description of Raspberry Pi's GPIO pins on the wiki. I connected the SIG pin from the relay to GPIO18, which is the sixth pin from the left in the top row.

Then I butchered a power strip. I removed the insulation from a segment of the cable, cut one of the cables inside, stripped some insulation from the ends and put them into the screw terminal on the relay. This is the part I was most uneasy about. You should obviously exercise caution when working with stuff that will be connected to mains voltage (extra caution when it actually is connected).

With everything attached, the only part remaining is software. The GPIO pins can be controlled through special files in the /sys filesystem, but I used a library called WiringPi. It includes the gpio command line tool, which makes working with GPIO pins easy.

First you have to configure the pin for output:

gpio export 18 out

Then you can set the state to high with:

gpio -g write 18 1

And to low with:

gpio -g write 18 0

Thus switching the relay on and off. I wrapped those commands in some trivial CGI scripts for the purpose of demonstration and controlled the lamp via a web browser.

2012-08-21

NXT delta robot

A delta robot is a robot with three motors placed on a triangular base, connected to a smaller triangular platform through three arms (the second platform is called the end effector, because it's the part that actually does stuff). The arms have universal joints in them and work as parallelograms. Because of that, the end effector's movement is restricted to just X,Y,Z translations, it doesn't rotate and stays parallel to the base. Because of their speed and precision, delta robots are widely used in the packaging industry and other places.

They're also the kind of thing that you look at and immediately think hey, I bet I could recreate that with Lego Mindstorms!



To make the robot work, we have to take the desired position of the end effector and translate it to angles to which the three arms must be rotated by the motors (fancy term for that is inverse kinematics). It involves some geometry, but luckily for us a man named Maxim Zavatsky worked it all out and posted a nice tutorial here. The program that controls my robot (which you can see here) is mostly a copy & paste of his code.

When making this robot, I found out that even though the NXT motors have encoders that tell you their rotations with degree accuracy, it's not very easy to precisely reach a certain angle on the motor. Setting up a gear reduction would help with the precision, but the Mindstorms set doesn't come with enough gears for three arms. I ended up using absolute position regulation from the enhanced NBC/NXC firmware (PosRegEnable() and PosRegSetAngle() functions). Since the PosRegSetAngle() call is non-blocking (it returns immediately and the position regulation happens in the background), it would be good to have a way of knowing when the motor has reached its set point. One solution that comes to mind is to keep watching the motor's position and when it stops changing assume that it is as close to the desired angle as it's going to get. Right now I'm using hard-coded Wait() calls, which is obviously not optimal.

My robot doesn't actually do anything (except move), but it would be interesting to attach a pen to it and make it into a drawbot. For that I'd have to somehow mount it upside down and probably work on making it a little stiffer (right now it's pretty wobbly). Another thing to try would be to reverse the calculations and turn the robot into a 3D input device (you would move the end effector by hand, read the angles from the motors, translate those into X,Y,Z and send the data to a computer).

Here's an album with some pictures of the robot.

Subway buddies

Have you ever wondered if you're meeting the same people every day on your daily commute? Over half a million people ride the Warsaw Metro daily, but if I arrive at the station at roughly the same time every day, surely there must be others with similar schedules? But even after almost a year of taking the same route, I couldn't recognize any familiar faces. So I decided it was time for a more scientific approach.

A surprisingly large number of people leave their phone's Bluetooth in discoverable state (I find it strange, because on most phones I've seen the default behavior is only to become discoverable for 120 seconds or so when pairing). I thought if I scanned for Bluetooth devices every time I rode the subway and saved the results, I could then check if I ever saw the same device on different days. So that's what I did, I made an application for my phone that does a Bluetooth scan and logs all devices it sees in a SQLite database. That was not ideal yet, because I still had to trigger the scan manually every time (I didn't want to keep scanning all the time, because that would quickly drain the battery and also I'd get a lot of false positives from my neighbors, coworkers etc.). Happily, there is a solution. Living in a city, just about the only time I lose cell phone signal is when I get on the subway. So that's a good condition to wait for to trigger the scan (there will be occasional false positives, but they don't bother us much). Obviously, this only works if your commute involves riding the subway and not, say, a bus.

Here's the source code of the application if you'd like to play with it.

So are there any strangers that happen to commute at the same time I do? After just two weeks of the experiment, with the help of a SQL query:

select addr, count(*), max(sightingtime)-min(sightingtime) y, group_concat(sightingtime) from sighting group by addr having y > 3600 order by y desc;

I found two persons that I shared a subway ride with on two different days. Unfortunately I can't really say much about them, except for the fact that one of them had an LG phone and the other a Samsung.

2012-02-21

Electricity meter fun

At the place I live, the electricity meter looks like this:



The fancy display shows total kilowatt hours and maximum power consumption, but it doesn't show current consumption. Instead it has this blinking red light - the faster it blinks, the higher the power consumption. But to get the actual figure, I'd have to count how many times it blinked, measure the time and then do some arithmetic. And that would be pedestrian. Instead I wrote an application for my phone that does the measurements (with the phone's camera) and displays the current power consumption:



Here's the source code if anyone's interested.

2011-12-31

NXT Drawbot

When I saw this drawbot, I immediately thought it was something I should be able to recreate with Lego Mindstorms. And so I did. The idea is simple, there's a pen suspended on thread from motors in the corners. When the motors wind or unwind the thread, the pen moves and draws a line. The rest is a simple application of the Pythagorean theorem to move the pen where we want it.



When watching other drawbots on YouTube etc. I was surprised to see they were able to achieve a level of precision that allows them to recreate pictures by effectively drawing each of their pixels with clever patterns. My bot clearly lacks such precision. I think the main reason for that is the friction between the pen and the drawing surface. Each time the pen is about to start moving, there's a noticeable moment before it breaks away from the static friction. That makes the bot incapable of very small precise movement. There's another source of imprecision - since the radius of the spools that the threads are wound onto is small, the difference in radius when there is no thread wound and when there is a lot of thread wound on the spool is non-negligible.

Here are some more pictures of the bot.

2011-10-20

Google Earth with a PS3 controller

Google Earth is a lot of fun with a 3D input device. But not everyone can justify shelling out a hundred bucks or so on a SpaceNavigator just to play with Google Earth. I've explored other possibilities, but the best alternative I've come up with is the PS3 controller. It has more than enough joysticks and buttons for five degrees of freedom. Have a look:

The PS3 controller is pretty well supported under Linux (at least if you connect it with a USB cable, it's more complicated if you want to use Bluetooth). The only problem really is mapping its various buttons and joysticks to proper functions in Google Earth. Fortunately, there is a piece of software called pystromo that can freely remap input events, thus allowing us to turn a PS3 controller into a SpaceNavigator-lookalike.

Here's what you need to do.

  • Download and unpack pystromo.
  • Open the lib/constants.py file in the pystromo directory with a text editor. Find the line containing "ABS_MISC" and add the following two lines after that (before the curly brace):
    48: "ABS_L2",
    49: "ABS_R2",
    
    (We have to do this, because pystromo doesn't have constants for the PS3 controller's L2 and R2 buttons.)
  • Create a new file in the pystromo directory and call it, say, config/ps3-ge.map. Put the following in it:
    [Device:dualshock]
    vendor=0x054c
    product=0x0268
    
    [Map:dualshock]
    ABS_X@0~255:ABS_X@0~255
    ABS_Y@0~255:ABS_Y@0~255
    ABS_Z@0~255:ABS_RZ@0~255
    ABS_RZ@0~255:ABS_RX@255~0
    ABS_L2@0~255,ABS_R2<1:ABS_Z@127~0
    ABS_R2@0~255,ABS_L2<1:ABS_Z@127~255
    
  • Connect your PS3 controller using a USB cable and press the PS button.
  • As root, run the following command: ./pystromo-remap.py -R -v -m config/ps3-ge.map
  • This will create a new input device, called eventN in /dev/input/. The one you're looking for is the one with the highest number. As root, run this to give your regular user access to the device: chmod 666 /dev/input/eventN
  • Open /opt/google/earth/free/drivers.ini with a text editor and put the following after the "SETTINGS" line (after the curly brace), remembering to replace eventN with the proper device number:
    SpaceNavigator/sensitivityX = 0.4
    SpaceNavigator/sensitivityY = 0.4
    SpaceNavigator/sensitivityZ = 0.1
    SpaceNavigator/sensitivityPitch = 0.05
    SpaceNavigator/sensitivityYaw = 0.05
    SpaceNavigator/sensitivityRoll = 100
    SpaceNavigator/device = /dev/input/eventN
    SpaceNavigator/zeroX = 127
    SpaceNavigator/zeroY = 127
    SpaceNavigator/zeroZ = 127
    SpaceNavigator/zeroPitch = 127
    SpaceNavigator/zeroYaw = 127
    SpaceNavigator/zeroRoll = 127
    
  • Run Google Earth.

You should now be able to navigate using the left and right sticks and L2/R2 buttons.

2011-10-17

Control Google Earth with an Android tablet

I have previously described how to turn an Android device into a mouse under Linux, using the uinput module. There's no reason we should limit ourselves to a simple mouse. Some applications benefit from a multi-axis controller, which we can simulate in a similar way. One such application is Google Earth. Here's a demonstration video:

And here's how it's done. Just as before, there's an application running on the tablet that listens for touch events and broadcasts them on the network and a Python script running on the computer that listens for those events and translates them to simulated controller events that Google Earth understands. Here's the tablet application's source code and here's just the APK if you don't want to compile it yourself. The Python script that's running on the computer is here.

There are some additional hoops you have to jump through to get it running.

  • The Python part requires python-uinput, which in turn requires libsuinput.
  • Remember to unblock UDP port 20125 on your computer's firewall, as that's the port that the tablet application uses to broadcast touchscreen events (the tablet and the computer obviously have to be on the same network).
  • Run android3dmouse.py as root.
  • Run the TouchscreenBroadcaster3D application on your Android device and touch the screen (the simulated mouse device only appears on the computer after the first events are emitted).
  • Look in /dev/input/ and figure out what the newly created device is called (it's going to be the eventN file with the highest number).
  • As root, execute the following command to let Google Earth running as a regular user access the device: chmod 666 /dev/input/eventN
  • Open /opt/google/earth/free/drivers.ini with a text editor and paste in the following after the "SETTINGS" line (after the curly brace), remembering to replace eventN with the proper device name:
    SpaceNavigator/sensitivityX = 80
    SpaceNavigator/sensitivityY = 80
    SpaceNavigator/sensitivityZ = 30
    SpaceNavigator/sensitivityPitch = 0.5
    SpaceNavigator/sensitivityYaw = 0.5
    SpaceNavigator/sensitivityRoll = 0.5
    SpaceNavigator/device = /dev/input/eventN
    SpaceNavigator/zeroX = 0.0
    SpaceNavigator/zeroY = 0.0
    SpaceNavigator/zeroZ = 0.0
    SpaceNavigator/zeroPitch = 0.0
    SpaceNavigator/zeroYaw = 0.0
    SpaceNavigator/zeroRoll = 0.0
    SpaceNavigator/gutterValue = 0
    
  • Since X happily grabbed the new device and it now moves the mouse cursor, execute the following command to make X let it go: xinput set-int-prop "python-uinput-mouse" "Device Enabled" 8 0
  • Finally, run Google Earth.

You should now be able to pan, zoom and rotate via multi-touch gestures on your tablet's (or phone's) screen. (Yes, one more degree of freedom would be nice, but I haven't figured out a good way to do it yet.)

If you can't get this mess to work, I'm not the first one to do something like this, there's a Google Summer of Code project done by Reese Butler that works in a similar manner, but uses a slightly different control scheme. The Android part is on the Market and the computer part can be found here. Maybe you'll have more luck with that one.