4 June 2017

Making a bastard sword the hard way

 A few years back I got it into my mind that it would be neat to make a bastard sword from scratch. Well, not entirely from scratch; I had an old piece of spring steel I found at a museum (I think it might have originally been from a carriage that was disassembled and scrapped).

The project ended up being a lot of work and I learned a few lessons along the way.

I started by drawing some rough sketches and made a wooden version of the sword to get the sizing right.



Here is the wooden version made from some scrap I had lying around. This only took a couple of days to finish and was very useful in determining the shape I wanted the finished product top have.

The crossguard:


Blade tip:

 Entire blade:


Connecting the two:
I originally considered threading the end to secure the pommel. That's why the last couple inches are rounded.

 Entire thing:
Notice the broken tip? There is a reason swords are not made of wood...

After I was satisfied with the wooden version (I never bothered to make a pommel or grips for it), I started working on the blade for the metal version.

Unfortunately most automotive springs have a hole in the middle of them and my spring was no exception. So the first thing I did was weld it shut using a welding stick (nickel for flexibility). Notice the difference in colouring between the two metals:
Noticeable now, but barely visible later

Since the spring was not very close to the blade dimensions I wanted (too wide) I cut the edges off using an oxy/acetylene torch. If you are skilled with the torch you can make some very precise cuts with it.

Unfortunately I am not that skilled and ended up cutting off a bit too much at one point. This did not affect the shape of the blade (I had to grind it down anyway), but it did negatively affect the temper at a single point around 3/4 the way down the blade. However I only noticed this much later.

Kind of blurry, but this is the edge after torch cutting:

The resulting shape:
by this point I had done some extensive straightening on the spring using a sledgehammer and a hydraulic press

What ensued next was a lot of grinding with an angle grinder. Actually, two angle grinders since I burned out the motor of my first grinder along the way.

Unfortunately I don't have many pictures of this portion of the project, but suffice to say I severely underestimated the amount of time that was required to grind out the shape of the blade using a standard grinding disc.

This was due to the fact that I was grinding extremely tough spring spring as well as the difficulty in grinding a fuller in the middle of the blade to cut down on the weight.

I did eventually finish, but it probably took about 60 hours total.

It turns out that under all that rust was some shiny steel:
Pointed end with fuller
Next up was the crossguard.

I insisted on making this piece as well as the pommel out of stainless steel. Stainless steel can be somewhat difficult to work with, but luckily I had a mill to do most of the work.

Side View:
Stainless steel can be hard on cutters. Hence the cutting fluid to the right.
 Top View:

Close up:

Twins:
The metal version ended up being slightly larger than the wooden one.

Next up was the pommel. I picked a fairly complex hexagonal design for this piece, so to aid in the process I created a 3d model in Sketchup:
I added the diameter measurements to ensure I didn't remove too much stock on the lathe.
Turning this down on the lathe was the easy part. Although not necessary, it sped up the time on the mill later on.

On the lathe:

For scale:

Doing the geometry on the mill for this was tricky. I probably spent more time setting up the table than actually cutting the piece. It was also tricky to grab a cylinder shaped piece and I had to watch out for excessive vibration along the way.

Getting the table centered:

Mounting the piece:

Lots and lots of cutting:

All done:

In the end I was really pleased with how the pommel turned out. It was a very challenging design and unlike the blade I actually had to pay for the stock, so I only had one shot at it.

To get the proper square hole down the middle I was even able to cut it with an EDM machine! All it cost me was a case of beer...

The result:

Other side:

Now it was time to join everything together. For the crossguard I simply welded it directly to the blade.

 Here is the blade handle prior to welding
Few sword handles are this wide. I kind of went overboard on the design. Strong though.
 For the pommel, rather than welding I press fit it onto the end of the blade.

Heating it up with a torch:
Noticed the recessed area around the blade. This is where the material from the blade will collect upon hammering and hold the pommel in place.
Very ugly, but an extremely tight fit:

Looking much nicer, although still needs more polishing:

The other end:

Everything connected:

Now that all the hardware was connected, the only thing missing was a handle.

I ended up making this out of a piece of poplar wood I found in the yard.

Getting the rough shape on the lathe:
I don't have a wood lathe. This made a mess :(
After that I cut it in half and chipped out space in the middle using a small chisel:

Fitting it back together:

I then glued everything together using gorilla glue and some hose clamps:
The glue foamed up a bit, but I was able to sand it down after it had dried.
At this point I considered leaving the handle as a plain wooden handle. But in the end I decided to add a black leather grip over the top to improve handling.

