Jump to content
 

DCC Controlled (PECO) Turntable Project using a Arduino Uno


Recommended Posts

  • 4 weeks later...
  • 2 months later...

Firstly I would like to thank Ray for his hard work in starting off this excellent post! also for Eric and friends for the various coding updates..  I have made a few changes to the code and managed to get a working turntable on my layout, including an OLED display to show the position and head/tail indication.  I only have 4 positions on my turntable and I didn't use the servo brake or manual pot but left these functions in.

 

The display I used was a 1.3" I2C IIC Serial 128X64 OLED LCD LED Display Module Digital for Arduino W which can be obtained easily on eBay... the driver for this is U8glib.h https://code.google.com/p/u8glib/ and the other components as mentioned by others I ordered from Proto-pic.

 

The revised coding is as follows, pictures to follow...

 

Jonathan

////////////////////////////////////////////////////////////////////////////////
//
//   DCC Turntable Rev 17 9 Jan 2015
//   based on code from rmweb.co.uk forum - edited by J.Luce
//   Program functions:
//     "Real World" interface
//     2- N.O. Push buttons to enable move to "Head" or "Tail"
//     1- 10k Continuous turn POT to select track.
//     1- N.O. Reset button on fascia
//     Use digital inputs on 6 & 7 to stepforward and backward and 
//       read out in the serial monitor so that you can program easier.
//     Release & Servo Brake function works with brake and release function.
//     Route positioning not taking shortest route to next location- (i.e. Tk.1 to Tk. 10 would be through 0)
//     Always approaches a track from the same direction to account for gear/mechanical lash/slop.
//       if the table was going CW to pos. 1 it approaches value B and stops
//       if the table was going CCW to Pos 1 it should go past B a (value B-X) and then go CW to B.
//     Added a (commented out)set up tool in the "loop" section of the code to set up the POT on the fascia panel.
//       this let's you align the POT to the markings on the panel.  Uncomment to use, then re-comment to hide.
//     Set up tool in the "loop" section of the code to set up the Brake Servo using the POT on the fascia panel. 
//       this let's you find the optimal Release and Brake position for the servo brake.  Uncomment to use, then re-comment to hide.
//     Added u8g display to show track position and heading, initialise at startup
//     Move to track 0 "Head" at startup
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
//
// DCC Turntable Control Routines

#include <DCC_Decoder.h>
#include <AccelStepper.h>
#include <Wire.h>
#include <Adafruit_MotorShield.h>
#include "utility/Adafruit_PWMServoDriver.h"
#include <Servo.h>            //servo library reference
#include "U8glib.h"

// setup u8g object, please remove comment from one of the following constructor calls
// IMPORTANT NOTE: The following list is incomplete. The complete list of supported 
// devices with all constructor calls is here: http://code.google.com/p/u8glib/wiki/device

U8GLIB_SH1106_128X64 u8g(U8G_I2C_OPT_DEV_0|U8G_I2C_OPT_FAST);	// Dev 0, Fast I2C / TWI

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Defines and structures
//
#define kDCC_INTERRUPT            0

typedef struct
{
    int               address;                // Address to respond to
   
} DCCAccessoryAddress;

DCCAccessoryAddress gAddresses[5];          // Allows 4 dcc addresses: [XX] = number of addresses you need (including 0).

const unsigned long releaseTimeout_ms = 2000;      //reduced to 2 seconds for now    
const long MOTOR_STEP_COUNT = 200 * 16;	            //number of steps for a full rotation
       
//new stuff
boolean tableTargetHead = false;        //the new variable for Head/Tail Position either from DCC or Analog
int tableTargetPosition = 0;            //the new variable for Table Postition either from DCC or Analog
boolean newTargetLocation = false;
boolean buttonPushedHead = false;
boolean buttonPushedTail = false;
boolean inMotionToNewTarget = false;
boolean isReleased = false;		// isReleased tries to make sure the motor is not continuously released
unsigned long stepperLastMoveTime = 0;
const long MOTOR_OVERSHOOT = 10;        // the amount of overshoot/ lash correction when approaching from CCW
int overshootDestination = -1;

//Servo Stuff
Servo brakeservo;  // create servo object to control a servo
const int servoBrake = 9;  //value for brake position
const int servoRelease = 2;  //value for release position

//Programming button variables
boolean programmingMode = false;
boolean programmingModeMoveForward = true;	//If in programming mode, are we moving forward?  
unsigned long programmingLastMoveMillis = 0;	//When was the last programming move done?
const int programRotateDelay = 100;			//Delay between steps in ms while holding button

//location variables
const int A = 144;          //TT Track 0-  Head
const int B = 328;          //TT Track 1-  Head
const int C = 482;          //TT Track 2-  Head
const int D = 632;          //TT Track 3-  Head
const int N = 1745;         //TT Track 0-  Tail
const int O = 1928;         //TT Track 1-  Tail
const int P = 2080;         //TT Track 2-  Tail
const int Q = 2230;         //TT Track 3-  Tail

const int PositionTrackHead[] = { A, B, C, D };
const int PositionTrackTail[] = { N, O, P, Q };

////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//
// 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(BACKWARD, MICROSTEP);
}
void backwardstep2() {  
  myStepper2->onestep(FORWARD, MICROSTEP);
}
void release2()   {
  myStepper2->release();
}

// Now we'll wrap the stepper in an AccelStepper object  

AccelStepper stepper2 = AccelStepper(forwardstep2, backwardstep2);

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Decoder Initiation 
//
void ConfigureDecoder()
{                                    //Put all the decoder #'s you need here.  Remember to change
                                     //DCCAccessoryAddress gAddresses[XX];(above) where XX = number of addresses you need. 
    gAddresses[0].address = 200;      
    gAddresses[1].address = 201;      
    gAddresses[2].address = 202;
    gAddresses[3].address = 203;
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// 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;
    
    for(int i=0; i<(int)(sizeof(gAddresses)/sizeof(gAddresses[0])); i++)
    {
        if( address == gAddresses[i].address )
        { 
 
            Serial.println("");  
            Serial.print("DCC addr: ");
            Serial.print(address,DEC);
            Serial.print("   Head/Tail = (1/0) : ");
            Serial.println(enable,DEC);
                                  
			//new stuff
                        tableTargetHead = enable;
                        tableTargetPosition = i;

                        //picture loop
                        u8g.firstPage();  
                        do {
                          draw(tableTargetPosition, tableTargetHead);
                        } while( u8g.nextPage() ); 

			//New packet and we have a new target location, set the flag
			newTargetLocation = true;
                        doStepperMove();   
			
  			// old location for if/else statements
		}
	}
}

