Scratchbuilding a turntable

Affiliate Disclosure: We may receive a commision from some of the links and ads shown on this website (Learn More Here)


Welcome to your Virtual Model Railroad Club on the web. Want join in the convesations?

Register for your free membership today!



ikallio1

Member
Scratchbuilding a turntable: Indexing, part 1

Disclaimer

This is a construction journal, not a plan to be followed! If you are inspired
to build something after reading these articles, do so at your own risk. Take
the necessary precautions for safety. Working with powertools and electricity
is dangerous.


Indexing the turntable, part 1

As mentioned in the design, the indexing is based on a set of positioning
vanes attached to the positioning disk. The vanes pass between an IR
emitter (IR LED) and a pair of IR detectors (phototransistors). The first
picture shows what I found for this project. I found the phototransistors
at a local Fry's and the IR LED was in my junkbox from an earlier
experiment.
sensors.jpg


I made a PCB for the sensor board using the laser printer toner transfer
method. This method is described in many places on the
internet, see <http://www.riccibitti.com/pcb/pcb.htm> for an example. The
hardest part of the method seems to be finding suitable paper that
will release the toner easily. I used some inkjet photo paper from
Costco, but it was too high quality. It has some sort of polymer
coating which didn't come off the PCB very easily with water soaking. One
guy recommends using shiny newsprint - doesn't seem to matter if it's
already got some printing ink on it. I haven't tried it yet, but I did start
collecting nice white pieces of it whenever I run across them (older Apple
iPod and other i* ads seem to have a lot of white :)

My result with the toner transfer was a bit ugly so I had to patch the
toner with some nail polish before the soak in ferric chloride. The second
picture shows the end result. It looked and worked OK. Then I soldered
the components onto it and attached a piece of ribbon cable scavenged
from an old ATA hard drive cable. An old shelving bracket made a nice
mounting bracket (note to self: always check pieces of metal like this
for hardness before scavenging: I think I destroyed a nice metal drill bit
making the mounting holes, this bracket was made of very hard steel).
sensorPCB.jpg


The 3rd picture shows the whole positioning system assembled and mounted
on the turntable and positioning disk. (Note the corrosion on the vanes - it
happened overnight after I mounted the test vanes and forgot to clean off
the flux residue). I followed Wayne Rodericks advice and made a whole
stack of those vanes at a time. Mine didn't turn out completely uniform
unfortunately - I'm not much of a metal worker. But they seem to work just
fine.
positioning_system.jpg


You might laugh when you hear where the metal for those vanes came
from :) I couldn't find suitable sheet metal in my junk box and didn't feel like
driving to the HW store. I got an idea and headed for the pantry, where I
examined all the canned foods. Most cans have ribbed sides but a can of
coconut milk had nice smooth sides. I suddenly developed a craving for some
nice Thai green curry! A short while later I had the stack of rough cut vanes
you see in the last picture and a nice meal :)
positioning_vanes1.jpg


Continued in part 2

Cheers,
ik
 
Last edited:

ikallio1

Member
Scratchbuilding a turntable: Indexing, part 2

Disclaimer

This is a construction journal, not a plan to be followed! If you are inspired
to build something after reading these articles, do so at your own risk. Take
the necessary precautions for safety. Working with powertools and electricity
is dangerous.


Indexing the turntable, part 2

When I started experimenting with the setup described in part 1, I was
very disappointed to notice that the vane shadows falling on the
sensors were so sharp that I was unable to locate the centerpoint
location between the sensors. After a bit of headscratching I
reasoned that this must be caused by the light source being too
close to a mathematical point. The PN junction in this IR LED
must be physically very small, hence the light is practically a point
source. I needed something much more diffuse.

I had some slightly opaque plastic that might be able to diffuse
the IR light sufficiently. I cut a small piece and started thinking
about how to mount it in front of the IR LED. I looked around and
noticed that the eraser cover in my mechanical pencil is almost the
same size as the LED. I tried it and voila, it fit snugly on the
IR LED.

I cut a small cylinder from the cover and glued the piece of plastic
to one end. The whole thing then slipped nicely over the IR LED. After
firing up my sensor measurement program for the Arduino, I realized that
I needed to increase the intensity of the IR LED, so I decreased its
resistor to 470 ohms. Now the signal shapes from the sensors (in response
to the vane shadows) were perfect!

The first picture shows the sensor board with the makeshift light
diffuser in place.
sensor_board.jpg


Positioning vanes

The second picture shows the positioning disk with all the vanes attached.
You can also see the split ring PCB board which will be used to deliver power
to the bridge tracks. I made that with a soak in ferric chloride as well, this
time I didn't need any complicated circuitry on it so I just used clear packing
tape to protect the parts of the copper cladding that I didn't want dissolved.
The split ring PCB is epoxied onto the positioning disk.
positioning_disk.jpg


The screws I ended up using for the pivot point of the vanes are a bit on the
large side. I couldn't find smaller ones easily, but they seem to work OK
anyway. After playing with the 3 test vanes earlier, I realized that having
only a small tiny blob of solder between the vane and the inlaid PCB is best.
Having solder in the whole area between the vane and PCB made any
adjustments very hard. I suppose a larger soldering iron might compensate.
This is another reason why going with Wayne's original idea would have been
better.

I made another goof with the positioning disk. I had originally numbered the
vane positions clockwise. Then late one night I realized that I was looking at
the underside of the positioning disk - therefore the vanes should have been
numbered counterclockwise! My approach tracks were numbered clockwise of
course. I thought I was so lucky catching this gaffe before mounting all the
vanes. WRONG.

After mounting all the vanes with the "corrected" order, I couldn't believe it
when I started playing with the table and noticed where the bridge was
stopping. The wider gaps (for the garden tracks) where in the clockwise
direction from the 6 degree gaps (roundhouse tracks). What went wrong? It
took me a while to notice that the positioning vanes have to go the other
way because the sensor board is stationary, and the vanes are rotating! I
was cursing my "cleverness" as I spent couple of hours moving the vanes :-/

Positioning guide