Gluing on the leather:
I added some shellac to the wood before gluing on the leather. It was almost a shame to cover it.
Wrapped and waiting for the glue to dry:

After cutting the excess leather some final polishing, the result was a completed bastard sword!

Overall about 42" from top to bottom:

In hand:

Metal vs wood version:

Another view:

For the most part I am extremely happy with how project turned out. The result ended up matching my original vision, it didn't cost too much, and I had a lot of fun chopping up different things with it.

I am especially proud of the pommel, which is probably the most complex shape I have machined thus far.

Regarding the blade, in retrospect I would not have used an automotive spring as a starting material. Although barely visible, the original hole in the steel is a potential weak point. Spring steel is also very difficult to work with in its hardened state and I would not be willing to spend the same amount of time grinding another blade if I had to do it all over again.

I also ended up finding a point on the blade where the cutting torch heated up the metal too much, causing it to lose some of its temper. The result is that if the sword is bent too far in this position it will not snap 100% back to its original shape and must occasionally be re-straightened by hand.

I think in an ideal situation, all grinding and machining would be performed on a soft, annealed piece of high carbon steel. Then, when the correct shape was achieved, the blade could be heated and tempered to the desired hardness. It would also be nice to know the exact carbon content of the steel.

The downside is this process requires a rather large forge, high temperatures and a fair amount of experimentation to get the process down.

Maybe for the next sword?...








10 January 2016

Steering wheel controls for an aftermarket head unit in a '98 Buick LeSabre

Man, it's been a while since I posted. Been working on a few interesting projects, just haven't had the time to write them down. Nonetheless, here's one that turned out pretty good.

I recently purchased a new (to me) '98 Buick LeSabre LS, so I immediately began fixing all the random crap in it that bugged me. Luckily, this was the exact same model as my old car so I've gotten pretty good at working on them and have a ton of spare parts lying around.

Namely I had an aftermarket Pioneer DE-UHxxxx something or other head unit I wanted to put in because as we all know listening to the radio sucks. However, this time I wanted to keep the steering wheel controls functioning. Partly because I'm lazy but also because I've hit NEXT so many time on that radio I'm afraid that the button is wearing out!

In this case, there are 8 buttons on the steering wheel that run directly to the stock LeSabre radio and control VOL+, VOL-, SEEK+, SEEK-, TEMP+, TEMP-, SCAN+, SCAN-.

As seen in the diagram below, these commands are all sent to the radio over a single wire, which then interprets them based on the resistance of the connection. And in the case of TEMP+ and TEMP-, passes them along over a serial connection to the climate control unit.


All 8 switches are in parallel and the resistance progressively increases as you move from right to left. Power is sourced from power distribution cell 10 (12VDC), passes through several fuses, the steering wheel connections (note that the "Inflatable Restraint Steering Wheel Module Coils" are not really coils, but in fact rotary electrical connectors) then back and into the radio wiring harness via a light green wire. This is confirmed by the radio diagram which lists the purpose of each wire:



The one we're interested in is Pin E6 LT GRN which is listed as the Remote Control Signal. This can be further confirmed by checking the aftermarket wiring harness (where it dead ends as it isn't used for anything) with a multimeter. When these buttons are depressed, it should read a resistance between this wire and power (found going through a 2A fuse under the steering column) similar to the one above, depending on which button is pressed (they will differ slightly due to tolerances). When I tried this, I read the following values:


Button Resistance (Ω)
VOL+ 1.293k
VOL- 1.586k
TEMP+ 1.932k
TEMP- 2.409k
SEEK+ 3.131k
SEEK- 4.303k
SCAN+ 6.830k
SCAN- 13.790k

Meaning everything is working as expected.

But how does this translate into useful commands on the new Pioneer radio? Luckily, most aftermarket radios have a remote input that works similarly to the one in the stock LeSabre radio. It too, is capable of reading resistances and issuing commands based on those resistances. And luckily, these resistances have already been figured out here: http://jvde.net/node/7




Now, if you wanted to do a REALLY nice job, you could open up the steering wheel and swap out all those resistors. Or, like most people you could buy an interpreter (like this) and set it up to read the existing resistances and correlate them to the desired outputs. However, neither option was attractive to me. Opening the steering wheel is too much work. And the interpreter costs $50, takes up space, and introduces added complexity and potential lag into the controls. Therefore I chose option 3.

Option 3 is using the existing resistances in the circuit to issue commands to the radio. Now, the downside to this method is you will only get a limited range of commands, some will likely be duplicated, and they won't map to the correct buttons. But, since I mainly just wanted volume and track controls and only I will be using the car, none of that matters to me.