/////////////////////////////////////////////////////////////////////////////
//
//  draw ug8 display
//  

void draw(int address, boolean enable) {
  // graphic commands to redraw the complete screen should be placed here  
  u8g.setFont(u8g_font_unifont);
  u8g.setPrintPos(20, 25);
  u8g.print("Position ");
  u8g.print(address,DEC);
  u8g.setPrintPos(20, 45); 
  if (enable)
  { 
    u8g.print("Head");
  }
  else
  {
    u8g.print("Tail");
  }
  u8g.drawRFrame(0,0,128,64,8);
}
      
/////////////////////////////////////////////////////////////////////////////
//
//  readAnalogLocation() Reads the pot input on analog pin 1, displays some
//  information out the serial, and sets the target position variable
//

int readAnalogLocation()
{
	int potDisp = analogRead(1);
	int potOut = potDisp / 79; //1023 / 13

	Serial.println("");
        Serial.print("Analog Location: ");
	Serial.print("Track # ");
	Serial.print(potOut, DEC);
	Serial.print("   Head/Tail = (1/0) : ");
	Serial.println(tableTargetHead, DEC);

	//tableTargetPosition = potOut;
	return potOut;
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Subroutine: doStepperMove()
//	 Moves the stepper based on location inputs, calls up "SetStepperTargetLocation()"
//
///////////////////////////////////////

void doStepperMove()
{

        // Run the Stepper Motor //
        stepper2.run();

	boolean isInMotion = (abs(stepper2.distanceToGo()) > 0);
	boolean newTargetSet = false;

	// If there is a new target location, set the target
	if (newTargetLocation)
	{
		Serial.println("Moving to New Target Location...");
		SetStepperTargetLocation();
		newTargetSet = true;
	}

	if (inMotionToNewTarget)
	{
		if ((!isInMotion) && (!newTargetSet))
		{
			Serial.print("Not Moving!  DtG: ");
			Serial.print(stepper2.distanceToGo());
			Serial.print(" TP: ");
			Serial.print(stepper2.targetPosition());
			Serial.print(" CP: ");
			Serial.print(stepper2.currentPosition());
			Serial.print(" S: ");
			Serial.print(stepper2.speed());
			Serial.println();
		}
				//release the brake
                                brakeservo.write(servoRelease);
                                delay (5);  
		inMotionToNewTarget = isInMotion;
	}
	else
	{
		if (programmingMode)
		{
			//If we are programming, do that move
				//release the brake
                                brakeservo.write(servoRelease);
                                delay (5);  
        
                        if ((millis() - programmingLastMoveMillis) >= programRotateDelay)
			{
				programmingLastMoveMillis = millis();
				stepper2.move(programmingModeMoveForward ? 1 : -1);
                                
                                Serial.println("");
				Serial.print("Programming mode, Current location: ");
				Serial.println(stepper2.currentPosition());
		                int potDisp = analogRead(1);
		                int potOut = potDisp / 79; //1023 / 13
		                Serial.print("Analog Location: ");
                                Serial.print("Track # ");
		                Serial.println(potOut, DEC);
		                delay(45);
			}
		}
		if ((stepper2.currentPosition() % MOTOR_STEP_COUNT) == 0)
		{
    		        //setCurrentPosition seems to always reset the position to 0, ignoring the parameter
			Serial.print("Current location: ");
			Serial.print(stepper2.currentPosition());
			Serial.println(" % STEPCOUNT.  Why here?");
		}
	}
                      //stepper timer subroutine came from here.
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Subroutine: SetStepperTargetLocation()
//     Takes the global variables: tableTargetHeadOrTail, and tableTargetPosition, and sets the stepper2
//   object moveTo() target position in steps-  inserts values back into "doStepperMove()"
//
///////////////////////////////////////

void SetStepperTargetLocation()
{
    int newTargetLoc = -1;
    if (tableTargetHead)
    {    //use head location variable
        {
            newTargetLoc = PositionTrackHead[tableTargetPosition];
            inMotionToNewTarget = true;
        }
    }
    else
    {    //use tail location variable
        {
            newTargetLoc = PositionTrackTail[tableTargetPosition];
            inMotionToNewTarget = true;
        }
    }

    if (newTargetLoc > 0)
    {
        int currentLoc = stepper2.currentPosition();
        int mainDiff = newTargetLoc - currentLoc;
        if (mainDiff > (MOTOR_STEP_COUNT / 2))
        {
            mainDiff = mainDiff - MOTOR_STEP_COUNT;
        }
        else if (mainDiff < (-MOTOR_STEP_COUNT / 2))
        {
            mainDiff = mainDiff + MOTOR_STEP_COUNT;
        }

        if (mainDiff < 0)
        {
            mainDiff -= MOTOR_OVERSHOOT;
            overshootDestination = MOTOR_OVERSHOOT;
        }
        stepper2.move(mainDiff);
    }
    programmingMode = false;
    newTargetLocation = false;
  }
 
//////////////////////////////////////////////////////////////////////////////////////////////////
//
//  Stepper Timer sub routine this runs from the main loop. It also supports the release function.
//
//////////////////////////////////////////////////////////////////////////////////////////////////

void stepperTimer()
{
    // Run the Stepper Motor //
    stepper2.run();
       
    boolean isInMotion = (abs(stepper2.distanceToGo()) > 0);
    //Check if we have any distance to move for release() timeout.  Can check the
    // buffered var isInMotion because we also check the other variables.
    if (isInMotion || programmingMode )
    {
        //We still have some distance to move, so reset the release timeout
        stepperLastMoveTime = millis();
        isReleased = false;
    }
    else
    {
        if (!isReleased)
        {
            if (overshootDestination > 0)
            {
                stepper2.move(overshootDestination);
                overshootDestination = -1;
            }
            if (((millis() - stepperLastMoveTime) >= releaseTimeout_ms))
            {
                //If isReleased, don't release again.
                isReleased = true;
                Serial.print ("Relative Current Position: ");
                Serial.print(stepper2.currentPosition());    //shows position the table thinks it is at (how it got here)

                int currentLoc = stepper2.currentPosition();    // Resets the positon to the actual positive number it should be
                currentLoc = currentLoc % MOTOR_STEP_COUNT;
                if (currentLoc < 0)
                {
                    currentLoc += MOTOR_STEP_COUNT;
                }
                stepper2.setCurrentPosition(currentLoc);
                stepper2.moveTo(currentLoc);
                
                Serial.print ("    Actual Current Position: ");
                Serial.println(stepper2.currentPosition());    // shows the position value corrected.

                //Set the servo brake
                brakeservo.write(servoBrake);
                delay(750);

                //release the motor
                release2();
                Serial.println("    Brake Set & Motor Released ");
            }
        }
    }
}

///////////////////////////////////////////////////////
//
//  Check Programming Buttons-  look for either of the programming buttons being pushed
//

void checkProgrammingButtons()
{
	programmingMode = false;
	bool buttonPushedProgUp = (digitalRead(6) == LOW);
	bool buttonPushedProgDown = (digitalRead(7) == LOW);

	//If one button is pushed, but not both
	if ((buttonPushedProgDown || buttonPushedProgUp) && !(buttonPushedProgDown && buttonPushedProgUp))
	{
		programmingMode = true;
		programmingModeMoveForward = buttonPushedProgUp;
	    doStepperMove();
        }
}

///////////////////////////////////////////////////////////////
// Manual move to using the pushbuttons and POT
//

void checkManualButtons()
{
	//Read the Head button input
	if (digitalRead(4) == LOW)
	{
		buttonPushedHead = true;
	}
	else if (buttonPushedHead)
	{
		//Button was pushed, but is not being pushed now
		//Clear pushed variable
		buttonPushedHead = false;
		//Set the target head variable
		tableTargetHead = true;
		//Read the analog location
		tableTargetPosition = readAnalogLocation();

		//Then set the new target flag
		newTargetLocation = true;
          doStepperMove();
	}

	//Read the Tail button input
	if (digitalRead(5) == LOW)
	{
		buttonPushedTail = true;
	}
	else if (buttonPushedTail)
	{
		//Button was pushed, but is not being pushed now
		//Clear pushed variable
		buttonPushedTail = false;
		//Set the target head variable
		tableTargetHead = false;
		//Read the analog location
		tableTargetPosition = readAnalogLocation();

		//Then set the new target flag
		newTargetLocation = true;
          doStepperMove();  
	}
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//
// Setup
//

void setup()
{
	Serial.begin(9600);

	AFMStop.begin(); // Start the shield

        //servo brake release before stepp moves
        brakeservo.attach(10);  // attaches the servo on pin 10 to the servo object
        brakeservo.write(servoRelease);
        delay (30);

        //initial display
        tableTargetHead = true;
        tableTargetPosition = 0;

        u8g.firstPage();  
        do {
        draw(tableTargetPosition, tableTargetHead);
        } while( u8g.nextPage() ); 

	//configure pin3 as an input and enable the internal pull-up resistor
	pinMode(3, INPUT_PULLUP);		//Hall Effect sensor: to reset position on startup
	//configure pin4 as an input and enable the internal pull-up resistor
	pinMode(4, INPUT_PULLUP);		//Head button
	//configure pin5 as an input and enable the internal pull-up resistor
	pinMode(5, INPUT_PULLUP);		//Tail button
	//configure pin6 as an input and enable the internal pull-up resistor
	pinMode(6, INPUT_PULLUP);		//Programming: Move forward single step
	//configure pin7 as an input and enable the internal pull-up resistor
	pinMode(7, INPUT_PULLUP);		//Programming: Move reverse single step

	//read the sensoron Dig I/O #3 (open collector type- Hall Effect sensor) value into a variable
	int sensorVal = digitalRead(3);

	//set stepper motor speed and acceleration 
	stepper2.setMaxSpeed(80.0);
	stepper2.setAcceleration(10.0);

	// if near reference point move away
	while (sensorVal == LOW) {
		sensorVal = digitalRead(3);
		forwardstep2();
		delay(25);
		Serial.println("Stepper Home");
	}

	// step backward to sensor index point
	while (sensorVal == HIGH) {
		sensorVal = digitalRead(3);
		backwardstep2();
		delay(50);
	}

        //when home- sets brake
        delay (500);
        brakeservo.write(servoBrake);

       //initial track position 0 head
       newTargetLocation = true;
       doStepperMove();   

       
   DCC.SetBasicAccessoryDecoderPacketHandler(BasicAccDecoderPacket_Handler, true);
   ConfigureDecoder();
   DCC.SetupDecoder( 0x00, 0x00, kDCC_INTERRUPT );
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Main loop
//

void loop()
{
   static int addr = 0;
    
        ////////////////////////////////////////////////////////////////
        // Loop DCC library

    DCC.loop();

        ////////////////////////////////////////////////////////////////
        // Bump to next address to test
    if( ++addr >= (int)(sizeof(gAddresses)/sizeof(gAddresses[0])) )
    {
        addr = 0;
    }

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//  To configure the POT (uncomment this text)
	//configure alalog pin 1 as an input
	
        //  int potDisp = analogRead(1);
	// 
	//  int potOut = potDisp / 79; //1023 / 13
	//     delay(1000);  
	//     Serial.print("Analog Location: ");
	//     Serial.println(potOut);
	
        // end of POT configuration- re-comment this section to hide during normal use
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//  To configure the Servo Brake (uncomment this text) 
	//configure alalog pin 1 as an input
	
        //    int potDisp = analogRead(1);            // reads the value of the potentiometer (value between 0 and 1023)
        //    int potOut = map(potDisp, 0, 1023, 0, 50);     // scale it to use it with the servo (value between 0 and 180)
        //    brakeservo.write(potOut);                  // sets the servo position according to the scaled value
        //    delay(1000); 
	//    Serial.print("Servo Position Value: ");
	//    Serial.println(potOut);
        
	// end of POT configuration- re-comment this section to hide during normal use
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

	//Tests to see if the manual move buttons are pressed, if so set the needed flags
          checkManualButtons();

	//Checks the programming buttons, if depressed then set the right flags
          checkProgrammingButtons();

	//StepperAccel.Run() in this function
          stepperTimer();

}

Link to post
Share on other sites

 

Firstly I would like to thank Ray for his hard work in starting off this excellent post! also for Eric and friends for the various coding updates..  I have made a few changes to the code and managed to get a working turntable on my layout, including an OLED display to show the position and head/tail indication.  I only have 4 positions on my turntable and I didn't use the servo brake or manual pot but left these functions in.

 

The display I used was a 1.3" I2C IIC Serial 128X64 OLED LCD LED Display Module Digital for Arduino W which can be obtained easily on eBay... the driver for this is U8glib.h https://code.google.com/p/u8glib/ and the other components as mentioned by others I ordered from Proto-pic.

 

The revised coding is as follows, pictures to follow...

 

Jonathan

 

 

Jonathan

 

Thank you so much to post the revision 17 here.
This is what I was working for to merge 2 or 3 options in one sketch.
 
I hope someone can still contribute to the enrichment of this work, and very rich in informations.
 
I would like to thank to Ray to begin this project in a so detailed manner and to all that had give your contribution.  
It was a fun and brilliant project.

Sorry for my english.

 

 

 

JB

Edited by jbsorocaba
Link to post
Share on other sites

I have built the DCC circuit Board and thanks to everyone especially Ray for this thread.

I have hit a stumbling block in so much as I have Digitrax and I don't seem to be able to program the DCC board to Accessory 200?

Any ideas how I can do that in digitrax please?

Thanks

Barry

Link to post
Share on other sites

Hi Guys, very good to see you all putting this thread to good use. I'll be picking up some of your modifications when I get around to continuing with my T/T and adding programable positions. But that's for later.

 

Barry, you don't have to use accessory address 200, just change the code for the addresses you prefer in lines 133-137 of Jonathans post above.

 

Ray.

Edited by tender
Link to post
Share on other sites

Ray thanks for coming back on.

A few Q's - why has Jonathan got 4 addresses?

I only want my turntable to turn 180 degrees each time. ( only one entry/exit) How can I change Jonathons sketch to do that?

I am very naive at programming!!!

Thank you for all your assistance.

Barry

Link to post
Share on other sites

Ray thanks for coming back on.

A few Q's - why has Jonathan got 4 addresses?

I only want my turntable to turn 180 degrees each time. ( only one entry/exit) How can I change Jonathons sketch to do that?

I am very naive at programming!!!

Thank you for all your assistance.

Barry

Hi Barry,

Each address is one road for the turntable, thus setting accessory decoder address 200 to Normal sets the turntable to this road and Reverse turns it 180 degrees.

Jonathans code has 4 roads hence 4 addresses, just remove or comment out lines 135-137 if you only want one.

Change the number in line 134 from 200 to the accessory address you want to use.

Ray.

Link to post
Share on other sites

 

Firstly I would like to thank Ray for his hard work in starting off this excellent post! also for Eric and friends for the various coding updates..  I have made a few changes to the code and managed to get a working turntable on my layout, including an OLED display to show the position and head/tail indication.  I only have 4 positions on my turntable and I didn't use the servo brake or manual pot but left these functions in.

 

The display I used was a 1.3" I2C IIC Serial 128X64 OLED LCD LED Display Module Digital for Arduino W which can be obtained easily on eBay... the driver for this is U8glib.h https://code.google.com/p/u8glib/ and the other components as mentioned by others I ordered from Proto-pic.

 

The revised coding is as follows, pictures to follow...

 

Jonathan

Jonathan-

 

Great stuff!  Glad to see that some use is becoming of the code.  I have been tweaking the code as well.  I made some changes this past weekend that I really like.  I will post a video soon of the unit in operation. 

 

-Eric

Link to post
Share on other sites

Thanks Ray!

I guarantee I'll be back with more questions!

I found the Aduino and Adafruit easy to sort but the DCC Circuit was my first bash at electronics!

I'm not convinced it's working correctly as when I did the DCC Monitor test, the data scrolled but it was all zeros!!

 

Barry

Link to post
Share on other sites

All-

 

As hinted in the last post, I have made some significant changes to the code I am running.  I changed the stepper from direct drive to a gearbox drive (50:1) eliminated the brake, and did some other changes.  I am really happy with the results.  I wrote some JMRI code to just keep calling up DCC accessory codes (not in order) with about 2 min in between each request.  Then at the end of the day, I stopped the code and called up each track to see is there was any noticeable drift over time.  I did notice a little, but nothing significant.  That was about 120 moves over 4 hours and in the end it still lined up correctly.  What drew me to the gearbox, was that after about 10 moves with the direct drive and a heavy locomotive, the previous drive had a noticeable drift (or loss of resolution- ie- skipped steps).  I really liked the "microstepping" but the torque I have now at "Interleave" stepping is significant.  The motor also runs significantly cooler.  I want to still try and overdrive the i2c clock, but I can't get that to work.  That would allow me to go back to microstepping, but at higher speeds.

 

So- Below is my code.  Have fun.

////////////////////////////////////////////////////////////////////////////////
//
//   February 1st 2015- Cleaned up code- ready for distribution again.
//   November 22nd 2014- working on the i2c bus speed problem.- same file name
//   October 28th 2014-  change to 50:1 gear box.  change to Interleave for motor resolution adjust software.
//
////////////////////////////////////////////////////////////////////////////////
//
//   On30_Module_DCC Turntable Rev_22e   February_1_2015
//        based on code from rmweb.co.uk forum
//          edited by E.Sitiko with programming help from D.Whetten
//        Program functions desired are:
//            14 road turntable  (works) 
//            DCC addresses 200 to 214 (works!)
//            clean up code to make changes to Position easy (works)
//            "Real World" interface
//                2- N.O. Push buttons to enable move to "Head" or "Tail" (works)
//                1- 10k Continuous turn POT to select track. (works)
//                1- N.O. Reset button on fascia  (works)
//               Use digital inputs on 6 & 7 to stepforward and backward and 
//               read out in the serial monitor so that you can program easier. (works)
//            "Release" function- to release power to the motor when idle. (works!!)
//            Route positioning not taking shortest route to next location- (i.e. Tk.1 to Tk. 10 would be through 0)  (works)
//            Always approaches a track from the same direction to account for gear/mechanical lash/slop. (works)
//                      if the table was going CW to pos. 1 it approaches value B and stops
//                      if the table was going CCW to Pos 1 it should go past B a (value B-X) and then go CW to B.
//
//            Added a (commented out)set up tool in the "loop" section of the code to set up the POT on the fascia panel.
//                this let's you align the POT to the markings on the panel.  Uncomment to use, then re-comment to hide.  (works)
//
//   (FUTURE)  DCC Address 200 or Analog 0 = continuous slow rotation, based on "Head" or "Tail" (does not work now)
//
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
//
// DCC Turntable Control Routines

#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[15];          // Allows 15 dcc addresses: [XX] = number of addresses you need (including 0).

const unsigned long releaseTimeout_ms = 900000;         //timer set to 15 min for now - this is the release timer
const unsigned long Count_Reset_Timeout_ms = 500;      //timer for reseting position following a move set to 1/2 sec for now 

const long MOTOR_STEP_COUNT = 20000;	            //number of steps (200 * 4(Interleave)) * 50 for a full turntable rotation 20,000
       
//new stuff
boolean tableTargetHead = false;        //the new variable for Head/Tail Position either from DCC or Analog
int tableTargetPosition = 0;            //the new variable for Table Postition either from DCC or Analog
boolean newTargetLocation = false;
boolean buttonPushedHead = false;
boolean buttonPushedTail = false;
boolean inMotionToNewTarget = false;
boolean isReleased = false;		// isReleased tries to make sure the motor is not continuously released
boolean isStopped = false;              // isStopped is the boolean to enable the count reset timer to function.
unsigned long stepperLastMoveTime = 0;
const long MOTOR_OVERSHOOT = 50;        // the amount of overshoot/ lash correction when approaching from CCW (best guess 50- 1/8 revolution of the worm gear)
int overshootDestination = -1;

//Programming button variables
boolean programmingMode = false;
boolean programmingModeMoveForward = true;	//If in programming mode, are we moving forward?  
unsigned long programmingLastMoveMillis = 0;	//When was the last programming move done?
const int programRotateDelay = 50;			//Delay between steps in ms while holding button

//Do display rotation
const int displayRotateDelay = 5;	//This is the minimum delay in ms between steps of the stepper motor
boolean displayRotating = false;		//Is the "Display Rotate" function enabled?
boolean displayRotatingCW = true;		//In Display Rotate mode, are we rotating CW or CCW?  
unsigned long displayRotatingLastMoveMillis = 0;

//location variables
const int A = 150;           //TT Track 0-  Head
const int B = 736;           //TT Track 1-  Head         
const int C = 1589;          //TT Track 2-  Head     
const int D = 3045;          //TT Track 3-  Head     
const int E = 3997;          //TT Track 4-  Head    
const int F = 4704;          //TT Track 5-  Head
const int G = 5644;          //TT Track 6-  Head
const int H = 12548;         //TT Track 7-  Head
const int I = 13400;         //TT Track 8-  Head
const int J = 14150;         //TT Track 9-  Head
const int K = 16090;         //TT Track 10- Head
const int L = 16801;         //TT Track 11- Head
const int M = 17513;         //TT Track 12- Head
const int N = 18600;         //TT Track 13- Head
const int O = 19530;         //TT Track 14- Head

const int P = 10281;          //TT Track 0-  Tail
const int Q = 10740;          //TT Track 1-  Tail    
const int R = 11586;          //TT Track 2-  Tail   
const int S = 13042;          //TT Track 3-  Tail    
const int T = 13984;          //TT Track 4-  Tail 
const int U = 14681;          //TT Track 5-  Tail
const int V = 15624;          //TT Track 6-  Tail
const int W = 2549;           //TT Track 7-  Tail
const int X = 3401;           //TT Track 8-  Tail
const int Y = 4160;           //TT Track 9-  Tail
const int Z = 6097;           //TT Track 10- Tail
const int AA = 6809;          //TT Track 11- Tail
const int AB = 7531;          //TT Track 12- Tail
const int AC = 8605;          //TT Track 13- Tail
const int AD = 9546;          //TT Track 14- Tail

const int PositionTrackHead[] = { A, B, C, D, E, F, G, H, I, J, K, L, M, N, O };
const int PositionTrackTail[] = { P, Q, R, S, T, U, V, W, X, Y, Z, AA, AB, AC, AD };

////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//
// 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! (400 Interleave steps/revolution * 50:1 gear box)
void forwardstep2() {  
  myStepper2->onestep(FORWARD, INTERLEAVE);  //changed direction due to motor rewire
}
void backwardstep2() {  
  myStepper2->onestep(BACKWARD, INTERLEAVE);   //changed direction due to motor rewire
}
void release2()   {
  myStepper2->release();
}


// Now we'll wrap the stepper in an AccelStepper object  

AccelStepper stepper2 = AccelStepper(forwardstep2, backwardstep2);

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Decoder Initiation 
//
void ConfigureDecoder()
{                                    //Put all the decoder #'s you need here.  Remember to change
                                     // DCCAccessoryAddress gAddresses[XX];(above) where XX = number of addresses you need. 
    gAddresses[0].address = 200;      
    gAddresses[1].address = 201;      
    gAddresses[2].address = 202;
    gAddresses[3].address = 203;
    gAddresses[4].address = 204;
    gAddresses[5].address = 205;
    gAddresses[6].address = 206;
    gAddresses[7].address = 207;
    gAddresses[8].address = 208;
    gAddresses[9].address = 209;
    gAddresses[10].address = 210;
    gAddresses[11].address = 211;
    gAddresses[12].address = 212;
    gAddresses[13].address = 213;
    gAddresses[14].address = 214;
    
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// 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;
    
    for(int i=0; i<(int)(sizeof(gAddresses)/sizeof(gAddresses[0])); i++)
    {
        if( address == gAddresses[i].address )
        { 
          
            Serial.println("");  
            Serial.print("DCC addr: ");
            Serial.print(address,DEC);
            Serial.print("   Head/Tail = (1/0) : ");
            Serial.println(enable,DEC);
                                  
			//new stuff
                        tableTargetHead = enable;
                        tableTargetPosition = i;

			//New packet and we have a new target location, set the flag
			newTargetLocation = true;
                        doStepperMove();   
			
  			// old location for if/else statements
		}
	}
}
      
/////////////////////////////////////////////////////////////////////////////
//
//  readAnalogLocation() Reads the pot input on analog pin 1, displays some
//  information out the serial, and sets the target position variable
//
int readAnalogLocation()
{
	int potDisp = analogRead(1);
	int potOut = potDisp / 73; //1023 / 14

	Serial.println("");
        Serial.print("Analog Location: ");
	Serial.print("Track # ");
	Serial.print(potOut, DEC);
	Serial.print("   Head/Tail = (1/0) : ");
	Serial.println(tableTargetHead, DEC);
	

	//tableTargetPosition = potOut;
	return potOut;
}


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Subroutine: doStepperMove()
//	 Moves the stepper based on location inputs, calls up "SetStepperTargetLocation()"
//
///////////////////////////////////////

void doStepperMove()
{

        // Run the Stepper Motor //
        stepper2.run();

	boolean isInMotion = (abs(stepper2.distanceToGo()) > 0);
	boolean newTargetSet = false;

	// If there is a new target location, set the target
	if (newTargetLocation)
	{
		Serial.println("Moving to New Target Location...");
		SetStepperTargetLocation();
		newTargetSet = true;
	}

	if (inMotionToNewTarget)
	{
		if ((!isInMotion) && (!newTargetSet))
		{
			Serial.print("Not Moving!  DtG: ");
			Serial.print(stepper2.distanceToGo());
			Serial.print(" TP: ");
			Serial.print(stepper2.targetPosition());
			Serial.print(" CP: ");
			Serial.print(stepper2.currentPosition());
			Serial.print(" S: ");
			Serial.print(stepper2.speed());
			Serial.println();
		}
		inMotionToNewTarget = isInMotion;
	}
	else
	{
		if (programmingMode)
		{
			//If we are programming, do that move
        
                        if ((millis() - programmingLastMoveMillis) >= programRotateDelay)
			{
				programmingLastMoveMillis = millis();
				stepper2.move(programmingModeMoveForward ? 5 : -5);    //Tried to change this to something like 5 steps- for programming
                                
                                Serial.println("");
				Serial.print("Programming mode, Current location: ");
				Serial.println(stepper2.currentPosition());
		                int potDisp = analogRead(1);
		                int potOut = potDisp / 73; //1023 / 14
		                Serial.print("Analog Location: ");
                                Serial.print("Track # ");
		                Serial.println(potOut, DEC);
		                delay(50); //sets delay between steps when using programming buttons
	
			}
		}
		//Only do display rotate if we aren't doing the programming move
		else if (displayRotating)
		{
			//Are we in "DisplayRotate" mode?  if so, do that..
                        if ((millis() - displayRotatingLastMoveMillis) >= displayRotateDelay)
			{
				displayRotatingLastMoveMillis = millis();
				stepper2.move(displayRotatingCW ? 1 : -1);
				Serial.print("Display rotate mode: ");
				Serial.println(stepper2.currentPosition());
			}
		}

		if ((stepper2.currentPosition() % MOTOR_STEP_COUNT) == 0)
		{
    		        //setCurrentPosition seems to always reset the position to 0, ignoring the parameter
			Serial.print("Current location: ");
			Serial.print(stepper2.currentPosition());
			Serial.println(" % STEPCOUNT.  Why here?");
		}
	}

                      //stepper timer subroutine came from here.
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Subroutine: SetStepperTargetLocation()
//     Takes the global variables: tableTargetHeadOrTail, and tableTargetPosition, and sets the stepper2
//   object moveTo() target position in steps-  inserts values back into "doStepperMove()"
//
///////////////////////////////////////
void SetStepperTargetLocation()
{
    int newTargetLoc = -1;
    if (tableTargetHead)
    {    //use head location variable
        if (tableTargetPosition == 0)
        {
            //Special case: Display Rotate
            displayRotating = true;
            displayRotatingCW = true;
           
            Serial.println("Entering display rotate mode, CW.");
        }
        else
        {
            displayRotating = false;
            newTargetLoc = PositionTrackHead[tableTargetPosition];
            inMotionToNewTarget = true;
        }
    }
    else
    {    //use tail location variable
        if (tableTargetPosition == 0)
        {
            //Special case: Display Rotate
            displayRotating = true;
            displayRotatingCW = false;

            Serial.println("Entering display rotate mode, CCW.");
        }
        else
        {
            displayRotating = false;
            newTargetLoc = PositionTrackTail[tableTargetPosition];
            inMotionToNewTarget = true;
        }
    }

    if (newTargetLoc > 0)
    {
        long currentLoc = stepper2.currentPosition();
        long mainDiff = newTargetLoc - currentLoc;
        if (mainDiff > (MOTOR_STEP_COUNT / 2))
        {
            mainDiff = mainDiff - MOTOR_STEP_COUNT;
        }
        else if (mainDiff < (-MOTOR_STEP_COUNT / 2))
        {
            mainDiff = mainDiff + MOTOR_STEP_COUNT;
        }

        if (mainDiff < 0)   //changed this to less than or equal to, to wake up the motor if you recall the track it is sitting on.
        {
            mainDiff -= MOTOR_OVERSHOOT;
            overshootDestination = MOTOR_OVERSHOOT;
        }
        stepper2.move(mainDiff);
        delay (30);
    }

    programmingMode = false;
    newTargetLocation = false;

  }
 
//////////////////////////////////////////////////////////////////////////////////////////////////
//
//  Stepper Timer sub routine this runs from the main loop. It also supports the release function.
//
//////////////////////////////////////////////////////////////////////////////////////////////////

void stepperTimer()
{
    // Run the Stepper Motor //
    stepper2.run();
       
    boolean isInMotion = (abs(stepper2.distanceToGo()) > 0);
    //Check if we have any distance to move for release() timeout.  Can check the
    // buffered var isInMotion because we also check the other variables.
    if (isInMotion || programmingMode || displayRotating)  // || newTargetSet)
    {
        //We still have some distance to move, so reset the release timeout
        stepperLastMoveTime = millis();
        isReleased = false;
        isStopped = false;
    }
    else
    {
        if (!isStopped)
        {
            if (overshootDestination > 0)
            {
                stepper2.move(overshootDestination);
                overshootDestination = -1;
            }

            if (((millis() - stepperLastMoveTime) >= Count_Reset_Timeout_ms))
            
            {
                isStopped = true;
                //   isReleased = true;
                Serial.print ("Relative Current Position: ");
                Serial.print(stepper2.currentPosition());    //shows position the table thinks it is at (how it got here)

                long currentLoc = stepper2.currentPosition();    // Resets the positon to the actual positive number it should be
                currentLoc = currentLoc % MOTOR_STEP_COUNT;
                if (currentLoc < 0)
                {
                    currentLoc += MOTOR_STEP_COUNT;
                }
                stepper2.setCurrentPosition(currentLoc);
                stepper2.moveTo(currentLoc);
                
                Serial.print ("    Actual Current Position: ");
                Serial.println(stepper2.currentPosition());    // shows the position value corrected.
            }
        }

        if (!isReleased)
          {
            if (((millis() - stepperLastMoveTime) >= releaseTimeout_ms))
            
            {
                //If isReleased, don't release again.
                isReleased = true;
                
                //release the motor
                release2();
                Serial.println("  Motor Released  ");
            }
        }
    }
}

///////////////////////////////////////////////////////
//
//  Check Programming Buttons-  look for either of the programming buttons being pushed
//
void checkProgrammingButtons()
{
	programmingMode = false;
	bool buttonPushedProgUp = (digitalRead(6) == LOW);
	bool buttonPushedProgDown = (digitalRead(7) == LOW);

	//If one button is pushed, but not both
	if ((buttonPushedProgDown || buttonPushedProgUp) && !(buttonPushedProgDown && buttonPushedProgUp))
	{
		programmingMode = true;
		programmingModeMoveForward = buttonPushedProgUp;
	    doStepperMove();  
        }

}

///////////////////////////////////////////////////////////////
// Manual move to using the pushbuttons and POT
//
void checkManualButtons()
{
	//Read the Head button input
	if (digitalRead(4) == LOW)
	{
		buttonPushedHead = true;
	}
	else if (buttonPushedHead)
	{
		//Button was pushed, but is not being pushed now
		//Clear pushed variable
		buttonPushedHead = false;
		//Set the target head variable
		tableTargetHead = true;
		//Read the analog location
		tableTargetPosition = readAnalogLocation();

		//Then set the new target flag
		newTargetLocation = true;
          doStepperMove();
	}

	//Read the Tail button input
	if (digitalRead(5) == LOW)
	{
		buttonPushedTail = true;
	}
	else if (buttonPushedTail)
	{
		//Button was pushed, but is not being pushed now
		//Clear pushed variable
		buttonPushedTail = false;
		//Set the target head variable
		tableTargetHead = false;
		//Read the analog location
		tableTargetPosition = readAnalogLocation();

		//Then set the new target flag
		newTargetLocation = true;
          doStepperMove();  
	}

}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//
// Setup
//
void setup()
{
	Serial.begin(9600);

        AFMStop.begin(); // Start the shield  //tried different values- liked the lack of noise with 4000- but not with interleave- no noticable change 

        //TWBR = ((F_CPU /400000L) - 16) / 2; // TWBR = ((F_CPU /400000L) - 16) / 2; // Change the i2c clock to 400KHz per chat group- didn't work still 75rpm.
	
        //configure pin3 as an input and enable the internal pull-up resistor
	pinMode(3, INPUT_PULLUP);		//Hall Effect sensor: to reset position on startup
	//configure pin4 as an input and enable the internal pull-up resistor
	pinMode(4, INPUT_PULLUP);		//Head button
	//configure pin5 as an input and enable the internal pull-up resistor
	pinMode(5, INPUT_PULLUP);		//Tail button
	//configure pin6 as an input and enable the internal pull-up resistor
	pinMode(6, INPUT_PULLUP);		//Programming: Move forward single step
	//configure pin7 as an input and enable the internal pull-up resistor
	pinMode(7, INPUT_PULLUP);		//Programming: Move reverse single step

	//read the sensoron Dig I/O #3 (open collector type- Hall Effect sensor) value into a variable
	int sensorVal = digitalRead(3);

	//set stepper motor speed and acceleration 
	stepper2.setMaxSpeed(500);        //values between 20 and 50 (experiment- 800 rpm= about 80 in real life with stepper in single, 
                                          //  or double, about 40rpm with Interleave, about 5rpm with microstep)
	stepper2.setAcceleration(25);    //values between 5 and 20. (accel experiment- 25)

	// if near reference point move away
	while (sensorVal == LOW) {
		sensorVal = digitalRead(3);
                forwardstep2();    //  Rewired motor- changed direction   
		delay(5);     //value is 5 
		Serial.println("Stepper Home");
	}

	// step backward to sensor index point
	while (sensorVal == HIGH) {
		sensorVal = digitalRead(3);
		backwardstep2();    //  Rewired motor- changed direction
		delay(50);  //value is 50
	}

        Serial.println("");
        Serial.println("United Railways- East Yard Turntable:  Ready for Use");
        Serial.println("");
    

   DCC.SetBasicAccessoryDecoderPacketHandler(BasicAccDecoderPacket_Handler, true);
   ConfigureDecoder();
   DCC.SetupDecoder( 0x00, 0x00, kDCC_INTERRUPT );
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Main loop
//
void loop()
{
   static int addr = 0;
    
        ////////////////////////////////////////////////////////////////
        // Loop DCC library
    DCC.loop();
    
        ////////////////////////////////////////////////////////////////
        // Bump to next address to test
    if( ++addr >= (int)(sizeof(gAddresses)/sizeof(gAddresses[0])) )
    {
        addr = 0;
    }

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//  To configure the POT (uncomment this text)
	//configure alalog pin 1 as an input
	
        //  int potDisp = analogRead(1);
	// 
        //  int potOut = potDisp / 73; //1023 / 14
	//     delay(1000);  
	//     Serial.print("Analog Location: ");
	//     Serial.println(potOut);
	
        // end of POT configuration- re-comment this section to hide during normal use
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

	//Tests to see if the manual move buttons are pressed, if so set the needed flags
          checkManualButtons();

	//Checks the programming buttons, if depressed then set the right flags
          checkProgrammingButtons();

	//StepperAccel.Run() in this function
          stepperTimer();  
}

On30_Module_DCC_Turntable_Rev_22e.ino

Link to post
Share on other sites

When I try to run Jonathon's sketch, I get an error message:

From Clipboard:

 

  This report would have more information with
  "Show verbose output during compilation"
  enabled in File > Preferences.
Arduino: 1.0.6 (Windows 7), Board: "Arduino Uno"
sketch_feb03b.ino:35:20: error: U8glib.h: No such file or directory
sketch_feb03b:41: error: 'U8GLIB_SH1106_128X64' does not name a type
sketch_feb03b.ino: In function 'void BasicAccDecoderPacket_Handler(int, boolean, byte)':
sketch_feb03b:172: error: 'u8g' was not declared in this scope
sketch_feb03b.ino: In function 'void draw(int, boolean)':
sketch_feb03b:193: error: 'u8g' was not declared in this scope
sketch_feb03b:193: error: 'u8g_font_unifont' was not declared in this scope
sketch_feb03b.ino: In function 'void setup()':
sketch_feb03b:511: error: 'u8g' was not declared in this scope
 
 
Any ideas please - it's gobble de to me!
 
Thanks 
Barry
Link to post
Share on other sites

When I try to run Jonathon's sketch, I get an error message:

From Clipboard:

 

  This report would have more information with

  "Show verbose output during compilation"

  enabled in File > Preferences.

Arduino: 1.0.6 (Windows 7), Board: "Arduino Uno"

sketch_feb03b.ino:35:20: error: U8glib.h: No such file or directory

sketch_feb03b:41: error: 'U8GLIB_SH1106_128X64' does not name a type

sketch_feb03b.ino: In function 'void BasicAccDecoderPacket_Handler(int, boolean, byte)':

sketch_feb03b:172: error: 'u8g' was not declared in this scope

sketch_feb03b.ino: In function 'void draw(int, boolean)':

sketch_feb03b:193: error: 'u8g' was not declared in this scope

sketch_feb03b:193: error: 'u8g_font_unifont' was not declared in this scope

sketch_feb03b.ino: In function 'void setup()':

sketch_feb03b:511: error: 'u8g' was not declared in this scope

 

 

Any ideas please - it's gobble de ###### to me!

 

Thanks 

Barry

Hi Barry, have you got the basic turntable working (first two pages of this thread). You said earlier you was having problems with the DCC interface, have you sorted this?

From the error messages it looks like you haven't installed the additional U8glib.h libraries required for the display module Jonathans code uses.

 

Ray.

Link to post
Share on other sites

Hi Ray,

Yes, I should have realised - it's for that read out thingy!!

 

No, I'm still struggling to get the DCC interface working. I've disconnected it and I'm just checking over it.

Also, not sure if the hall sensor is working? I'm using the same sensor as you but a smaller magnet (as its N Gauge)

Does it matters it's facing N or S pole to the sensor?

 

Excuse my poor knowledge!

 

Barry

Link to post
Share on other sites

I'm happy that the interface is built ok and all wires going to it are ok.

My problem seems to be centred around DCC as when I do the DC monitor test all the figures are zero.

It scrolls ok but it's just scrolling packets of zero.

When I run it through part 6 - it stops at the reference point but I can't budge it using the handset set to access 200 c or t

The digitrax system doesn't seem to recognise it.

I think I need a way to program the interface as accessory 200 from the digitrax handset - but that doesn't seem possible!

 

Barry

Link to post
Share on other sites

I'm happy that the interface is built ok and all wires going to it are ok.

My problem seems to be centred around DCC as when I do the DC monitor test all the figures are zero.

It scrolls ok but it's just scrolling packets of zero.

When I run it through part 6 - it stops at the reference point but I can't budge it using the handset set to access 200 c or t

The digitrax system doesn't seem to recognise it.

I think I need a way to program the interface as accessory 200 from the digitrax handset - but that doesn't seem possible!

Barry

Hi Barry, what Digitrax system do you have?
Link to post
Share on other sites

Hi Barry. Have you got the activate value alternating between 0 and 1 as indicated in part 6 (post 25)?

This should happen when you send accessory 200 c and t commands from your throttle.

If this is not happening it looks like you still may have a problem with the DCC interface circuit.

Ray.

Link to post
Share on other sites

YES, yes, yes, yes.......whoop whoop whoop!!!!!

Found the problem - poor DCC Connection from track!! (Spent all afternoon trying to make it work only for it to be a loose connection)!!

 

Many many thanks Ray!

 

Thanks also to Jonathon.

 

Video here:

 

Barry

  • Like 2
Link to post
Share on other sites

YES, yes, yes, yes.......whoop whoop whoop!!!!!

Found the problem - poor DCC Connection from track!! (Spent all afternoon trying to make it work only for it to be a loose connection)!!

Many many thanks Ray!

Thanks also to Jonathon.

Video here:

Barry

Well done Barry, looks like you're well on your way now. Beats the hell out of paying £300 plus for a commercial unit I saw at the weekend and that used a Peco T/T as well.

Ray.

Edited by tender
Link to post
Share on other sites

  • RMweb Premium

Ray

 

I'm some way off doing so at the moment but I guess it wouldn't be too difficult to do something similar to power a sector plate.

 

Presumably driving the sector plate at the pivot point would severely strain the motor so I'm thinking that I'd solder a nut to a piece of angle that I then run down a piece of threaded rod. The piece of angle would be bolted to the underside of the sector plate so that it is free to twist as the sector plate moves back and forth.

 

The stepper motor would be coupled to the end of the threaded rod and fixed to the baseboard on which the sector plate was mounted. Turning the stepper motor (shaft/spindle) would cause the threaded rod to turn and thus move the sector plate.

 

That is about the limit of my engineering capability.

 

All I appear to need is a means to be able to secure the stepper motor to the threaded rod - any ideas?

 

Your original sketch would appear to do the rest as I have no need to do anything other than allow the sector plate to travel backwards and forwards within a defined arc.

 

It sounds fairly simple so I must have over-looked something.

Link to post
Share on other sites

RayI'm some way off doing so at the moment but I guess it wouldn't be too difficult to do something similar to power a sector plate.Presumably driving the sector plate at the pivot point would severely strain the motor so I'm thinking that I'd solder a nut to a piece of angle that I then run down a piece of threaded rod. The piece of angle would be bolted to the underside of the sector plate so that it is free to twist as the sector plate moves back and forth.The stepper motor would be coupled to the end of the threaded rod and fixed to the baseboard on which the sector plate was mounted. Turning the stepper motor (shaft/spindle) would cause the threaded rod to turn and thus move the sector plate.That is about the limit of my engineering capability.All I appear to need is a means to be able to secure the stepper motor to the threaded rod - any ideas?Your original sketch would appear to do the rest as I have no need to do anything other than allow the sector plate to travel backwards and forwards within a defined arc.It sounds fairly simple so I must have over-looked something.

Hi Ray

Not sure I fully understand your concept, is the threaded rod perpendicular to the sector plate? If so you will have to allow for the arc described by the sector plate as the nut screws its way along the threaded rod.

To connect the threaded rod to the motor I would use a bellows connector as per the turntable.

Bellows Coupling (RS693-2467)

 

Hope this helps.

 

Ray.

Link to post
Share on other sites

  • RMweb Premium

Ray

 

With apologies to any engineers who may be watching . . . .

 

My original thinking was that the motor would be fixed horizontally with the spindle roughly at 90º to the centre line of the sector plate. The bracket on the underside of the sector plate would hold the horizontal threaded rod at a similar angle to the centre line but it would be able to turn clockwise/anti-clockwise on its securing bolt as the sector plate moves through the arc.

 

Thanks for the link to the bellows couplings. They're not something I've heard of before.

 

Likewise, for some reason I thought 6mm was the smallest diameter threaded rod easily available. I was wrong there, as B & Q (at least) appear to stock 4mm out of the rack - the vertical version of "Off the shelf"!

 

I can see it is time for some experimentation although it is unlikely to be for a while yet.

 

I may have missed it somewhere in one of the earlier posts but I wonder how easy it would be to use a rotary switch instead of DCC to select the position of the sector plate, a bit like using such a switch to select a specific road in a fan of sidings.

 

Thanks for starting the thread - excuse the pun - and thanks to the other contributors.

 

Edited to add . . .

 

I re-thought the idea again (after posting) and think that the motor's mount would also need to be free to turn both clockwise and anti-clockwise (albeit slightly) to maintain the straight line between the motor spindle and the threaded rod in the nut affixed to the bracket on the sector plate.

Edited by Ray H
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...