To aid in fine-tuning the indexing system I mounted a positioning guide to the
bottom of the pit. I made it out of a piece of clear plastic. I scribed a line
with a box knife on the back side of the plastic and attached it with duct
tape. See picture 3. This allowed me to actually see how precisely
repeatable the positioning was (it wasn't very repeatable to begin with!).
positioning_guide.jpg


Next entry will describe the control software.

Cheers,
ik
 
Last edited:

ikallio1

Member
Scratchbuilding a turntable: Indexing, part 3

Disclaimer

This is a construction journal, not a plan to be followed! If you are inspired
to build something after reading these articles, do so at your own risk. Take
the necessary precautions for safety. Working with powertools and electricity
is dangerous.



Control software

Here's the fun part:
Code:
/*

Turntable control
=================

Physical inputs:
- Potentiometer for user to request turning direction
   and speed
- Analog inputs from two phototransistors (used to determine
   location of the positioning vanes)

Physical outputs:
- 2 wires to send PWM pulses to a DC motor
 
System description:
- Turntable bridge has a positioning disk mounted rigidly
   on the same axle. Positioning disk is under the layout.
   Positioning vanes mounted on the positioning disk are
   used to accurately stop the turntable at the correct
   location for the approach tracks on the layout. DC motor
   drive wheel bears on the positioning disk to turn the
   turntable bridge.

Functional description:
- The control panel has a single potentiometer. The user
   rotates it in the direction, (CW or CCW), that he wants
   the bridge to rotate. This makes the bridge rotate at its
   standard RUN speed in the chosen direction. When the user
   returns the potentiometer to its center position, the
   bridge decelerates to APPROACH speed and continues to
   the next track. As it nears the track, The bridge decelerates
   to HUNT speed and zeroes in to place.
- APPROACH mode ends when the leading edge phototransistor
   is occluded
- HUNT mode ends when the light falling on the phototransistors
   is balanced. System enters STOP mode
- Speed changes are never abrupt, the control software gently
   accelerates/decelerates transition between RUN, APPROACH
   and HUNT speeds
- A really fast turn speed called LUDICROUS speed is used
   when the potentiometer is turned all the way to the
   extreme CW or CCW position

*/

const int Motor1 = 11;      // PWM output pin to drive motor CW
const int Motor2 = 10;      // PWM output pin to drive motor CCW
const int PotPin = 0;       // Analog input pin that the potentiometer is attached to
const int PTCW = 1;         // Analog input pin for clockwise phototransistor
const int PTCCW = 2;        // Analog input pin for counterclockwise phototransistor
int PotValue = 0;           // value read from the pot
int MotorSpeed = 0;         // Current speed value output to the PWM (analog out) to drive the DC motor
int TargetSpeed = 0;        // Target speed is used when accelerating and decelerating
int PhotoValue = 0;         // value read from Phototransistor
int PhotoValueCCW = 0;      // value read from the counterclockwise Phototransistor

#define STOP                    0       // Bridge is stopped
#define RUN                     1       // Bridge is turning at normal speed
#define LUDICROUS               2       // Bridge is turning at ludicrous speed
#define APPROACH                3       // slow down and start looking for positioning vane
#define HUNT                    4       // Positioning vane detected, move slowly until light input balanced

int Mode = STOP;

#define CW                      0       // Clockwise direction
#define CCW                     1       // Counter-clockwise direction

int TargetDirection = CW;       // Target direction is used when decelerating and accelerating
int Direction = CW;             // Current direction of rotation
char *DirectionText[] = {
  "CW ",
  "CCW "
};
 
// Below are the potentiometer treshold values used to enter the different operating modes

#define CW_TRESHOLD             750
#define CW_TRESHOLD_LUDICROUS   900
#define CCW_TRESHOLD            350
#define CCW_TRESHOLD_LUDICROUS  100

#define APPROACH_TRESHOLD_LOW   330
#define APPROACH_TRESHOLD_HIGH  730

// Below are the PWM output values for setting different speeds

#define RUN_SPEED               48
#define LUDICROUS_SPEED         125
#define APPROACH_SPEED          42
#define HUNT_SPEED              38
#define MINIMUM_SPEED           35              // motor stalls at this voltage, no point in spending time decelerating from or accelerating to this value
#define STANDARD_ACCELERATION   1

// Below are the treshold values from the phototransistors used to determine mode changes

#define HUNT_TRESHOLD           800
#define BALANCE_TRESHOLD         50
#define FINE_BALANCE_LIMIT       10

void setup() {

  // Make sure motor is stopped to begin with
  analogWrite(Motor1, 0);
  analogWrite(Motor2, 0);
}

/*

Main Control Loop
=================

*/

void loop() {


  // read the user input (CW/CCW) potentiometer
  PotValue = analogRead(PotPin);           

  // if CW requested, then go to RUN mode in the CW direction
  if (PotValue > CW_TRESHOLD)
  {
    TargetDirection = CW;
    Mode = RUN;
    if (PotValue > CW_TRESHOLD_LUDICROUS)
      Mode = LUDICROUS;
  }
  // else if CCW, then go to RUN mode in the CCW direction
  else if (PotValue < CCW_TRESHOLD)
  {
    TargetDirection = CCW;
    Mode = RUN; 
    if (PotValue < CCW_TRESHOLD_LUDICROUS)
      Mode = LUDICROUS;
  }

  // do all the mode-specific stuff
 
  switch (Mode) {
   
    case STOP:
      TargetSpeed = 0;
      break;
     
    case RUN:
      TargetSpeed = RUN_SPEED;

      // if potentiometer returned to middle, then go to APPROACH mode
      if (PotValue >= APPROACH_TRESHOLD_LOW && PotValue <= APPROACH_TRESHOLD_HIGH)
      {
        Mode = APPROACH;
        TargetSpeed = APPROACH_SPEED;
      }
      break;

    case LUDICROUS:
      TargetSpeed = LUDICROUS_SPEED;

      // if potentiometer returned to middle, then go to APPROACH mode
      if (PotValue >= APPROACH_TRESHOLD_LOW && PotValue <= APPROACH_TRESHOLD_HIGH)
      {
        Mode = APPROACH;
        TargetSpeed = APPROACH_SPEED;
      }
      break;
     
    case APPROACH:
      // wait until approach speed and direction have stabilized
      if (Direction == TargetDirection && MotorSpeed == TargetSpeed)
      {
        // read the leading edge phototransistor
        if (Direction == CW)
        {
          PhotoValue = analogRead(PTCW);
        }
        else
        {
          PhotoValue = analogRead(PTCCW);
        }

        // if occluded, then go to HUNT mode
        if (PhotoValue > HUNT_TRESHOLD)
        {
          Mode = HUNT;
          TargetSpeed = HUNT_SPEED;
        }
      }
      break;
     
    case HUNT:
      // read phototransistors
      PhotoValue = analogRead(PTCW);
      PhotoValueCCW = analogRead(PTCCW);
     
      // if values close enough, then go to STOP mode
      if (abs(PhotoValue-PhotoValueCCW) < BALANCE_TRESHOLD)
      {
        Mode = STOP;
        MotorSpeed = 0;
        TargetSpeed = 0;

        // Fine hunt loop
        while(abs(PhotoValue-PhotoValueCCW) > FINE_BALANCE_LIMIT)
        {
          PhotoValue = analogRead(PTCW);
          PhotoValueCCW = analogRead(PTCCW);
        }

        // perform immediate motor stop      
        analogWrite(Motor1, 0);          
        analogWrite(Motor2, 0);          
      }
      break;
  }

  // Handle acceleration/deceleration:
  // =================================
 
  // if target speed/direction not yet attained, then adjust speed
  if (Direction != TargetDirection)
  {
    // Decelerate to 0 speed
    if (MotorSpeed > MINIMUM_SPEED)
    {
      MotorSpeed -= STANDARD_ACCELERATION;
    }
    else
    {
      // 0 speed attained, time to start accelerating in the other direction
      MotorSpeed = 0;
      Direction = TargetDirection;
    }
  }
  else if (MotorSpeed < TargetSpeed)
  {
    // Accelerate
    if (MotorSpeed < MINIMUM_SPEED)
      MotorSpeed = MINIMUM_SPEED;       // jump straight to MINIMUM_SPEED
    else
      MotorSpeed += STANDARD_ACCELERATION;
  }
  else if (MotorSpeed > TargetSpeed && MotorSpeed > MINIMUM_SPEED)
  {
    // Decelerate
    MotorSpeed -= STANDARD_ACCELERATION;
  }

  // Update motor speed
  if (Direction == CW)
  {
    analogWrite(Motor1, MotorSpeed);          
    analogWrite(Motor2, 0);          
  }
  else
  {
    analogWrite(Motor1, 0);          
    analogWrite(Motor2, MotorSpeed);          
  }

  // Delay 50 ms (Control program runs 20 times per second), except only 10ms in HUNT mode
  if (Mode == HUNT)
  {
    delay (10);
  }
  else
  {
    delay(50);
  }
}
I made the code fairly well self-documenting, but if there are any questions
about it feel free to ask. I had to add a fine hunt mode, where the control
program goes into a continuous loop after a certain level of balance has been
found between the light sensors. It then loops continuously until the balance]
is sufficiently close and immediately stops the motor. I found that even with
the slowest HUNT speed I could get without stalling the motor, 10 ms was
too long an interval to find the centerpoint with sufficient precision.