So, I went ahead and added a 7.5k resistor in series with the steering wheel controls like so:









This shifts the measured resistances to the following:


Button Resistance (Ω) Pioneer Command
VOL+ 8.793k SEEK+
VOL- 9.086k SEEK+
TEMP+ 9.432k SEEK-
TEMP- 9.909k SEEK-
SEEK+ 10.631k SEEK-
SEEK- 11.803k SEEK-
SCAN+ 14.33k VOL+
SCAN- 21.29k VOL-

Meaning that I was able to achieve all 4 of the commands I wanted, with minimal effort and 0 expense (assuming you have the resistors lying around).

Your mileage may vary depending on what resistances are used in your make and model and what commands you would like to keep.

After a few weeks of use I'm glad to say it works very reliably with almost no lag. I was even able to re-purpose the old 12VDC wire to power a dashcam, since it turns on whenever the ignition does. Score!


16 March 2014

Kiln Controller Update


After receiving some parts, I was finally able to make progress on my Kiln controller. Although my goal was to only use stuff I have lying around, I ended up ordering an AD595-AQ amplifier chip, some more durable K-Type thermocouple probes, as well as a socket to plug them into. I also bought a 220V outlet and plug. This was all pretty cheap except for the chip which was about $20, or $40 total since I bought two of them, since they are apparently easy to fry if you touch the compensation terminals when it's running.

The controller is divided into two parts, the low voltage sensor/processing board and the high voltage box:

Below is the box, which is made of plastic and a grounded steel faceplate. Inside is a high powered 4PST mechanical relay which is switched using 110AC through a much smaller 5V SPDT relay I salvaged from my sparkfun hobby kit. And also a very simple milled pcb with some connectors and soldering to keep everything in place. Unfortunately I forgot to take a picture of the interior before I closed everything up.

High Voltage Switching Box

Also from my sparkfun hobby kit is an Arduino Uno, a BJT, and a small breadboard. I can't remember where the LCD is from. I think I pulled it out of a stereo.

Shown below, the breadboard is pretty full with the 2-digit numeric LCD and amplifier circuitry taking up all the space. I ended up super-gluing the thermocouple socket to the plastic base plate since I ran out of room.

Low Voltage Amplifier and Control (Green LED = Relay, Red LED = Alarm)

The LCD displays the temperature reading (well, the two leading digits), the BJT toggles the relay and the AD595 amplifies the thermocouple voltage to ~10 mV/°C and provides an ice point reference.

Originally, I was hoping that the Arduino would have enough resolution to read the thermocouple voltage directly. However, this was not the case since even when the reference voltage was decreased to its lowest level of 1.1V (normally 5V) the best that the 10-bit DAQ can manage is reading millivolt changes. K-Type thermocouples have a sensitivity of ~41µV/°C and it was desired to read the temperature to within a couple of degrees.

Voltage reading from my thermocouple versus temperature suggest they are linear and indeed K-Type


Thus, the AD595 was selected to provide a gain of 247. It also has some other nifty features such as a failure alarm, which on my board outputs to the red LED and lights up when the thermocouple becomes disconnected.

One problem with the AD595 is that it's amplification is limited by the input voltage. With only 5V available from the Arduino the output was limited to 500°C. This was not sufficient for heat treating steel.

Luckily, by using the ~12VDC directly from the Arduino wall adapter I was able to increase the range to ~1000°C, which should be adequate. This required the addition of a voltage divider to the AD595 output, since the Arduino is also limited to readings of 5VDC or less. It also meant that it could no longer solely be run from USB, but that wasn't really a problem since it will only be used in the shop anyway.

Closeup of the faceplate
Closeup of the board

A relay can only be on or off and this limits the control somewhat. Nevertheless, I decided to add PID control using this library. This really was overkill, at least until I get a voltage regulator or even a SSR to reduce the switching noise. The small relay just makes a click, but the bigger one you can definitely hear across the room.

But it worked! With a 100°C set point I was able to keep the temperature within a range of about ±10°C. Without much tuning it was kind of jittery, but I think this can be improved with better Kp, Kd, and Ki values or by turning of one or two of the kiln elements. However I believe I am at a point where the performance is good enough to run an actual heat treatment cycle. Which in and itself is a whole new challenge...

Since it's kind hard to discern my circuit from the mess of wires above, I figure I should provide some kind of a reference. Apart from the added LCD and BJT switch, my board implements pretty much the exact same circuit found here as well that shown in the AD595 datasheet.

