Well this took me several hours to figure out: chrome will only let you have one download in progress from the same URL at the same time. The second attempt will just hang until the first one is done.
I tried changing the Content-Disposition filename= value at the server side (so that each download gets a different filename), but that doesn't help. But if I ask for http://localhost/foo and http://localhost/bar, it works. (I can also get two downloads at the same time if I do one of them in an incognito window).
Firefox doesn't seem to have this limitation.
Tuesday, January 21, 2014
Sunday, January 19, 2014
Raspberry Pi GPIO pins to stepper controller
I picked up a 3-axis beefy NEMA-23 stepper kit from ebay for around $240. It comes with a Longs Motor DM542A stepper controller, which seems to be more or less identical to a lot of other brands.

The kit came with a board that takes commands from a PC parallel port (driven by eg., linuxcnc), and apparently the timing is such that USB-parallel adapters don't work well; you need a hardware parallel port.
I wasn't particularly excited to track down a machine old enough to have a parallel port and lug it around with my project, so I looked into whether the GPIO pins on my Raspberry Pi would be suitable to drive the DIR (direction) and PUL (pulse / step) pins directly. I found some general discussion, but not much that was concrete.

I think I originally picked up NOOBS to put on the SD card, but it's been a while and I don't remember exactly. But it came up with a menu and I picked the recommended option of Raspbian wheezy, which it downloaded and installed. Installation was a breeze, and the machine has been working great for me. (I'm writing this post on it, even, although it's pretty laggy if I try to open multiple tabs in the browser).
Most of the skepticism I saw about using the GPIO pins centered around the need for an RTOS to ensure that the process toggling the pulse line can do so at the required intervals without getting held up for extra milliseconds. When I ran "uname -a", I noticed "PREEMPT", which means that it already has some (but perhaps not the most extreme variety?) kernel patches for hard timing. Awesome!
Voltages were another concern: the stepper driver wants 5v logic inputs, but the raspi runs at 3.3v. Fortunately, this doesn't seem to be a problem either; the driver board seems perfectly happy with 3.3v input.
At first I though my driver wasn't working right when I wired it up -- I got no power light. But it turns out the ENBL line needs to be pulled down rather than up for the board to work.
I also found that the board doesn't seem to have the - side of each input tied together, so I had to wire up the ENBL-, DIR- and PUL- inputs all to ground.
I looked over the pinout for P1 on the raspi to figure out which GPIO lines to use, and didn't find any major reasons to use any particular ones; seems like almost all of them have alternate uses that I mostly don't think I'll need. So I used pins 1, 3, 5, 7 and 9, corresponding to +3.3v, GPIO-0, GPIO-1, GPIO-4 and GND on my rev. 1 board.
My first stab at controlling the stepper used the python example code. Note that this code uses board pin numbers rather than the GPIO numbering:
#!/usr/bin/python
import RPi.GPIO as GPIO
import time
# use P1 header pin numbering convention
GPIO.setmode(GPIO.BOARD)
# Set up the GPIO channels - one input and one output
GPIO.setup(3, GPIO.OUT)
GPIO.setup(5, GPIO.OUT)
GPIO.setup(7, GPIO.OUT)
GPIO.output(3, GPIO.HIGH)
while True:
GPIO.output(5, GPIO.HIGH)
time.sleep(0.001)
GPIO.output(5, GPIO.LOW)
time.sleep(0.001)
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <sched.h>
#include <sys/mman.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
The kit came with a board that takes commands from a PC parallel port (driven by eg., linuxcnc), and apparently the timing is such that USB-parallel adapters don't work well; you need a hardware parallel port.
I wasn't particularly excited to track down a machine old enough to have a parallel port and lug it around with my project, so I looked into whether the GPIO pins on my Raspberry Pi would be suitable to drive the DIR (direction) and PUL (pulse / step) pins directly. I found some general discussion, but not much that was concrete.
I think I originally picked up NOOBS to put on the SD card, but it's been a while and I don't remember exactly. But it came up with a menu and I picked the recommended option of Raspbian wheezy, which it downloaded and installed. Installation was a breeze, and the machine has been working great for me. (I'm writing this post on it, even, although it's pretty laggy if I try to open multiple tabs in the browser).
Most of the skepticism I saw about using the GPIO pins centered around the need for an RTOS to ensure that the process toggling the pulse line can do so at the required intervals without getting held up for extra milliseconds. When I ran "uname -a", I noticed "PREEMPT", which means that it already has some (but perhaps not the most extreme variety?) kernel patches for hard timing. Awesome!
Voltages were another concern: the stepper driver wants 5v logic inputs, but the raspi runs at 3.3v. Fortunately, this doesn't seem to be a problem either; the driver board seems perfectly happy with 3.3v input.
At first I though my driver wasn't working right when I wired it up -- I got no power light. But it turns out the ENBL line needs to be pulled down rather than up for the board to work.
I also found that the board doesn't seem to have the - side of each input tied together, so I had to wire up the ENBL-, DIR- and PUL- inputs all to ground.
I looked over the pinout for P1 on the raspi to figure out which GPIO lines to use, and didn't find any major reasons to use any particular ones; seems like almost all of them have alternate uses that I mostly don't think I'll need. So I used pins 1, 3, 5, 7 and 9, corresponding to +3.3v, GPIO-0, GPIO-1, GPIO-4 and GND on my rev. 1 board.
My first stab at controlling the stepper used the python example code. Note that this code uses board pin numbers rather than the GPIO numbering:
#!/usr/bin/python
import RPi.GPIO as GPIO
import time
# use P1 header pin numbering convention
GPIO.setmode(GPIO.BOARD)
# Set up the GPIO channels - one input and one output
GPIO.setup(3, GPIO.OUT)
GPIO.setup(5, GPIO.OUT)
GPIO.setup(7, GPIO.OUT)
GPIO.output(3, GPIO.HIGH)
while True:
GPIO.output(5, GPIO.HIGH)
time.sleep(0.001)
GPIO.output(5, GPIO.LOW)
time.sleep(0.001)
This worked just fine, although as expected, it'd glitch every few seconds, audible as a stuttering sound in the stepper. Glitching got worse when I loaded down the system by doing things like loading web pages.
Next I tried the C example code to see if it'd do better. It might have been somewhat better, but still had noticeable glitching.
I found excellent wiki page with example code for using the RTOS patches, and mashed it up with the GPIO example code, and it works great!
So it looks like the principle is sound. The remaining task is to get it integrated with some sort of g-code interpreter (update: I ported grbl to raspi), at which point we'll have a $35 CNC controller with HDMI output that can drive step/direction pins on stepper controllers directly, without having to use parallel ports and adapter boards.
// Compile with:
// gcc -o rt_gpio rt_gpio.c -lrt
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <sched.h>
#include <sys/mman.h>
#include <string.h>
// defines for using the realtime kernel
#define MY_PRIORITY (49) /* we use 49 as the PRREMPT_RT use 50
as the priority of kernel tasklets
and interrupt handler by default */
#define MAX_SAFE_STACK (8*1024) /* The maximum stack size which is
guaranteed safe to access without
faulting */
#define NSEC_PER_SEC (1000000000) /* The number of nsecs per sec. */
// defines for talking to the gpio pins
// Access from ARM Running Linux
#define BCM2708_PERI_BASE 0x20000000
#define GPIO_BASE (BCM2708_PERI_BASE + 0x200000) /* GPIO controll
er */
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#define PAGE_SIZE (4*1024)
#define BLOCK_SIZE (4*1024)
int mem_fd;
void *gpio_map;
// I/O access
volatile unsigned *gpio;
// GPIO setup macros. Always use INP_GPIO(x) before using OUT_GPIO(x) or SET_GPIO_ALT(x,y)
#define INP_GPIO(g) *(gpio+((g)/10)) &= ~(7<<(((g)%10)*3))
#define OUT_GPIO(g) *(gpio+((g)/10)) |= (1<<(((g)%10)*3))
#define SET_GPIO_ALT(g,a) *(gpio+(((g)/10))) |= (((a)<=3?(a)+4:(a)==4?3:2)<<(((g)%10)*3))
#define INP_GPIO(g) *(gpio+((g)/10)) &= ~(7<<(((g)%10)*3))
#define OUT_GPIO(g) *(gpio+((g)/10)) |= (1<<(((g)%10)*3))
#define SET_GPIO_ALT(g,a) *(gpio+(((g)/10))) |= (((a)<=3?(a)+4:(a)==4?3:2)<<(((g)%10)*3))
#define GPIO_SET *(gpio+7) // sets bits which are 1 ignores bits which are 0
#define GPIO_CLR *(gpio+10) // clears bits which are 1 ignores bits which are 0
void setup_io();
void stack_prefault(void) {
unsigned char dummy[MAX_SAFE_STACK];
memset(dummy, 0, MAX_SAFE_STACK);
return;
}
int main(int argc, char* argv[])
{
struct timespec t;
struct sched_param param;
int interval = 1000000; // ns
/* Declare ourself as a real time task */
param.sched_priority = MY_PRIORITY;
if(sched_setscheduler(0, SCHED_FIFO, ¶m) == -1) {
perror("sched_setscheduler failed");
exit(-1);
}
/* Lock memory */
if(mlockall(MCL_CURRENT|MCL_FUTURE) == -1) {
perror("mlockall failed");
exit(-2);
}
/* Pre-fault our stack */
stack_prefault();
clock_gettime(CLOCK_MONOTONIC ,&t);
/* start after one second */
t.tv_sec++;
int g,rep;
// Set up gpi pointer for direct register access
setup_io();
/************************************************************************\
* You are about to change the GPIO settings of your computer. *
* Mess this up and it will stop working! *
* It might be a good idea to 'sync' before running this program *
* so at least you still have your code changes written to the SD-card! *
\************************************************************************/
#define DIR (0)
#define STEP (1)
INP_GPIO(DIR); // must use INP_GPIO before we can use OUT_GPIO
OUT_GPIO(DIR);
INP_GPIO(STEP);
OUT_GPIO(STEP);
GPIO_SET = 1 << DIR;
int state = 0;
while(1) {
/* wait until next shot */
clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &t, NULL);
/* do the stuff */
if (state) {
GPIO_SET = 1 << STEP;
} else {
GPIO_CLR = 1 << STEP;
}
state = !state;
/* calculate next shot */
t.tv_nsec += interval;
while (t.tv_nsec >= NSEC_PER_SEC) {
t.tv_nsec -= NSEC_PER_SEC;
t.tv_sec++;
}
}
}
//
// Set up a memory regions to access GPIO
//
void setup_io()
{
/* open /dev/mem */
if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0) {
printf("can't open /dev/mem \n");
exit(-1);
}
/* mmap GPIO */
gpio_map = mmap(
NULL, //Any adddress in our space will do
BLOCK_SIZE, //Map length
PROT_READ|PROT_WRITE,// Enable reading & writing to mapped memory
MAP_SHARED, //Shared with other processes
mem_fd, //File to map
GPIO_BASE //Offset to GPIO peripheral
);
close(mem_fd); //No need to keep mem_fd open after mmap
if (gpio_map == MAP_FAILED) {
printf("mmap error %d\n", (int)gpio_map);//errno also set!
exit(-1);
}
// Always use volatile pointer!
gpio = (volatile unsigned *)gpio_map;
} // setup_io
Thursday, January 16, 2014
Read text format protobuf from file in Java
java.io.InputStream inputStream = [open file and get input stream]
java.io.InputStreamReader reader = new java.io.InputStreamReader(inputStream);
MyProto.Builder myProtoBuilder = myProto.newBuilder();
TextFormat.merge(reader, myProtoBuilder);
Wednesday, October 02, 2013
Sagulator
This is a really handy tool to figure out how much deflection to plan for when building wood structures:
http://www.woodbin.com/calcs/sagulator.htm
Plywood seems to do about as well as solid wood, and MDF is about 3x worse than plywood for deflection.
http://www.woodbin.com/calcs/sagulator.htm
Plywood seems to do about as well as solid wood, and MDF is about 3x worse than plywood for deflection.
Sunday, September 01, 2013
Water heater burner only runs for a second
If you're lighting a water heater and the pilot lights fine, but when the burner engages, you only get a brief puff of gas, check the gas shutoff valve for the house. Sometimes they leak, so that gas builds up in the lines. The leak is enough to keep the pilot lit, and the built up pressure lets the burner run for a second or two, but that's all. Sometimes the shutoff valve will stick a bit as well, so that it's still closed even though it moved somewhat.
(If that's the case for you, you should probably also replace your shutoff valve!)
Sunday, July 07, 2013
Flour smells like soap
Recently a batch of bread I made had an aftertaste like soap. Then the next day my wife made pizza dough from the same flour and yeast, and it had the same effect.
Searching online, I read about lactic bacteria contaminating bread starters, particularly if they're too wet. But today when I went to make another batch of bread, I noticed that the flour had the same smell.
So it looks the flour somehow got contaminated, although I don't see anything else about it online.
Searching online, I read about lactic bacteria contaminating bread starters, particularly if they're too wet. But today when I went to make another batch of bread, I noticed that the flour had the same smell.
So it looks the flour somehow got contaminated, although I don't see anything else about it online.
Thursday, June 27, 2013
Sketchup 2013 with wine in linux
Tried to install Sketchup 2013 on Ubuntu Lucid, and it kept complaining about needing to install the Windows Imaging Component.
Downloaded it: http://download.microsoft.com/download/f/f/1/ff178bb1-da91-48ed-89e5-478a99387d4f/wic_x86_enu.exe 53c18652ac2f8a51303deb48a1b7abbdb1db427f
But it claimed a newer version was already installed. From here I gleaned that I needed to move system32/windowscodecs.dll out of the way first: http://winetricks.googlecode.com/svn/trunk/src/winetricks
Then I was able to install WIC and then Sketchup.
Downloaded it: http://download.microsoft.com/download/f/f/1/ff178bb1-da91-48ed-89e5-478a99387d4f/wic_x86_enu.exe 53c18652ac2f8a51303deb48a1b7abbdb1db427f
But it claimed a newer version was already installed. From here I gleaned that I needed to move system32/windowscodecs.dll out of the way first: http://winetricks.googlecode.com/svn/trunk/src/winetricks
Then I was able to install WIC and then Sketchup.
Subscribe to:
Posts (Atom)