So now I've pretty much caught up with where I am with the construction.
Here's an overview photo (I put a little Z scale train loop on the mounting flange just for fun ;-) :
z_scale_layout.jpg


Next step is to fine-tune the positioning vanes with the positioning guide,
build the bridge, install bridge rails and install the table in the layout. It will
probably be a little while before the next entry comes in. Cheers, until then
ik

Ps. anyone know what size of ties were used on bridges (specifically turntable
bridges) and what spacing was used? I have some 9" x 9" HO scale lumber -
would that be prototypical?
 
Last edited:

Jon NFL

Member
>> Ps. anyone know what size of ties were used on bridges (specifically turntable
bridges) and what spacing was used? I have some 9" x 9" HO scale lumber -
would that be prototypical?


From the drawings for a 56', A-frame (armstrong) TT, the cross ties are 8 x 12, bolted under the 2 main beams. Those beams are a pair of 8" x 18", spaced side-by-side. The space is enough for the 1 1/2" x 33" bolt. I can't tell if the tie or the beam is notched. The 33" bolt goes through the 12 tie and the 18" beam. Ties at the center of the TT are larger. Lateral spacing appears to be 12" between (20" center)
My drawings came from the California Railroad Museum.

Big project - have you thought about publishing beyond this forum?
 
Last edited by a moderator:

ikallio1

Member
Thanks for the information. I went out and photographed some actual
bridges locally which I guess are from about the same era as the turntable
I'm modelling. It seems the bridges are using some square profile cross ties
(maybe 8" x 8") and some rectangular profile ones (maybe 8 x 12). I will take
some measurements from those photos and see what they give.

I wasn't really thinking about publishing this when I started the thread. And I'm
still a complete newbie RR modeller, it would seem presumptious to publish something
at this stage. Besides, I wouldn't even know where to start trying to get an
article published.

Will post the next journal entry in a bit.

Cheers,
ik
 

ikallio1

Member
Scratchbuilding a turntable: Correcting vane positions

Disclaimer

This is a construction journal, not a plan to be followed! If you are inspired
to build something after reading these articles, do so at your own risk. Take
the necessary precautions for safety. Working with powertools and electricity
is dangerous.



Correcting the vane positions

I needed to accurately measure the deviations of the positioning vanes
from their intended positions. I used my digital camera to do this.
I modified the positioning guide to include a millimeter scale,
then took a photograph of the positioning disk at each
stop from both approach directions (clockwise and
counterclockwise). See photograph 1 for example.
vane_positions.jpg


As you can see from the track plan presented earlier,
I have 18 approach tracks, and have to provide 2 table positions
for each track (needed to be able to turn the engine 180 degrees).
I have a total of 36 positioning vanes so I needed to take 72
photos. I had a bit of work to do.

I then loaded each photograph in Gimp (a open source graphical
editing program), used the measuring tool in there to measure
(in pixels) how much the deviation was between the 0-line of the
positioning guide and the positioning mark on the rim of the
positioning disk. Then I measured (in pixels) how much the 10 mm
distance (on the positioning guide) came to in that photograph.

A simple bit of arithmetic then gave me the deviation in millimeters.
See the table in picture 2 (the pdf file).
vane_positions.jpg


It was interesting to see the difference in deviation when
approaching each position from CW and CCW directions. There
seemed to be a fairly consistent error just over 1/10th millimeters.
The largest error was 0.28 mm. This would translate to an
error of a bit over 1/100 inches at the approach track rail ends.
Looks promising so far.