The LCD is very straightforward and uses 7 pins to set the digit from 0-9 and 2 more pins to select which digit to display. It then toggles back and forth forever to give the appearance of displaying two digits simultaneously.

I've also included my Arduino code below, which as of March 2014 is not yet configured to run any kind of heat treatment cycle. It can however read the temperature, display it on the LCD, switch the relay, and maintain a setpoint temperature. The display magnitude (*1, *10, or *100) can be determined from the behaviour of the Arduino's built-in LED on Pin 13.

Although I've had to put my kiln project on hold for a while due to moving away from my shop for work, I hope you've enjoyed this brief update!



#include <PID_v1.h>

//   1--------    2--------
//   |   A   |    |   A   |
//  F|       |B  F|       |B
//   |---G---|    |---G---|
//  E|       |C  E|       |C
//   |   D   |    |   D   |
//   ---------    ---------
//   |  |  |  |  |  |  |  |  |  |                      -> pins and segments they control
// CA1 CA2 G  F  E  D  C  B  A  Decimel (not used)

//pinout
const int A = 2;
const int B = 3;
const int C = 4;
const int D = 5;
const int E = 6;
const int F = 7;
const int G = 8;

const int CA1 = 9;
const int CA2 = 10;

const int RELAY = 12;

//Define Variables we'll be connecting to
double Setpoint, Input, Output;
//Specify the links and initial tuning parameters; PID(&Input, &Output, &Setpoint, Kp, Ki, Kd, Direction)
PID myPID(&Input, &Output, &Setpoint,200,50,0, DIRECT);
int WindowSize = 5000;
unsigned long windowStartTime;


//used to manage display flicker
//ideally replace with milli counter values ************************************
int count = 0;

//Used for 2-digit display
int char1, char2;
boolean flip = true;

//arefvolts multiplier based on DEFAULT analog reference setting below
float arefVolts = 5;
//Amplification derived from AD595 datasheet; 247.3 (10 mV/°C divided by 40.44 uV/°C).
//Therefore, each degree C increase results in a 0.01V increase, requring a 100 multiplier to go from voltage to temperature
//Doubled to 200 to account for voltage divider; increases theoretical maximum to 1000°C
float multiplier = 200;
// factor to tune
float alpha = 0.1;
//Store value from pin vbetween 0 and 1023
int analog0 =0;
//store estimated pin voltage and temperature values using supplied constants
float volts, temperature1, temperature2=0;
//store fixed temperature value for display
int temp;
//Use to show magnitude
//off = less than 100
//on = greater than 99, less than 1000
//blink = greater than 1000
int led = 13;
//Keep track of time elapsed from program initialization
unsigned long milliseconds, minutes;

// the setup routine runs once when you press reset:
void setup() {
  
  //Setpoint set for testing purposes at 100
  Setpoint = 100;
  //tell the PID to range between 0 and the full window size
  myPID.SetOutputLimits(0, WindowSize);
  //turn the PID on
  myPID.SetMode(AUTOMATIC);
  windowStartTime = millis();
  
  
  // initialize pins
  pinMode(led, OUTPUT);
  //set the reference pin voltage to default, allows readings of up to 5V in 4.88mV increments in 1024 resolution
  analogReference(DEFAULT);
  
  //Temporary serial, for debugging
  Serial.begin(9600);          //  setup serial
  
  //Initialize pins
  pinMode(A, OUTPUT);
  pinMode(B, OUTPUT);
  pinMode(C, OUTPUT);
  pinMode(D, OUTPUT);
  pinMode(E, OUTPUT);
  pinMode(F, OUTPUT);
  pinMode(G, OUTPUT);
  pinMode(CA1, OUTPUT);
  pinMode(CA2, OUTPUT);
  pinMode(RELAY, OUTPUT);

}

