Jump to content
 

DCC Controlled (PECO) Turntable Project using a Arduino Uno


Recommended Posts

Hi Geoff (and anybody else looking in).

 

As promised here is the new code for a 180 degree Turntable which powers down the stepper after reaching the desired position. Getting rid of that annoying 'whine' and keeping the motor cool.

 

The are  two ​ three sections that need to be modified to suit your turntable.

                         // 'road' must be greater than 'road180'
                          // road-road180 should be approx 1600
    int road = 2706;      //Adjust 'road' for correct position
    int road180 = 1098;   //Tweak 'road180' for 180deg rotation

As it say's adjust the value following 'road' and 'road180' to suit your turntable.

If you used the previous version you can just plug-in your existing values that you used in the 'stepper2.moveTo' statements or start again with what's here.

 

The other is:

stepper2.moveTo(1900); // somewhere between road and road180
  while (stepper2.currentPosition() < 1900) {

​Like it say's again, make value of 'moveTo' and 'currentPosition' roughly half way between the values in 'road' and 'road180'

 

oh, and I nearly forgot, set the address to whatever accessory address you want to use.

   gAddresses[0].address = 400;

So here's the complete sketch:

 
////////////////////////////////////////////////////////////////////////////////
//
// DCC Turntable Control Test Routines (Accessory Address 200)
 
#include <DCC_Decoder.h>
#include <AccelStepper.h>
#include <Wire.h>
#include <Adafruit_MotorShield.h>
#include "utility/Adafruit_PWMServoDriver.h"
 
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Defines and structures
//
#define kDCC_INTERRUPT            0
 
typedef struct
{
    int               address;                // Address to respond to
    
} 
 
DCCAccessoryAddress;
 
DCCAccessoryAddress gAddresses[1];
  
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//
// Adafruit Setup
 
Adafruit_MotorShield AFMStop(0x60); // Default address, no jumpers
 
// Connect stepper with 200 steps per revolution (1.8 degree)
// to the M3, M4 terminals (blue,yellow,green,red)
 
Adafruit_StepperMotor *myStepper2 = AFMStop.getStepper(200, 2);
 
// you can change these to SINGLE, DOUBLE, INTERLEAVE or MICROSTEP!
 
// wrapper for the motor! (3200 Microsteps/revolution)
void forwardstep2() {  
  myStepper2->onestep(FORWARD, MICROSTEP);
}
void backwardstep2() {  
  myStepper2->onestep(BACKWARD, MICROSTEP);
}
 void release2() {
  myStepper2->release();
}

// Now we'll wrap the stepper in an AccelStepper object
 
AccelStepper stepper2(forwardstep2, backwardstep2);
 
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Decoder Init 
//
void ConfigureDecoder()
 {
    gAddresses[0].address = 400;
 }
 
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Basic accessory packet handler 
//
void BasicAccDecoderPacket_Handler(int address, boolean activate, byte data)
{
        // Convert NMRA packet address format to human address
    address -= 1;
    address *= 4;
    address += 1;
    address += (data & 0x06) >> 1;
    
    boolean enable = (data & 0x01) ? 1 : 0;
    
                          // 'road' must be greater than 'road180'
                          // road-road180 should be approx 1600
    int road = 2706;      //Adjust 'road' for correct position
    int road180 = 1098;   //Tweak 'road180' for 180deg rotation
    
        if( address == 400 )  //DCC accessory address
        {
            Serial.print("Basic addr: ");
            Serial.print(address,DEC);
            Serial.print("   activate: ");
            Serial.println(enable,DEC);
            
            if( enable )
              {
                stepper2.moveTo(road180); 
              while (stepper2.currentPosition() > road180) {
                stepper2.run();
                    }
                delay(1000);    
                release2();
                Serial.println("Release ");
              }
           else
              {
                stepper2.moveTo(road); 
              while (stepper2.currentPosition() < road) {
                stepper2.run();
                    } 
                delay(1000);
                release2();
                Serial.println("Release ");
              }
       }
}
 
 
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Setup
//
void setup() 
{ 
   
   Serial.begin(9600);
   
   AFMStop.begin(); // Start the shiel
  
  //configure pin3 as an input and enable the internal pull-up resistor
  pinMode(3, INPUT_PULLUP);
  //read the sensor (open collector type) value into a variable
  int sensorVal = digitalRead(3);
   
  //set stepper motor speed and acceleration 
  stepper2.setMaxSpeed(30.0);
  stepper2.setAcceleration(20.0);
//  stepper2.moveTo(800);
 
// if near reference point move away
  sensorVal = digitalRead(3);
  while (sensorVal == LOW) {
    sensorVal = digitalRead(3);
    forwardstep2();
      delay(50);
  }
  
// step forward to sensor index point
  while (sensorVal == HIGH) {
    sensorVal = digitalRead(3);
    forwardstep2();
      delay(50);
  }
  
  delay(1000);
  stepper2.moveTo(1900); // somewhere between road and road180
  while (stepper2.currentPosition() < 1900) {
                stepper2.run();
                    }
                delay(1000);    
                release2();
   
   DCC.SetBasicAccessoryDecoderPacketHandler(BasicAccDecoderPacket_Handler, true);
   ConfigureDecoder();
   DCC.SetupDecoder( 0x00, 0x00, kDCC_INTERRUPT );
   release2();
}
 
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Main loop
//
void loop()
{
    static int addr = 0;
   
        ////////////////////////////////////////////////////////////////
        // Loop DCC library
    DCC.loop();
    
        ////////////////////////////////////////////////////////////////
        // Loop Stepper
    
    stepper2.run();

}
 
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 

Have fun.

 

Ray.

Edited by tender
Link to post
Share on other sites

  • RMweb Gold

Hi Geoff (and anybody else looking in).

 

As promised here is the new code for a 180 degree Turntable which powers down the stepper after reaching the desired position. Getting rid of that annoying 'whine' and keeping the motor cool.

 

The are  two ​ three sections that need to be modified to suit your turntable.

                         // 'road' must be greater than 'road180'
                          // road-road180 should be approx 1600
    int road = 2706;      //Adjust 'road' for correct position
    int road180 = 1098;   //Tweak 'road180' for 180deg rotation

As it say's adjust the value following 'road' and 'road180' to suit your turntable.

If you used the previous version you can just plug-in your existing values that you used in the 'stepper2.moveTo' statements or start again with what's here.

 

The other is:

stepper2.moveTo(1900); // somewhere between road and road180
  while (stepper2.currentPosition() < 1900) {

​Like it say's again, make value of 'moveTo' and 'currentPosition' roughly half way between the values in 'road' and 'road180'

 

oh, and I nearly forgot, set the address to whatever accessory address you want to use.

   gAddresses[0].address = 400;

So here's the complete sketch:

 
////////////////////////////////////////////////////////////////////////////////
//
// DCC Turntable Control Test Routines (Accessory Address 200)
 
#include <DCC_Decoder.h>
#include <AccelStepper.h>
#include <Wire.h>
#include <Adafruit_MotorShield.h>
#include "utility/Adafruit_PWMServoDriver.h"
 
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Defines and structures
//
#define kDCC_INTERRUPT            0
 
typedef struct
{
    int               address;                // Address to respond to
    
} 
 
DCCAccessoryAddress;
 
DCCAccessoryAddress gAddresses[1];
  
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//
// Adafruit Setup
 
Adafruit_MotorShield AFMStop(0x60); // Default address, no jumpers
 
// Connect stepper with 200 steps per revolution (1.8 degree)
// to the M3, M4 terminals (blue,yellow,green,red)
 
Adafruit_StepperMotor *myStepper2 = AFMStop.getStepper(200, 2);
 
// you can change these to SINGLE, DOUBLE, INTERLEAVE or MICROSTEP!
 
// wrapper for the motor! (3200 Microsteps/revolution)
void forwardstep2() {  
  myStepper2->onestep(FORWARD, MICROSTEP);
}
void backwardstep2() {  
  myStepper2->onestep(BACKWARD, MICROSTEP);
}
 void release2() {
  myStepper2->release();
}

// Now we'll wrap the stepper in an AccelStepper object
 
AccelStepper stepper2(forwardstep2, backwardstep2);
 
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Decoder Init 
//
void ConfigureDecoder()
 {
    gAddresses[0].address = 400;
 }
 
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Basic accessory packet handler 
//
void BasicAccDecoderPacket_Handler(int address, boolean activate, byte data)
{
        // Convert NMRA packet address format to human address
    address -= 1;
    address *= 4;
    address += 1;
    address += (data & 0x06) >> 1;
    
    boolean enable = (data & 0x01) ? 1 : 0;
    
                          // 'road' must be greater than 'road180'
                          // road-road180 should be approx 1600
    int road = 2706;      //Adjust 'road' for correct position
    int road180 = 1098;   //Tweak 'road180' for 180deg rotation
    
        if( address == 400 )  //DCC accessory address
        {
            Serial.print("Basic addr: ");
            Serial.print(address,DEC);
            Serial.print("   activate: ");
            Serial.println(enable,DEC);
            
            if( enable )
              {
                stepper2.moveTo(road180); 
              while (stepper2.currentPosition() > road180) {
                stepper2.run();
                    }
                delay(1000);    
                release2();
                Serial.println("Release ");
              }
           else
              {
                stepper2.moveTo(road); 
              while (stepper2.currentPosition() < road) {
                stepper2.run();
                    } 
                delay(1000);
                release2();
                Serial.println("Release ");
              }
       }
}
 
 
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Setup
//
void setup() 
{ 
   
   Serial.begin(9600);
   
   AFMStop.begin(); // Start the shiel
  
  //configure pin3 as an input and enable the internal pull-up resistor
  pinMode(3, INPUT_PULLUP);
  //read the sensor (open collector type) value into a variable
  int sensorVal = digitalRead(3);
   
  //set stepper motor speed and acceleration 
  stepper2.setMaxSpeed(30.0);
  stepper2.setAcceleration(20.0);
//  stepper2.moveTo(800);
 
// if near reference point move away
  sensorVal = digitalRead(3);
  while (sensorVal == LOW) {
    sensorVal = digitalRead(3);
    forwardstep2();
      delay(50);
  }
  
// step forward to sensor index point
  while (sensorVal == HIGH) {
    sensorVal = digitalRead(3);
    forwardstep2();
      delay(50);
  }
  
  delay(1000);
  stepper2.moveTo(1900); // somewhere between road and road180
  while (stepper2.currentPosition() < 1900) {
                stepper2.run();
                    }
                delay(1000);    
                release2();
   
   DCC.SetBasicAccessoryDecoderPacketHandler(BasicAccDecoderPacket_Handler, true);
   ConfigureDecoder();
   DCC.SetupDecoder( 0x00, 0x00, kDCC_INTERRUPT );
   release2();
}
 
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Main loop
//
void loop()
{
    static int addr = 0;
   
        ////////////////////////////////////////////////////////////////
        // Loop DCC library
    DCC.loop();
    
        ////////////////////////////////////////////////////////////////
        // Loop Stepper
    
    stepper2.run();

}
 
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 

Have fun.

 

Ray.

 

Thank you Ray. I will have a go at this sometime tomorrow.

 

Geoff

Link to post
Share on other sites

  • RMweb Gold

Hello Ray, well after much tribulation I have got the new programming working. First trip up was the line "utility/Adafruit_PWMServoDriver.h" which has to be changed to include _MS in front of _PWM----etc. I omitted to change that. Then, because I have no understanding of programming I get a little confused by the combination of symbols and 'conversational' language but I eventually sorted my brain out only to find the table stopping halfway between the two track positions and not responding to any commands.I finally tracked that down to one of the DCC wires to the interface board having been dislodged, presumably when I swapped over the power connections to connect the usb from my MacBook. But it is all sorted now and working just as you predicted. Thank you so much for giving up more of your time, I am very grateful.

 

Best regards.

 

Geoff

  • Like 1
Link to post
Share on other sites

  • RMweb Premium

Hi Geoff (and anybody else looking in).

 

As promised here is the new code for a 180 degree Turntable which powers down the stepper after reaching the desired position. Getting rid of that annoying 'whine' and keeping the motor cool.

 

The are  two ​ three sections that need to be modified to suit your turntable.

                         // 'road' must be greater than 'road180'
                          // road-road180 should be approx 1600
    int road = 2706;      //Adjust 'road' for correct position
    int road180 = 1098;   //Tweak 'road180' for 180deg rotation

As it say's adjust the value following 'road' and 'road180' to suit your turntable.

If you used the previous version you can just plug-in your existing values that you used in the 'stepper2.moveTo' statements or start again with what's here.

 

The other is:

stepper2.moveTo(1900); // somewhere between road and road180
  while (stepper2.currentPosition() < 1900) {

​Like it say's again, make value of 'moveTo' and 'currentPosition' roughly half way between the values in 'road' and 'road180'

 

oh, and I nearly forgot, set the address to whatever accessory address you want to use.

   gAddresses[0].address = 400;

So here's the complete sketch:

 
////////////////////////////////////////////////////////////////////////////////
//
// DCC Turntable Control Test Routines (Accessory Address 200)
 
#include <DCC_Decoder.h>
#include <AccelStepper.h>
#include <Wire.h>
#include <Adafruit_MotorShield.h>
#include "utility/Adafruit_PWMServoDriver.h"
 
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Defines and structures
//
#define kDCC_INTERRUPT            0
 
typedef struct
{
    int               address;                // Address to respond to
    
} 
 
DCCAccessoryAddress;
 
DCCAccessoryAddress gAddresses[1];
  
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//
// Adafruit Setup
 
Adafruit_MotorShield AFMStop(0x60); // Default address, no jumpers
 
// Connect stepper with 200 steps per revolution (1.8 degree)
// to the M3, M4 terminals (blue,yellow,green,red)
 
Adafruit_StepperMotor *myStepper2 = AFMStop.getStepper(200, 2);
 
// you can change these to SINGLE, DOUBLE, INTERLEAVE or MICROSTEP!
 
// wrapper for the motor! (3200 Microsteps/revolution)
void forwardstep2() {  
  myStepper2->onestep(FORWARD, MICROSTEP);
}
void backwardstep2() {  
  myStepper2->onestep(BACKWARD, MICROSTEP);
}
 void release2() {
  myStepper2->release();
}

// Now we'll wrap the stepper in an AccelStepper object
 
AccelStepper stepper2(forwardstep2, backwardstep2);
 
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Decoder Init 
//
void ConfigureDecoder()
 {
    gAddresses[0].address = 400;
 }
 
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Basic accessory packet handler 
//
void BasicAccDecoderPacket_Handler(int address, boolean activate, byte data)
{
        // Convert NMRA packet address format to human address
    address -= 1;
    address *= 4;
    address += 1;
    address += (data & 0x06) >> 1;
    
    boolean enable = (data & 0x01) ? 1 : 0;
    
                          // 'road' must be greater than 'road180'
                          // road-road180 should be approx 1600
    int road = 2706;      //Adjust 'road' for correct position
    int road180 = 1098;   //Tweak 'road180' for 180deg rotation
    
        if( address == 400 )  //DCC accessory address
        {
            Serial.print("Basic addr: ");
            Serial.print(address,DEC);
            Serial.print("   activate: ");
            Serial.println(enable,DEC);
            
            if( enable )
              {
                stepper2.moveTo(road180); 
              while (stepper2.currentPosition() > road180) {
                stepper2.run();
                    }
                delay(1000);    
                release2();
                Serial.println("Release ");
              }
           else
              {
                stepper2.moveTo(road); 
              while (stepper2.currentPosition() < road) {
                stepper2.run();
                    } 
                delay(1000);
                release2();
                Serial.println("Release ");
              }
       }
}
 
 
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Setup
//
void setup() 
{ 
   
   Serial.begin(9600);
   
   AFMStop.begin(); // Start the shiel
  
  //configure pin3 as an input and enable the internal pull-up resistor
  pinMode(3, INPUT_PULLUP);
  //read the sensor (open collector type) value into a variable
  int sensorVal = digitalRead(3);
   
  //set stepper motor speed and acceleration 
  stepper2.setMaxSpeed(30.0);
  stepper2.setAcceleration(20.0);
//  stepper2.moveTo(800);
 
// if near reference point move away
  sensorVal = digitalRead(3);
  while (sensorVal == LOW) {
    sensorVal = digitalRead(3);
    forwardstep2();
      delay(50);
  }
  
// step forward to sensor index point
  while (sensorVal == HIGH) {
    sensorVal = digitalRead(3);
    forwardstep2();
      delay(50);
  }
  
  delay(1000);
  stepper2.moveTo(1900); // somewhere between road and road180
  while (stepper2.currentPosition() < 1900) {
                stepper2.run();
                    }
                delay(1000);    
                release2();
   
   DCC.SetBasicAccessoryDecoderPacketHandler(BasicAccDecoderPacket_Handler, true);
   ConfigureDecoder();
   DCC.SetupDecoder( 0x00, 0x00, kDCC_INTERRUPT );
   release2();
}
 
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Main loop
//
void loop()
{
    static int addr = 0;
   
        ////////////////////////////////////////////////////////////////
        // Loop DCC library
    DCC.loop();
    
        ////////////////////////////////////////////////////////////////
        // Loop Stepper
    
    stepper2.run();

}
 
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 

Have fun.

 

Ray.

 

Hi

 

Its better to put constants at the start of your code so when configuring they are all in one place. 

 

For example

 

 

 
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Defines and structures
//
#define kDCC_INTERRUPT 0
 
#define STARTPOS 2706
#define ENDPOS 1098 
#define HALFWAY 1900
#define ADDRESS 400
 

 

Cheers

 

Paul

Link to post
Share on other sites

  • RMweb Premium

 

for people with more than one road/station, you could use this, which is what i do..

 

define the struct as follows;

 

typedef struct
{
  int address;
  int stationFront;
  int stationBack;
}
DCCAccessoryAddress;
 
then in ConfigureDecoder, i use something like this...
 
void ConfigureDecoder()
{
    // this is home
  gAddresses[0].address = 200;
  gAddresses[0].stationFront = 906;
  gAddresses[0].stationBack = 2506;
  
  gAddresses[1].address = 201;
  gAddresses[1].stationFront = 1700;
  gAddresses[1].stationBack = 100;
  
  gAddresses[2].address = 202;
  gAddresses[2].stationFront = 1900;
  gAddresses[2].stationBack = 300;
 
etc etc
 
// these are the nudge addresses
  gAddresses[12].address = 300;
  gAddresses[13].address = 301;
  gAddresses[14].address = 302;
  gAddresses[15].address = 303;
 
therefore the BasicAccDecoderPacket_Handler can be written as such
 
Serial.print("Moving to Station : ");
            Serial.println(i, DEC);
            
            if( enable )
            {
                if (i < 12)
                {
                  Serial.print("Moving to Front Position : ");
                  Serial.println(gAddresses[i].stationFront, DEC);
                  stepper2.moveTo(gAddresses[i].stationFront);
                  break;
                }
                else
                switch (i)
                {
                  // nudge addresses  
                  case 12:
                    Serial.print("Nudging forward 25 steps : ");
                    Serial.println(stepper2.currentPosition() + cNudge, DEC);
                    stepper2.moveTo(stepper2.currentPosition() + cNudge);
                    break;  
        
                  case 13:
                    Serial.print("Nudging forward 50 steps : ");
                    Serial.println(stepper2.currentPosition() + (cNudge * 2), DEC);
                    stepper2.moveTo(stepper2.currentPosition() + (cNudge * 2));
                    break; 
        
                  case 14:
                    Serial.print("Nudging forward 100 steps : ");
                    Serial.println(stepper2.currentPosition() + (cNudge * 4), DEC);
                    stepper2.moveTo(stepper2.currentPosition() + (cNudge * 4));
                    break; 
                  case 15:
                    Serial.print("Nudging forward 500 steps : ");
                    Serial.println(stepper2.currentPosition() + (cNudge * 20), DEC);
                    stepper2.moveTo(stepper2.currentPosition() + (cNudge * 20));
                    break; 
                      
                }
            }
this makes for slightly cleaner code ( not repeating code that can be easily functionised/coded better 
 
IMHO as a Technical Lead Developer.
 

 

Hi

 

However you are still defining constants in the middle of the code.

 

Cheers

 

Paul (Senior Analyst Programmer)

Link to post
Share on other sites

  • RMweb Gold

Hi Geoff...

 

sounds to me like you need either

 

1) a dcc interface board

2) dcc interface with arduino headers and an i2c output 

 

www.dccinterface.com

 

 

both available from me :-)

 

( taking advantage of the situation )

 

Thanks Ian, it was just a wire pulled out of a screw connector block, not even completely out, but just not making contact which is why I didn't notice it while I was grovelling about under the railway swapping the connections over. It is all sorted now thanks.

 

Geoff

Edited by geoff
Link to post
Share on other sites

Thanks Paul and Ian for your suggestions. Like i said 5 years ago (wow, is it that long ago, I've only just got around to cutting the hole in the baseboard to take the turntable) when i started this thread i'm no expert programmer, so thanks again and I'll clean up the code when i get a few minutes spare and post an update. (I can see now why i was having problems with the constants further down, i gave up in the end and just put them in again.)

 

Ray.

Edited by tender
Link to post
Share on other sites

So here's a tidied up version of the 180 degree turntable removing a lot of unnessarsary stuff as we are using just one DCC accessory address..

 

The following definitions are the only values you need to change to suit your system.

#define road 2706        //Adjust 'road' for correct position
#define road180 1098     //Tweak 'road180' for 180deg rotation
#define dccaddress 400   // DCC address to respond to

and the complete sketch

 
////////////////////////////////////////////////////////////////////////////////
//
// 180 Degree DCC Turntable (Accessory Address 400)
 
#include <DCC_Decoder.h>
#include <AccelStepper.h>
#include <Wire.h>
#include <Adafruit_MotorShield.h>
#include "utility/Adafruit_PWMServoDriver.h"
 
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Defines and structures
//
#define kDCC_INTERRUPT            0
                         // define road positions
                         // 'road' must be greater than 'road180'
                         // road-road180 should be approx 1600
#define road 2706        //Adjust 'road' for correct position
#define road180 1098     //Tweak 'road180' for 180deg rotation
#define dccaddress 400   // DCC address to respond to
  
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//
// Adafruit Setup
 
Adafruit_MotorShield AFMStop(0x60); // Default address, no jumpers
 
// Connect stepper with 200 steps per revolution (1.8 degree)
// to the M3, M4 terminals (blue,yellow,green,red)
 
Adafruit_StepperMotor *myStepper2 = AFMStop.getStepper(200, 2);
 
// you can change these to SINGLE, DOUBLE, INTERLEAVE or MICROSTEP!
 
// wrapper for the motor! (3200 Microsteps/revolution)
void forwardstep2() {  
  myStepper2->onestep(FORWARD, MICROSTEP);
}
void backwardstep2() {  
  myStepper2->onestep(BACKWARD, MICROSTEP);
}
 void release2() {
  myStepper2->release();
}

// Now we'll wrap the stepper in an AccelStepper object
 
AccelStepper stepper2(forwardstep2, backwardstep2);
 
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Basic accessory packet handler 
//
void BasicAccDecoderPacket_Handler(int address, boolean activate, byte data)
{
        // Convert NMRA packet address format to human address
    address -= 1;
    address *= 4;
    address += 1;
    address += (data & 0x06) >> 1;
    
    boolean enable = (data & 0x01) ? 1 : 0;
    
        if( address == dccaddress )  //DCC accessory address
        {
            Serial.print("Basic addr: ");
            Serial.print(address,DEC);
            Serial.print("   activate: ");
            Serial.println(enable,DEC);
            
            if( enable )
              {
                stepper2.moveTo(road180); 
              while (stepper2.currentPosition() > road180) {
                stepper2.run();
                    }
                delay(1000);    
                release2();
                Serial.println("Release ");
              }
           else
              {
                stepper2.moveTo(road); 
              while (stepper2.currentPosition() < road) {
                stepper2.run();
                    } 
                delay(1000);
                release2();
                Serial.println("Release ");
              }
       }
}
 
 
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Setup
//
void setup() 
{ 
   
   Serial.begin(9600);
   
   AFMStop.begin(); // Start the shiel
  
//configure pin3 as an input and enable the internal pull-up resistor
  pinMode(3, INPUT_PULLUP);
//read the sensor (open collector type) value into a variable
  int sensorVal = digitalRead(3);
   
//set stepper motor speed and acceleration 
  stepper2.setMaxSpeed(30.0);
  stepper2.setAcceleration(20.0);
 
// if near reference point move away
  sensorVal = digitalRead(3);
  while (sensorVal == LOW) {
    sensorVal = digitalRead(3);
    forwardstep2();
      delay(50);
  }
  
// step forward to sensor index point
  while (sensorVal == HIGH) {
    sensorVal = digitalRead(3);
    forwardstep2();
      delay(50);
  }
  
  delay(1000);
  stepper2.moveTo(road-800); // somewhere between road and road180
  while (stepper2.currentPosition() < road-800) {
                stepper2.run();
                    }
                delay(1000);    
                release2();
   
   DCC.SetBasicAccessoryDecoderPacketHandler(BasicAccDecoderPacket_Handler, true);
   DCC.SetupDecoder( 0x00, 0x00, kDCC_INTERRUPT );
}
 
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Main loop
//
void loop()
{
    static int addr = 0;
   
        ////////////////////////////////////////////////////////////////
        // Loop DCC library
    DCC.loop();
    
        ////////////////////////////////////////////////////////////////
        // Loop Stepper
    
    stepper2.run();

}
 
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 

again have fun and thanks to Paul and Ian for their input.

 

Ray.

Link to post
Share on other sites

  • RMweb Gold

So here's a tidied up version of the 180 degree turntable removing a lot of unnessarsary stuff as we are using just one DCC accessory address..

 

The following definitions are the only values you need to change to suit your system.

#define road 2706        //Adjust 'road' for correct position
#define road180 1098     //Tweak 'road180' for 180deg rotation
#define dccaddress 400   // DCC address to respond to

and the complete sketch

 
////////////////////////////////////////////////////////////////////////////////
//
// 180 Degree DCC Turntable (Accessory Address 400)
 
#include <DCC_Decoder.h>
#include <AccelStepper.h>
#include <Wire.h>
#include <Adafruit_MotorShield.h>
#include "utility/Adafruit_PWMServoDriver.h"
 
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Defines and structures
//
#define kDCC_INTERRUPT            0
                         // define road positions
                         // 'road' must be greater than 'road180'
                         // road-road180 should be approx 1600
#define road 2706        //Adjust 'road' for correct position
#define road180 1098     //Tweak 'road180' for 180deg rotation
#define dccaddress 400   // DCC address to respond to
  
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//
// Adafruit Setup
 
Adafruit_MotorShield AFMStop(0x60); // Default address, no jumpers
 
// Connect stepper with 200 steps per revolution (1.8 degree)
// to the M3, M4 terminals (blue,yellow,green,red)
 
Adafruit_StepperMotor *myStepper2 = AFMStop.getStepper(200, 2);
 
// you can change these to SINGLE, DOUBLE, INTERLEAVE or MICROSTEP!
 
// wrapper for the motor! (3200 Microsteps/revolution)
void forwardstep2() {  
  myStepper2->onestep(FORWARD, MICROSTEP);
}
void backwardstep2() {  
  myStepper2->onestep(BACKWARD, MICROSTEP);
}
 void release2() {
  myStepper2->release();
}

// Now we'll wrap the stepper in an AccelStepper object
 
AccelStepper stepper2(forwardstep2, backwardstep2);
 
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Basic accessory packet handler 
//
void BasicAccDecoderPacket_Handler(int address, boolean activate, byte data)
{
        // Convert NMRA packet address format to human address
    address -= 1;
    address *= 4;
    address += 1;
    address += (data & 0x06) >> 1;
    
    boolean enable = (data & 0x01) ? 1 : 0;
    
        if( address == dccaddress )  //DCC accessory address
        {
            Serial.print("Basic addr: ");
            Serial.print(address,DEC);
            Serial.print("   activate: ");
            Serial.println(enable,DEC);
            
            if( enable )
              {
                stepper2.moveTo(road180); 
              while (stepper2.currentPosition() > road180) {
                stepper2.run();
                    }
                delay(1000);    
                release2();
                Serial.println("Release ");
              }
           else
              {
                stepper2.moveTo(road); 
              while (stepper2.currentPosition() < road) {
                stepper2.run();
                    } 
                delay(1000);
                release2();
                Serial.println("Release ");
              }
       }
}
 
 
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Setup
//
void setup() 
{ 
   
   Serial.begin(9600);
   
   AFMStop.begin(); // Start the shiel
  
//configure pin3 as an input and enable the internal pull-up resistor
  pinMode(3, INPUT_PULLUP);
//read the sensor (open collector type) value into a variable
  int sensorVal = digitalRead(3);
   
//set stepper motor speed and acceleration 
  stepper2.setMaxSpeed(30.0);
  stepper2.setAcceleration(20.0);
 
// if near reference point move away
  sensorVal = digitalRead(3);
  while (sensorVal == LOW) {
    sensorVal = digitalRead(3);
    forwardstep2();
      delay(50);
  }
  
// step forward to sensor index point
  while (sensorVal == HIGH) {
    sensorVal = digitalRead(3);
    forwardstep2();
      delay(50);
  }
  
  delay(1000);
  stepper2.moveTo(road-800); // somewhere between road and road180
  while (stepper2.currentPosition() < road-800) {
                stepper2.run();
                    }
                delay(1000);    
                release2();
   
   DCC.SetBasicAccessoryDecoderPacketHandler(BasicAccDecoderPacket_Handler, true);
   DCC.SetupDecoder( 0x00, 0x00, kDCC_INTERRUPT );
}
 
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Main loop
//
void loop()
{
    static int addr = 0;
   
        ////////////////////////////////////////////////////////////////
        // Loop DCC library
    DCC.loop();
    
        ////////////////////////////////////////////////////////////////
        // Loop Stepper
    
    stepper2.run();

}
 
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 

again have fun and thanks to Paul and Ian for their input.

 

Ray.

 

Thanks Ray. I presume even with this version I would still have to alter the line beginning "utility/Adafruit etc to include _ MS in front of the _PWMServo etc to suit the code I have for my motor shield.

 

Geoff

Link to post
Share on other sites

Thanks Ray. I presume even with this version I would still have to alter the line beginning "utility/Adafruit etc to include _ MS in front of the _PWMServo etc to suit the code I have for my motor shield.

 

Geoff

 

Hi Geoff, sorry yes, i keep forgetting to update that, it compiles ok on my system as i have the earlier drivers installed.

 

 

Ray.

Link to post
Share on other sites

  • RMweb Gold

I have just installed the new 'streamlined' sketch and all is working just hunky dorey. Thank you Ray, Ian and all who have contributed to this thread. You have all enabled me to move from a frustratingly unreliable turntable to a really useful unit.

Thank you all very much indeed.

 

Geoff

Link to post
Share on other sites

I've just discovered this thread, and I was wondering whether there was a hardware update from the original post. I've only just started to build my railway, and have a Peco LK-55 turntable, and this all sounds ideal for my purposes. I will be having 4 roads under DCC control.

 

Cheers, Simon

Link to post
Share on other sites

I've just discovered this thread, and I was wondering whether there was a hardware update from the original post. I've only just started to build my railway, and have a Peco LK-55 turntable, and this all sounds ideal for my purposes. I will be having 4 roads under DCC control.

 

Cheers, Simon

 

 

Hi Simon, no the hardware is the same.  Some others have used a different Stepper Driver to the Adafruit Motor Shield but that will require a modified Arduino Sketch to my original postings. You might note that post 512 has an updated sketch which removes power from the stepper after reaching it's position but that only works for a 180 single road turntable. I'll update the 4 road sketch and post here shortly.

 

Keep us posted on your progress.

 

Ray.

Link to post
Share on other sites

Hi Ray, Don't know what happened then! Thanks for letting me know about the hardware. Started buying off eBay and RS for the bits. Downloaded Arduino software. Looking forward to getting to grips with the programming!

 

Cheers, Simon

  • Like 1
Link to post
Share on other sites

Hi Ray, Don't know what happened then! Thanks for letting me know about the hardware. Started buying off eBay and RS for the bits. Downloaded Arduino software. Looking forward to getting to grips with the programming!

 

Cheers, Simon

Hi Simon,

Have a look at posts 417 and 425, they relate to some updates for the software downloads for the Adafruit Shield.

 

Ray.

Link to post
Share on other sites

Hi, did you ever design a circuit board from the post #8?

 

Cheers, Simon

No, never got around to it, but Ian Jeffery has a DCC interface board. Send him a PM.

 

Edit: Looks like he may be selling them through his website www.dccinterface.com

Edited by tender
Link to post
Share on other sites

I have had a fair bit of interest in the board I made.

Pricing is as follows:

 

Bare board - £20 Incl. P&P

Complete kit (less Nano but including A4988) unassembled - £30 Incl. P&P

Complete kit (less Nano but including A4988) assembled and tested- £40 Incl. P&P

 

Comparable pricing with Uno and Adafruit shield pricing but in a neater package with a DCC interface. :)

I have a few boards/kits left and if there is interest I will get some more in. I may start using the Micro Pro board as it has more interrupts (the Nano and UNO only have 2 I/O ports capable of interrupt!).

It will require some minor design changes but it is possible to hook up some of the I/O to pins to enable them to be user configured.

 

If anyone has any requests I might look at doing other DCC Arduino project PCB boards for lights or signalling?

 

Where is the best/most convenient place to upload my AccelStepper libraries with 'setBacklash'?

 

Regards,

Hi, Seems like I needed to be validated first, I know this is late in the day, have just found this all, Any chance you have any bare boards available?

 

thanks

Dion

Link to post
Share on other sites

Hi Ray, Don't know what happened then! Thanks for letting me know about the hardware. Started buying off eBay and RS for the bits. Downloaded Arduino software. Looking forward to getting to grips with the programming!

 

Cheers, Simon

Hi. I now have all the hardware except the Hall sensor which is due next week. Only other question I have is which 9v power supply would you recommend?

 

Cheers, Simon

Link to post
Share on other sites

Hi. I now have all the hardware except the Hall sensor which is due next week. Only other question I have is which 9v power supply would you recommend?

 

Cheers, Simon

Hi Simon, I used a 12v supply rated at 1 amp, although you could get away with a 12v 500ma supply.

 

https://www.maplin.co.uk/p/12v-500ma-acdc-power-supply-n93ju?cmpid=ppc:pim_products:pla:google&gclid=EAIaIQobChMI9ZjI6-H11gIV0xbTCh3oWg-gEAQYAiABEgImKfD_BwE&gclsrc=aw.ds

Edited by tender
Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...