I then calculated a new origin for the 0-position (after all, this
position is arbitrary). I wanted to pick a position that would
minimise the number of vanes I needed to move. I picked the
value 1.22 as the new origin point (i.e. I subtracted 1.22 from
all deviations, arriving at the values in the "Corrected"
column. My criterion for needing to move a vane was 1/4 mm.
Anything under that would be close enough for now.

I then needed to figure out which vane was responsible for the
error, put that in the "Move vane" column, then rounded up
the movement amount to one decimal place for the correction
amount (last column)

Next it was time to heat up the soldering gun and shift some
vanes. I'm hoping that I managed to get all the vanes to
within 0.25mm of correct position (1/100 inch at the approach
track rail ends). This is good enough for now.

I plan to position the approach tracks using the turntable bridge
rails. This should put the average positioning error for the "better"
half of the bridge to less than 0.003 inches (0.13 mm divided by 2,
then add 20 pct to account for the larger diameter at the rail heads,
then divide by 25.4 to convert to inches). I will then have to
fine-adjust the opposing side vanes as best as I can until I get
acceptable accuracy for the bad end of the bridge.

Next step will be building the bridge. I will post the next journal
entry after I get that done.

Cheers,
ik
 
Last edited:

ikallio1

Member
Sorry for the long hiatus guys, been busy with other
hobbies and family life, in general. I hope to be
able to blow the dust off the project and post some
more progress soon.

-ik
 

ikallio1

Member
boy I'm glad I started this build log, sure will make it easier to resume the project
some day! The project is not dead by any means. I lost the H-bridge chip to another
project, but that can be replaced easily enough. I hope to be able to get back to
the project soon.

-ik
 

ikallio1

Member
Quick update - I started to dust off the project and realized I had "misappropriated" the Arduino for another project as well :-/

Oh well, that processor board was overkill for this project anyway. I have been tinkering with Atmel's lower end processors, the ATtiny series, in particular the ATTiny13A. It only has 8 pins, 5 of which can be used for I/O. One more can be added with some extra challenges. My project currently needs the 2 Analog inputs from the sensor board, 1 analog input from the direction control potentiometer, and 2 digital output pins for the motor. That's 5 I/O pins, so the ATtiny13A should be a perfect match for this project! These processors cost about 70 cents a piece - compare that to the $30 cost of the Arduino :)

I have built a simple processor board with the ATtiny13A, and a somewhat more complex programmer board (needed to write the program into the ATtiny13A). I'm in the process of bringing up the turntable to the level of functionality where it was when I set the project aside for a bit almost 4 years ago :)

The challenge is, the ATtiny13A has only 1024 bytes of program memory and 64 bytes of RAM. I have some work to do to fit the necessary functionality into those constraints. Once I get there, I will post photos and updated code listings.

-ik
 

ikallio1

Member
Finally had some time to tinker with the ATtiny13A. I was going to build a board with the ATtiny13A processor, Voltage regulator and motor driver / H-bridge chip. However I noticed that I can get ready made motor controller boards from Ebay for less than what I would have to pay for the components. So I ordered the Motor controller boards from Ebay and built a small processor board with just an ICSP programming header, plus headers for motor, potentiometer & sensor boards. The Motor controller board had a 5V regulator in it so I used that to power the processor board. It turned out very simple, will post pictures shortly.

The next step was a lot of fun, I converted the C program by hand to AVR assembly code. For some reason I really like writing assembly code - you get to know the processor on a much more intimate level :)

The AVRs have 32 registers, and I was able to put all the variables I needed into those registers, leaving the 64 byte RAM space completely untouched (except for the program stack). The key was to use only 8 bit unsigned variables. The only area where I was a bit dubious about this was the AD conversions. I am using only 8 bit of resolution from the converters but it seems to be working just fine. The total code size is currently 430 bytes! (not kilobytes or Megabytes:) It fits well into the available 1024 byte available space.

I am using the AVR assembler in Linux, avra. To compile (Assemble) the code, I use the simple command line

> avra Turntable.asm