// the loop routine runs over and over again forever:
void loop() {
  
  analog0=analogRead(0);
  //Get input voltage
  volts=(analog0/1023.0)*arefVolts;
  //Convert to estimated temperature
  temperature2=volts*multiplier;
  //Average old temperature with new to prevent jitter
  temperature1= alpha*temperature2 + (1-alpha)*temperature1;
  //Display
  display(temp);
  
  
  
  //Change status led to indicate magnitude of temperature display
  if(temperature1>99&&temperature1<1000){
    digitalWrite(led, HIGH);
  }else if(temperature1<1000) {
    digitalWrite(led, LOW);  
  }else{
    if(count>400){
      digitalWrite(led, HIGH);
    }else{
      digitalWrite(led, LOW);
    }
  }


  delay(1);
  count++;
    if(count>400){
      //Format for display
      temp=truncate(temperature1);
      // read the temp sensor on analog pin 0
      Serial.println(Output);
      count=0; 
    }
    
    milliseconds = millis();
    minutes = milliseconds/60000;


//    Tests Relay pin by toggling every minute    
//    if((minutes%2)==0){
//      digitalWrite(RELAY, LOW);
//    }else{
//      digitalWrite(RELAY, HIGH);
//    }
    
    
    
  Input = temperature1;
  myPID.Compute();
  /************************************************
   * turn the output pin on/off based on pid output
   ************************************************/
  unsigned long now = millis();
  if(now - windowStartTime>WindowSize){ //time to shift the Relay Window
    windowStartTime += WindowSize;
  }
  
  if(Output > now - windowStartTime){
    digitalWrite(RELAY,HIGH);
  }
  else{
    digitalWrite(RELAY,LOW);
  }
    
    
    
}

void display(int number){
  char1 = number/10;
  char2 = number%10;
  
  if(flip==true){
    digitalWrite(CA1, HIGH);
    digitalWrite(CA2, LOW);
    light(char1);
    flip=false;
  }else if(flip==false){
    digitalWrite(CA1, LOW);
    digitalWrite(CA2, HIGH);
    light(char2);
    flip=true;
  }  
}

void light(int character){
  
  if(character==0){
    
    digitalWrite(A, LOW);
    digitalWrite(B, LOW);
    digitalWrite(C, LOW);
    digitalWrite(D, LOW);
    digitalWrite(E, LOW);
    digitalWrite(F, LOW);
    digitalWrite(G, HIGH);
  
  }else if(character==1){
      
    digitalWrite(A, HIGH);
    digitalWrite(B, LOW);
    digitalWrite(C, LOW);
    digitalWrite(D, HIGH);
    digitalWrite(E, HIGH);
    digitalWrite(F, HIGH);
    digitalWrite(G, HIGH);
  
  }else if(character==2){
 
    digitalWrite(A, LOW);
    digitalWrite(B, LOW);
    digitalWrite(C, HIGH);
    digitalWrite(D, LOW);
    digitalWrite(E, LOW);
    digitalWrite(F, HIGH);
    digitalWrite(G, LOW);
    
  }else if(character==3){

    digitalWrite(A, LOW);
    digitalWrite(B, LOW);
    digitalWrite(C, LOW);
    digitalWrite(D, LOW);
    digitalWrite(E, HIGH);
    digitalWrite(F, HIGH);
    digitalWrite(G, LOW);
    
  }else if(character==4){
        
    digitalWrite(A, HIGH);
    digitalWrite(B, LOW);
    digitalWrite(C, LOW);
    digitalWrite(D, HIGH);
    digitalWrite(E, HIGH);
    digitalWrite(F, LOW);
    digitalWrite(G, LOW);
    
  }else if(character==5){

    digitalWrite(A, LOW);
    digitalWrite(B, HIGH);
    digitalWrite(C, LOW);
    digitalWrite(D, LOW);
    digitalWrite(E, HIGH);
    digitalWrite(F, LOW);
    digitalWrite(G, LOW);
    
  }else if(character==6){

    digitalWrite(A, LOW);
    digitalWrite(B, HIGH);
    digitalWrite(C, LOW);
    digitalWrite(D, LOW);
    digitalWrite(E, LOW);
    digitalWrite(F, LOW);
    digitalWrite(G, LOW);
    
  }else if(character==7){

    digitalWrite(A, LOW);
    digitalWrite(B, LOW);
    digitalWrite(C, LOW);
    digitalWrite(D, HIGH);
    digitalWrite(E, HIGH);
    digitalWrite(F, HIGH);
    digitalWrite(G, HIGH);
    
  }else if(character==8){

    digitalWrite(A, LOW);
    digitalWrite(B, LOW);
    digitalWrite(C, LOW);
    digitalWrite(D, LOW);
    digitalWrite(E, LOW);
    digitalWrite(F, LOW);
    digitalWrite(G, LOW);
    
  }else if(character==9){

    digitalWrite(A, LOW);
    digitalWrite(B, LOW);
    digitalWrite(C, LOW);
    digitalWrite(D, HIGH);
    digitalWrite(E, HIGH);
    digitalWrite(F, LOW);
    digitalWrite(G, LOW);  
  }
}

int truncate(float temperature){
  
  int temp = temperature;
  
  if(temperature>99){
    for(int i=0; temp > 999; i++){
      temp = temp/10;
    }
      temp = temp/10;
  }
  return temp;
}