No need for any make files since everything is contained within one source file Turntable.asm and there is one include file tn13def.inc. I will include the current listings of each shortly. This command line generates a Intel format HEX file called Turntable.hex. The HEX file is uploaded using the Arduino as a programmer (see <http://arduino.cc/en/Tutorial/ArduinoISP>). Instead of using the arduino for the actual target development, I just use the AVRDUDE programmer interface program directly from the command line to upload the HEX file.

> avrdude -C/usr/share/arduino/hardware/tools/avrdude.conf -v -v -v -v -pattiny13 -cstk500v1 -P/dev/ttyUSB0 -b19200 -Uflash:w:Turntable.hex:i

It took a while to figure all of this out. If I hadn't insisted on developing on Linux, I would have had a simpler experience just using the free AVR studio environment from Atmel, together with a commercial AVRISP programmer. But where's the fun and challenge in that?

The biggest problem of developing for ATtiny vs Arduino is the debugging. Inevitably you will have made mistakes and having no debugging interface to the ATtiny makes it much more challenging to find & remove the bugs!

Finally I seem to be getting comparable repeatability & accuracy with this new setup. I will be doing some fine turning with motor speeds and delay values and will post the final software after I'm satisfied.

Cheers,
ik
 

montanan

Whiskey Merchant
That's some nice work. I have an old scrathbuilt turntable on my layout, but it's no where as complex. It was scratchbuilt out of brass, and powered by a motor from an old player piano. No indexing on this antique. I think is was built about 35 years ago by the late Pete Ellis of Cascade, MT. Back then much of what we have today was a pipe dream. He donated it to me about 20 some years ago when he built an addition onto his model railroad building and had to do away with a town during his expansion and the turntable was in the way.



His entire layout was all code 70 hand laid track and when he found out that I was going to be going code 70, he thought he found a good home for it.
 

ikallio1

Member
Oooo, code 70, that looks so nice!

Are those approach tracks 8 or 9 degrees apart? That's one area where I have had a nagging doubt - my current design uses 6 degree spacing as in the prototype. I had a feeling the approach tracks would get a bit too close together given the diameter of the turntable. I do not know why I didn't take the time to do a bit of simple math; the distance between track centers should be very easily calculated with the simple formula x = r * 2 * sin (a / 2), where r is the radius of the turntable pit, a is the angle between approach tracks. See graph below.

Geometry.jpg

In my turntable, r = 173mm, a = 6, therefore x = 18.1mm! The HO gauge is 16.9mm, add to that double the code 85 rail head width 2 * 1.016, I get 18.932mm distance between outer edges of the rail heads! Gah! I would need to file the outsides of the approach tracks to about half the width, insulate the gap between adjacent rails. The wheels would of course bridge the gap and short circuit the adjacent left & right rails, so I would need to isolate the sections right next to the pit! This is sounding more complex than I want.

I am considering going back to the drawing board for a redesign of the area where I have the approach track spaced 6 degrees apart. If I use 7.5 degree separation in that area, the approach tracks would have 22.6mm of space, plenty enough to avoid such problems. I can still use the same stall geometry if I move the roundhouse a bit closer to the pit and add a slight curve to the approach tracks, starting maybe 2 or 3 inches from the pit. This would affect 11 tracks, and would mean moving 22 positioning vanes :-( Gah, should have done my homework better during the design phase! What to do, what to do?

-ik

ps. could anyone recommend a deck girder bridge kit? I was going to scratchbuild the bridge but I've come to the point where I'm ready allow myself this little "cheat" :) The bridge needs to be about 13.5 scale inches long (98 prototype feet). See the image below for the style I'm looking for - the girders are placed right under the rails, with 8x8s or 8x12s on top.

AuburnTT.jpg
 
Last edited by a moderator:

ikallio1

Member
In case someone is looking for the Assembly (ASM) code for the ATtiny13A, here it is. It is 428 bytes in length so using a bit more than 40 percent of the available code space. The ASM was hand assembled from the original C code. The original C code is left as comments at the end of each ASM line so you'll need a wide editor window to easily read the long lines. I also had to split the code into to parts due to maximum post length limitations.

So here is part 1: (all of this code is in the file turntable.asm)

Code:
; /*
;
;  Turntable control
;  =================
;
;  Physical inputs:
;  - Potentiometer for user to request turning direction
;    and speed
;  - Analog inputs from two phototransistors (used to determine
;    location of the positioning vanes)
;
;  Physical outputs:
;  - 2 wires to send PWM pulses to a DC motor
;  
;  System description:
;  - Turntable bridge has a positioning disk mounted rigidly
;    on the same axle. Positioning disk is under the layout.
;    Positioning vanes mounted on the positioning disk are
;    used to accurately stop the turntable at the correct
;    location for the approach tracks on the layout. DC motor
;    drive wheel bears on the positioning disk to turn the
;    turntable bridge.
;
;  Functional description:
;  - The control panel has a single potentiometer. The user
;    rotates it in the direction, (CW or CCW), that he wants
;    the bridge to rotate. This makes the bridge rotate at its
;    standard RUN speed in the chosen direction. When the user
;    returns the potentiometer to its center position, the
;    bridge decelerates to APPROACH speed and continues to
;    the next track. As it nears the track, The bridge decelerates
;    to HUNT speed and zeroes in to place.
;  - APPROACH mode ends when the leading edge phototransistor
;    is occluded
;  - HUNT mode ends when the light falling on the phototransistors
;    is balanced. System enters STOP mode
;  - Speed changes are never abrupt, the control software gently
;    accelerates/decelerates transition between RUN, APPROACH
;    and HUNT speeds
;  - A really fast turn speed called LUDICROUS speed is used
;    when the potentiometer is turned all the way to the
;    extreme CW or CCW position
;
; */
;

.include "tn13def.inc"

; Global variables (allocated to registers)
.DEF Speed               =R18
.DEF TargetSpeed         =R19
.DEF Direction           =R20
.DEF TargetDirection     =R21
.DEF Mode                 =R22
.DEF PotValue             =R23
.DEF LeadingPT           =R24
.DEF TrailingPT          =R25

; ADC channel MUX values
.equ ADC0                   =0
.equ ADC1                   =1
.equ ADC2                   =2
.equ ADC3                   =3

; I/O pin allocations
.equ MOTOR1                 =PB0
.equ MOTOR2                 =PB1
.equ POTPINIO               =PB2     ; ADC1
.equ PTCCWIO                =PB3     ; ADC3
.equ PTCWIO                 =PB4     ; ADC2
.equ POTPIN                 =ADC1
.equ PTCCW                  =ADC3
.equ PTCW                   =ADC2

; mode definitions
.equ STOP                   =0       ; Bridge is stopped
.equ RUN                    =1       ; Bridge is turning at normal speed
.equ LUDICROUS              =2       ; Bridge is turning at ludicrous speed
.equ APPROACH               =3       ; slow down and start looking for positioning vane
.equ HUNT                   =4       ; Positioning vane detected, move slowly until light input balanced

; turning directions
.equ CW                     =0       ; Clockwise direction
.equ CCW                    =1       ; Clockwise direction

; Below are the potentiometer treshold values used to enter the different operating modes
.equ CW_TRESHOLD_LUDICROUS  =0xF0
.equ CW_TRESHOLD            =0x50
.equ APPROACH_TRESHOLD_HIGH =0x40
.equ APPROACH_TRESHOLD_LOW  =0x12
.equ CCW_TRESHOLD           =0x0D
.equ CCW_TRESHOLD_LUDICROUS =0x03

; Below are the PWM output values for setting different speeds
.equ RUN_SPEED              =56
.equ LUDICROUS_SPEED        =125
.equ APPROACH_SPEED         =45
.equ HUNT_SPEED             =40
.equ MINIMUM_SPEED          =35              ; motor stalls at this voltage, no point in spending time decelerating from or accelerating to this value
.equ STD_ACCEL              =1               ; Standard Acceleration (change in speed per 50ms tick when accelerating or decelerating)

; Below are the treshold values from the phototransistors used to determine mode changes
.equ HUNT_TRESHOLD          =150
.equ BALANCE_TRESHOLD       =23
.equ FINE_BALANCE_LIMIT     =3


; Interrupt Vectors
; =================
; Vector Program   Source       Interrupt Definition
; Number Address
; 1      0x0000    RESET        External Pin, Power-on Reset, Brown-out Reset, Watchdog Reset
; 2      0x0001    INT0         External Interrupt Request 0
; 3      0x0002    PCINT0       Pin Change Interrupt Request 0
; 4      0x0003    TIM0_OVF     Timer/Counter Overflow
; 5      0x0004    EE_RDY       EEPROM Ready
; 6      0x0005    ANA_COMP     Analog Comparator
; 7      0x0006    TIM0_COMPA   Timer/Counter Compare Match A
; 8      0x0007    TIM0_COMPB   Timer/Counter Compare Match B
; 9      0x0008    WDT Watchdog Time-out
; 10     0x0009    ADC          ADC Conversion Complete
.org 0x0000
    rjmp init          ; The reset-vector on Address 0000
    reti               ; IRQ0 Handler
    reti               ; Pin change interrupt (PCINT0) Handler
    reti               ; Timer0 Overflow Handler
    reti               ; EEPROM Ready Handler
    reti               ; Analog Comparator Handler
    reti               ; Timer0 CompareA Handler
    reti               ; Timer0 CompareB Handler
    reti               ; Watchdog Interrupt Handler
    reti               ; ADC Conversion Handler

; *********************************  
; System initialization after RESET
; *********************************
init:

; Init stack
    ldi r16,LOW(RAMEND) ; RAMEND to SPL
    out SPL,r16

; Set the motor 1 & 2 pins low
    cbi PORTB, PB0
    cbi PORTB, PB1

; Set up the data direction register
; Inputs:   PB2 (ADC1) direction pot
;           PB3 (ADC3) IR sensor 1
;           PB4 (ADC2) IR sensor 2
; Outputs:  PB0 (OC0A) pwm out 1 to motor
;           PB1 (OC0B) pwm out 2 to motor
    ldi r16,(1<<DDB0)|(1<<DDB1)     ; PB0 & PB1 are outputs, rest are inputs
    out DDRB,r16

    ; configure & enable the ADC
    ldi r16,(1<<ADEN)|(1<<ADPS2)|(1<<ADPS1)|(0<<ADPS0) ; ADC Enable, ADC prescaler 110 = 1/16
    out ADCSRA,r16

    ; initialize global variables
    ldi Mode,STOP
    ldi Direction,CW
    ldi TargetDirection,CCW
    ldi Speed,0
    ldi TargetSpeed,0

    ; Start ADC1
    ldi r16, (1<<ADLAR)|(1<<MUX0)  ; select ADC1 (MUX[1:0] = 01), Vcc reference & ADLAR (only need 8 bit resolution)
    out ADMUX,r16
    sbi ADCSRA,ADSC                   ; ADC start conversion

    ; Jump to start of main program loop
    rjmp Main

; *************************
;    Drive:
; *************************
;
; Program the "8-bit Timer/Counter0 with PWM" to
; generate phase-correct PWM on either PB0 (OC0A) or
; PB1 (OC0B). The duty cycle controls how fast the
; motor turns.
;
; Inputs: Direction
;         Speed  
;
Drive:
IFDRIVE1:
    tst Speed                 ; if (Speed==0)
    brne ELSEIFDRIVE1         ; {
                              ;     // stop motor
    ldi r16,0                 ;     // Set to normal mode
    out TCCR0A,r16
    cbi PORTB,PORTB0          ;     // Set PORTB0 output low
    cbi PORTB,PORTB1          ;     // Set PORTB1 output low
    rjmp ENDIFDRIVE1          ; }
ELSEIFDRIVE1:                            
    cpi Direction,CCW         ; else if (Direction==CCW)
    brne ELSEDRIVE1           ; {
    cbi PORTB,PORTB0          ;     // Set PORTB0 output low
    ldi r16,0b00100001        ;     // Set to PWM mode 1 (Phase correct PWM), OC0B
    out TCCR0A,r16
    ldi r16,0b00000010        ;     // Set prescaler to 1/8
    out TCCR0B,r16      
    out OCR0B,Speed           ;     // Program Speed as the duty cycle
    rjmp ENDIFDRIVE1          ; }
ELSEDRIVE1:                   ; else
                              ; {
    cbi PORTB,PORTB1          ;     // Set PORTB1 output low
    ldi r16,0b10000001        ;     // Set to PWM mode 1 (Phase correct PWM), OC0A
    out TCCR0A,r16
    ldi r16,0b00000010        ;     // Set prescaler to 1/8
    out TCCR0B,r16      
    out OCR0A,Speed           ;     // Program Speed as the duty cycle
ENDIFDRIVE1:                   ; }
    ret

; **************************************************************
;                         analogRead
; **************************************************************
;
; Input: r16, selects AD channel 0,1,2 or 3 
; Output r16 returns the result of the AD conversion
;
analogRead:   
    andi r16,3                   ; mask away any extra bits from AD channel selection just in case
    ori r16,(1<<ADLAR)|(0<<REFS0); Left adjust (only need 8 bit resolution), Vcc used as analog reference 
    out ADMUX,r16
    sbi ADCSRA,ADSC                 ; start ADC conversion 

waitadc:                         ; Wait until conversion done
    sbic ADCSRA,ADSC             ; test ADSC bit
    rjmp waitadc

; read the value
    in r16,ADCH                     ; reading only the high byte since we requested left adjust (ADLAR)
    ret    

; *************************
;    delay(time [r17])
; *************************  
; This routine delays the program by counting from 1 to 256 * r17.
; uses the r16 and r17 registers as a 16 bit counter. The r16 counts to 256 
; as many times as specified in r17
delay:
    ldi r16, 0
dec_loop:
    nop              ; Note: calibrate number of nop's to make one count of r17 == 1ms
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    dec r16
    brne dec_loop
    dec r17
    brne dec_loop
    ret

; continued in part 2
 
Last edited:

ikallio1

Member
Code:
; part 2
; **************************
;          Main
; **************************
    
Main:
Loop:
    ldi r16,POTPIN                  ; // read the user input (CW/CCW) potentiometer
    rcall analogRead                ; PotValue = analogRead(PotPin);           
    mov PotValue,r16
 
IF1:
    cpi PotValue,CW_TRESHOLD        ; // if CW requested, then go to RUN mode in the CW direction
    brlo ELSEIF1                    ; if (PotValue >= CW_TRESHOLD) {
    ldi TargetDirection,CW          ;     TargetDirection = CW;
    ldi Mode,RUN                    ;     Mode = RUN;
IF2:                                ;     if (PotValue >= CW_TRESHOLD_LUDICROUS)
    cpi PotValue,CW_TRESHOLD_LUDICROUS
    brlo ENDIF2
    ldi Mode,LUDICROUS              ;         Mode = LUDICROUS;
ENDIF2:   
    rjmp ENDIF1                     ; }
ELSEIF1:                            ; // else if CCW, then go to RUN mode in the CCW direction
    cpi PotValue,CCW_TRESHOLD       ; else if (PotValue < CCW_TRESHOLD)
    brsh ENDIF1                     ; {
    ldi TargetDirection,CCW         ;     TargetDirection = CCW;
    ldi Mode,RUN                    ;     Mode = RUN;
IF3:                                ;     if (PotValue < CCW_TRESHOLD_LUDICROUS)
    cpi PotValue,CCW_TRESHOLD_LUDICROUS
    brsh ENDIF3
    ldi Mode,LUDICROUS              ;         Mode = LUDICROUS;
ENDIF3:
ENDIF1:                             ; }

                                    ; // do all the mode-specific stuff
                                    ;
                                    ; switch (Mode) {
    cpi Mode,STOP                   ;   case STOP:
    brne RUNTEST
    ldi TargetSpeed,0               ;     TargetSpeed = 0;
    rjmp ENDSWITCH                  ;     break;

RUNTEST:                              ;     
    cpi Mode,RUN                    ;   case RUN:
    brne LUDTEST
    ldi TargetSpeed,RUN_SPEED       ;     TargetSpeed = RUN_SPEED;
IF4:
    cpi r16,APPROACH_TRESHOLD_LOW   ;     // if potentiometer returned to middle, then go to APPROACH mode
    brlo ENDIF4                     ;     if (PotValue >= APPROACH_TRESHOLD_LOW && PotValue < APPROACH_TRESHOLD_HIGH)
    cpi r16,APPROACH_TRESHOLD_HIGH
    brsh ENDIF4                     ;     {
    ldi Mode,APPROACH               ;       Mode = APPROACH;
    ldi TargetSpeed,APPROACH_SPEED  ;       TargetSpeed = APPROACH_SPEED;
ENDIF4:                             ;     }
    rjmp ENDSWITCH                  ;     break;

LUDTEST:
    cpi Mode,LUDICROUS              ;   case LUDICROUS:
    brne APPRTEST
    ldi TargetSpeed,LUDICROUS_SPEED ;     TargetSpeed = LUDICROUS_SPEED;
IF5:
    cpi r16,APPROACH_TRESHOLD_LOW   ;     // if potentiometer returned to middle, then go to APPROACH mode
    brlo ENDIF5                        ;     if (PotValue >= APPROACH_TRESHOLD_LOW && PotValue < APPROACH_TRESHOLD_HIGH)
    cpi r16,APPROACH_TRESHOLD_HIGH  ;     {
    brsh ENDIF5
    ldi Mode,APPROACH               ;       Mode = APPROACH;
    ldi TargetSpeed,APPROACH_SPEED  ;       TargetSpeed = APPROACH_SPEED;
ENDIF5:                             ;     }
    rjmp ENDSWITCH                  ;     break;

APPRTEST:                           ;     
    cpi Mode,APPROACH               ; case APPROACH:
    brne HUNTTEST
IF6:
    cp Direction,TargetDirection    ; // wait until approach speed and direction have stabilized
    brne ENDIF6                     ;     if (Direction == TargetDirection && Speed == TargetSpeed)
    cp Speed,TargetSpeed            ;     {
    brne ENDIF6
IF7:                                ;       // read the leading edge phototransistor
    cpi Direction,CW                ;       if (Direction == CW)
    brne ELSE7                      ;       {
    ldi r16,PTCW                    ;         LeadingPT = analogRead(PTCW);
    rjmp ENDIF7                     ;       }
ELSE7:                              ;       else
                                    ;       {
    ldi r16,PTCCW                   ;         LeadingPT = analogRead(PTCCW);
ENDIF7:                             ;       }
    rcall analogRead
    mov LeadingPT,r16   

IF8:                                ;       // if occluded, then go to HUNT mode
    cpi LeadingPT,HUNT_TRESHOLD    ;       if (LeadingPT >= HUNT_TRESHOLD)
    brlo ENDIF8                     ;       {
    ldi Mode,HUNT                   ;         Mode = HUNT;
    ldi TargetSpeed,HUNT_SPEED      ;         TargetSpeed = HUNT_SPEED;
ENDIF8:                             ;       }
ENDIF6:                             ;     }
    rjmp ENDSWITCH                  ;     break;
    
HUNTTEST:                           ;   case HUNT:
    cpi Mode,HUNT
    brne ENDSWITCH
    ldi r16,PTCW                    ;     // read phototransistors
    cpi Direction,CW                ;     LeadingPT = analogRead(Direction==CW?PTCW:PTCCW);
    breq A1
    ldi r16,PTCCW
A1: rcall analogRead
    mov LeadingPT,r16
    ldi r16,PTCCW                   ;     TrailingPT = analogRead(Direction==CW?PTCCW:PTCW);
    cpi Direction,CW
    breq A2
    ldi r16,PTCW
A2: rcall analogRead                ;     
    mov TrailingPT,r16
IF9:                                ;     // if values close enough, then go to STOP mode
    ldi r16,BALANCE_TRESHOLD        ;     if (LeadingPT<TrailingPT+BALANCE_TRESHOLD)
    add TrailingPT,r16
    cp LeadingPT,TrailingPT
    brsh ENDIF9                     ;     {
    ldi Mode,STOP                   ;       Mode = STOP;
    ldi Speed,0                     ;       Speed = 0;
    ldi TargetSpeed,0               ;       TargetSpeed = 0;
DO1:                                ;       // Fine hunt loop == might not be necessary in the ASM version
                                    ;       do
                                    ;       {
    ldi r16,PTCW                    ;         LeadingPT = analogRead(Direction==CW?PTCW:PTCCW);
    cpi Direction,CW
    breq A3
    ldi r16,PTCCW
A3: rcall analogRead
    mov LeadingPT,r16
    ldi r16,PTCCW                     ;         TrailingPT = analogRead(Direction==CW?PTCCW:PTCW);
    cpi Direction,CW
    breq A4
    ldi r16,PTCW
A4: rcall analogRead
    mov TrailingPT,r16
    ldi r16,FINE_BALANCE_LIMIT
    add TrailingPT,r16              ;       } while(LeadingPT>=TrailingPT+FINE_BALANCE_LIMIT)
    cp LeadingPT,TrailingPT
    brsh DO1
    ldi r17,1                        ;       // deliberately overshoot for 0.20ms
    ldi r16,51
;    rcall dec_loop
    rcall Drive                     ;       // perform immediate motor stop       
                                    ;       analogWrite(Motor1, 0);           
                                    ;       analogWrite(Motor2, 0);           
ENDIF9:                             ;     }
     rjmp ENDSWITCH                 ;     break;
                                    ; }
ENDSWITCH:

    ; // Handle acceleration/deceleration:
    ; // =================================
                                    ;
IF10:                               ; // if target speed/direction not yet attained, then adjust speed
    cp Direction,TargetDirection    ; if (Direction != TargetDirection)
    breq ELSEIF10                   ; {
IF11:                               ;   // Decelerate to 0 speed
    cpi Speed,MINIMUM_SPEED         ;   if (Speed > MINIMUM_SPEED)
    brlo ELSE11                     ;   {
    subi Speed,STD_ACCEL            ;     Speed -= STD_ACCEL;
    rjmp ENDIF11                    ;   }
ELSE11:                             ;   else
                                    ;   {
                                    ;     // 0 speed attained, time to start accelerating in the other direction
    ldi Speed,0                     ;     Speed = 0;
    mov Direction,TargetDirection   ;     Direction = TargetDirection;
ENDIF11:                            ;   }
    rjmp ENDIF10                    ; }
ELSEIF10:                           ; else if (Speed < TargetSpeed)
    cp Speed,TargetSpeed            ; {
    brsh ELSEIF10b
IF12:                               ;   // Accelerate
    cpi Speed,MINIMUM_SPEED         ;   if (Speed < MINIMUM_SPEED)
    brsh ELSEIF12
    ldi Speed,MINIMUM_SPEED         ;     Speed = MINIMUM_SPEED;       // jump straight to MINIMUM_SPEED
    rjmp ENDIF12
ELSEIF12:                           ;   else
    ldi r16,STD_ACCEL               ;     Speed += STD_ACCEL;
    add Speed,r16
ENDIF12:   
    rjmp ENDIF10                    ; }
ELSEIF10b:                          ; else if (Speed >= TargetSpeed+1 && Speed >= MINIMUM_SPEED+1)
    cpi Speed,MINIMUM_SPEED+1       ; {
    brlo ENDIF10
    mov r16,TargetSpeed
    inc r16
    cp Speed,r16
    brlo ENDIF10   
                                     ;   // Decelerate
    subi Speed,STD_ACCEL            ;   Speed -= STD_ACCEL;
ENDIF10:                            ; }

    rcall Drive                     ; // Update motor speed
                                    ; if (Direction == CW)
                                    ; {
                                    ;   analogWrite(Motor1, Speed);           
                                    ;   analogWrite(Motor2, 0);           
                                    ; }
                                    ; else
                                    ; {
                                    ;   analogWrite(Motor1, 0);           
                                    ;   analogWrite(Motor2, Speed);           
                                    ; }
 IF13:                              ; // Delay 50 ms (Control program runs 20 times per second), except only 10ms in HUNT mode
    cpi Mode,HUNT                   ; if (Mode == HUNT)
    brne ELSE13                     ; {
    ldi r17,5                       ;   delay (10);
    rjmp ENDIF13                    ; }
ELSE13:                             ; else
                                    ; {
    ldi r17,10                      ;   delay(25);
ENDIF13:                            ; }
    rcall delay                     

    rjmp Loop                       ; }
 

ikallio1

Member
The good thing about having a long hiatus in a project is that technology can catch up to what you need :) That is indeed what has happened in the 6 years this project lay waiting for a better day: 3D printing came out! I have designed the turntable bridge in OpenScad and printed out my first revision on my Creality CR10 3d printer using PLA filament. It came about 1mm too long, but I should be able to sand it into place!

OpenScad is a really neat 3D design program in that it is akin to a programming language. You write a script that defines your object, and you have all sorts of fantastic programming features available to you (as the designer). You can use variables, loops, conditional statements, procedures etc. The good thing is I can write the script in such a way that it can be easily modified to generate a turntable bridge for different diameter pit, using different size timbers and so on. I.e. I can parameterisize the script. Here is a solid model of the result:
my_turntable_bridge03.jpgmy_turntable_bridge05.jpg

My feeling is that OpenScad can be especially good for generating plate girder beams. I shall endeavor to write a script that I can use after this project to generate whatever size and shape plate girder beams I need for a future model bridge, another turntable etc. Hopefully others can also make use of it.

In the next few weeks I will be working on the girder beams and support structures that will allow me to mount it on the rest of the turntable mechanism, attaching the rails, and of course painting the model. I use translucent PLA here and it really doesn't look too impressive until after it has been painted. I will keep this thread updated.

ik
 
Last edited:

ikallio1

Member
Hehe, I would never drink decaf!

But now I have a tapered plate girder beam!
girder.jpg
I had to massively exaggerate the size of the rivets in order for them to come through at all in the slicer (I'm using Cura) in preparation for the 3d printing process. We'll see how well it actually comes out - it is printing out right now.

ik
 

Frank

Member
Rather than messing with those sensors, have you considered just 3d printing a geneva drive? That should allow you to get precise centering at each index point, without having to have the motor stop at precisely the right spot.

Something like: https://www.instructables.com/id/3D-Printed-Geneva-Drive/ when combined with an appropriate gearing should allow you to precisely line up the tracks with minimal fuss. It's how the turntable I bought lines them up.
 

ikallio1

Member
I think employing 3d printing for this purpose is a great idea! However, the Geneva drive is fairly limiting in the sense that you have to divide the circle into a certain number of stops, say every N degrees. It would stop at every N degree spot, so in operation it would not look very prototypical. With the positioning vanes I have full freedom to position the approach tracks just like a real world designer had. For example the approach tracks to the round house could be at 8.5 degree intervals and the garden tracks at 12 degree intervals. Or whatever positions work for the prototype you're modeling.

I am now considering scrapping the old soldered-on metal vanes and printing out new positioning vanes. The vanes would be printed attached to a rigid disk body, so their registration in relation to each other would have mathematical accuracy, but I would still retain the full freedom of placing the vanes freely on the circle. No post installation measurements and fine tuning should be necessary! And the head vs tail end of the bridge would be able to land accurately in the right place provided the bridge was mounted right.

Also if I ever wanted to move approach tracks or add new ones, I could simply do it in my OpenScad design model - adding new vanes in there or moving old ones, then print out the new positioning disk system complete with the vanes. Mounting holes would remain in the same place, allowing me to accurately position the new disk in place after removing the old one.

ik
 

Frank

Member
I think employing 3d printing for this purpose is a great idea! However, the Geneva drive is fairly limiting in the sense that you have to divide the circle into a certain number of stops, say every N degrees. It would stop at every N degree spot, so in operation it would not look very prototypical. With the positioning vanes I have full freedom to position the approach tracks just like a real world designer had. For example the approach tracks to the round house could be at 8.5 degree intervals and the garden tracks at 12 degree intervals. Or whatever positions work for the prototype you're modeling.
ik
Yes, this is true, If for some reason you don't want them all evenly spaced, this approach likely wouldn't work. At least not without having unnatural pauses in various places. If you want it to be unevenly spaced or you want to skip over positions, it might make more sense to have a fly wheel and stops that raise and lower to lock the mechanism in the place you want, with the sensor just being used to cut power to the motor and place a locking block on the opposite side of the track.

And I'm totally with you on OpenSCAD, for things that can be modeled using geometric shapes, it seems to work better than other options I've tried.
 



ModelRailroadForums.com is a participant in the Amazon Services LLC Associates Program, an affiliate advertising program designed to provide a means for sites to earn advertising fees by advertising and linking to amazon.com

RailroadBookstore.com - An online railroad bookstore featuring a curated selection of new and used railroad books. Railroad pictorials, railroad history, steam locomotives, passenger trains, modern railroading. Hundreds of titles available, most at discount prices! We also have a video and children's book section.

ModelRailroadBookstore.com - An online model railroad bookstore featuring a curated selection of new and used books. Layout design, track plans, scenery and structure building, wiring, DCC, Tinplate, Toy Trains, Price Guides and more.



Top