Jump to content
 

Help needed for a Arduino Servo Project


tjorch

Recommended Posts

Hi all, this is my 1st attempt at (I take no credit for the code/wiring) Arduino. This a Model railway project to move a Turnout by  a servo & light a LED at the press of a push button switch. I have made a Frizing image from a Jpeg picture image.

The help I need is;

The Wiring

1 is the push button wiring correct
2 is the breadboard wiring correct 
3 can the breadboard wiring be tidied up (I eventually want to increase it to10 LEDs and 5 Servo's and transfer it all to PCB).

The Code ( I am a complete newbie when it comes to code)

4 I need the code to be altered to move only 1 servo between 90derees to 110degrees and to turn 1 LED on and a 2nd LED off and vise versa when the servo go's in opposite direction.
Hopefully then I can compare the 2 codes and work out how include the other 2 servo's and LED's (and eventually add 2 more making 5)

I hope I have explained myself properly and any help or advise would very appreciated. Many thanks Terry

post-25131-0-15869600-1482057353.jpg

post-25131-0-64403900-1482057377_thumb.jpg

Link to post
Share on other sites

#include <Servo.h> // include the Servo library

////////////////////////////////////////
//
// Definitions
//
////////////////////////////////////////

////////////////////////////////////////
// Basic parameters; adjust for your actual setup
#define NUMBER_OF_TURNOUTS 5
#define NUMBER_OF_SHIFT_REGISTERS 3
#define STEP_DELAY 70  // servo movement step delay, in milliseconds
///////////////////////////////////////

///////////////////////////////////////
// Data Structures
///////////////////////////////////////

//////////////////////////////////////
// TURNOUT_DEF holds all configuration
// information about turnouts and panel LEDS
//////////////////////////////////////
typedef struct TURNOUT_DEF {
  uint8_t button_pin; // Digital or analog pin for the button associated with this turnout
  uint8_t servo_pin; // Digital pin for the servo associated with this turnout
  int pos_main; // servo position for the MAIN leg, in degrees
  int pos_div; // servo position for the DIVERGENT leg, in degrees
  int panel_LED_main_green; // The position(s)of panel LEDS in the shift register chain
  int panel_LED_main_red; // Example assumes a bi-color (red/green) LED for each turnout leg
  int panel_LED_div_green; // modify these elements to reflect the actual LEDS you are using
  int panel_LED_div_red;
};

/////////////////////////////////////
// TURNOUT_DATA is wrapper structure holding
// both configuration and runtime data for turnout operation
/////////////////////////////////////
typedef struct TURNOUT_DATA {
  TURNOUT_DEF data; // configuration
  bool is_moving;
  byte alignment;
  int pos_now;
  int target_pos;
  unsigned long last_move;
};

// Alignment state values
#define ALIGN_NONE 0
#define ALIGN_MAIN  1
#define ALIGN_DIVERGENT 2


// pin ids for shift register chain controlling panel LEDS
#define LATCH_PIN 7
#define CLOCK_PIN 8
#define DATA_PIN 9

//////////////////////////////////////////
//
// Global variables
//
//////////////////////////////////////////

//////////////////////////////////////////
// TURNOUT_DATA Array
// * A0, A1, etc refer to analog pins which are used for buttons in this example
// * Replace pos_main (93) and pos_div (117) with real values for each turnout
// * LEDS are identified by their output position in the shift register chain;
// the identifier is a number between 0 and (NUMBER_OF_SHIFT_REGISTERS * 8) - 1. 
// Example assumes LEDS are connected to shift register outputs sequentially 
// from the first output of first register. You can connect LEDS to any output in
// any order; just set the identifiers accordingly.
//
// Only the TURNOUT_DEF part of the TURNOUT_DATA structure has to be initialized here; 
// The remaining elements are managed internally and are initialized automatically
//////////////////////////////////////////

TURNOUT_DATA turnouts[NUMBER_OF_TURNOUTS] = {
  {{A0, 2, 93, 117, 0, 1, 2, 3}},
  {{A1, 3, 93, 117, 4, 5, 6, 7}},
  {{A2, 4, 93, 117, 8, 9, 10, 11}},
  {{A3, 5, 93, 117, 12, 13, 14, 15}},
  {{A4, 6, 93, 117, 16, 17, 18, 19}}
};

// servo objects
Servo servos[NUMBER_OF_TURNOUTS];

// array to hold shift register state bytes
byte panel_LEDS[NUMBER_OF_SHIFT_REGISTERS];

void setup() 
{
  // Setup pins for shift register chain
  pinMode(LATCH_PIN, OUTPUT);
  pinMode(CLOCK_PIN, OUTPUT);
  pinMode(DATA_PIN, OUTPUT);
    
  // initialize each turnout 
  for(int i = 0; i < NUMBER_OF_TURNOUTS; i++){
    // attach the servo
    servos.attach(turnouts.data.servo_pin);
    // set the pin mode for the button pin
    pinMode(turnouts.data.button_pin, INPUT);
    // test and position the turnout by moving
    // to divergent then to main positions
    servos.write(turnouts.data.pos_div);
    turnouts.pos_now = turnouts.data.pos_div;
    setTurnout(i, ALIGN_MAIN);
    }
} // end of setup

void loop() 

  // get elapsed milliseconds at loop start
  unsigned long currentMillis = millis();

  // loop through the turnouts array
  for(int i = 0; i < NUMBER_OF_TURNOUTS; i++){
    if (turnouts.is_moving) {
      // if sufficient time has elapsed since the last move
      if ( (currentMillis - turnouts.last_move) >= STEP_DELAY ) {
        // move the turnout one degree
        turnouts.last_move = currentMillis;
        if (turnouts.pos_now < turnouts.target_pos) { // if the new angle is higher
          servos.write(++turnouts.pos_now);
        } else {  // otherwise the new angle is equal or lower
          if (turnouts.pos_now != turnouts.target_pos) { // not already at destination
            servos.write(--turnouts.pos_now);
          }
        }
      }
      // if target position reached, stop turnout motion
      if (turnouts.pos_now == turnouts.target_pos) {
        turnouts.is_moving = false;
        turnouts.last_move = 0;
        setIndicators(i);
      }
    } else {
      // if a turnout is NOT in motion, check to see if its button is pressed
      int button_state = digitalRead(turnouts.data.button_pin);
      if(button_state == HIGH){
        // toggle position
        if(turnouts.alignment == ALIGN_MAIN){
          setTurnout(i, ALIGN_DIVERGENT);
        } else {
          setTurnout(i, ALIGN_MAIN);
        }
      }
    }
  }
}// end of main loop

////////////////////////////////////////////////////////////////
// Supporting Functions
////////////////////////////////////////////////////////////////

void setTurnout(int id, int align){
    // Set indicators to show turnout in motion
    turnouts[id].alignment = ALIGN_NONE;
    setIndicators(id);
    // Set values to trigger motion on next loop iteration
    switch(align){
        case ALIGN_MAIN:
          turnouts[id].is_moving = true;
          turnouts[id].last_move = 0;
          turnouts[id].target_pos = turnouts[id].data.pos_main;
          turnouts[id].alignment = ALIGN_MAIN;
          break;
        case ALIGN_DIVERGENT:
          turnouts[id].is_moving = true;
          turnouts[id].last_move = 0;
          turnouts[id].target_pos = turnouts[id].data.pos_div;
          turnouts[id].alignment = ALIGN_DIVERGENT;
          break;
      }
}

void setIndicators(int id){
  switch(turnouts[id].alignment){
    case ALIGN_NONE: // means the turnout is in motion and not aligned
      panelWrite(turnouts[id].data.panel_LED_main_red, HIGH);
      panelWrite(turnouts[id].data.panel_LED_main_green, LOW);
      panelWrite(turnouts[id].data.panel_LED_div_red, HIGH);
      panelWrite(turnouts[id].data.panel_LED_div_green, LOW);
      break;
    case ALIGN_MAIN:
      panelWrite(turnouts[id].data.panel_LED_div_green, LOW);
      panelWrite(turnouts[id].data.panel_LED_div_red, HIGH);
      panelWrite(turnouts[id].data.panel_LED_main_green, HIGH);
      panelWrite(turnouts[id].data.panel_LED_main_red, LOW);
      break;
    case ALIGN_DIVERGENT:
      panelWrite(turnouts[id].data.panel_LED_div_green, HIGH);
      panelWrite(turnouts[id].data.panel_LED_div_red, LOW);
      panelWrite(turnouts[id].data.panel_LED_main_green, LOW);
      panelWrite(turnouts[id].data.panel_LED_main_red, HIGH);
      break;
  }
}
/////////////////////////////////////////////////
// Shift Register Functions
/////////////////////////////////////////////////
void panelWrite(int id, byte state) {
  int reg = floor(id / 8);
  int pos = id % 8;
  bitWrite(panel_LEDS[reg], pos, state);
  panelRefresh();
}

void panelRefresh(){
  // Prepare to shift by turning off the output
  digitalWrite(LATCH_PIN, LOW);
  // shift all bits out in MSB (most significant bit first) order
  for(int i = (NUMBER_OF_SHIFT_REGISTERS - 1); i>=0; i--) {
    // shift out the bits
    shiftOut(DATA_PIN, CLOCK_PIN, MSBFIRST, panel_LEDS);
  }
  // turn on the output to activate
  digitalWrite(LATCH_PIN, HIGH);
}

Link to post
Share on other sites

Hi Robin, thanks for your reply, it is all very confusing and conflicting, one person tells me I can only use a total of 5 servo's with a UNO board and you tell I can use 12 :scratchhead:(on the Arduino forum) . I am that new to all of this that even a sentence like "There is no need for external pull-up resistors if you use pinMode(pin, INPUT_PULLUP);" is at this moment in time is beyond me, but I do appreciate  your input.Terry

Link to post
Share on other sites

  • RMweb Premium

How much have you tested for yourself?

 

1) Yes though there are other ways of doing this as with everything.

2) Without spending a fair bit of time it's difficult to say. Two things stand out at first glance. The red wire looping round the left-hand end of the breadboard doesn't seem to connect to anything. Check that all the groups of 5 holes along the top of the breadboard that you are using for power are actually connected to each other, they may not be.

 

If you have never done any of this before you might want to start out with something less ambitious first. Why not just a button and a single servo or a button and a shift register?

 

Cheers

Dave

Link to post
Share on other sites

I have built the board as in the Fritzing image (all the LEDs come on, and when I upload the code the Servo's jitter and the LEDs flicker and the pressing the buttons does'nt do anything, but is that because the code is not assigned to anything?.The red wire looping round the left-hand end of the breadboard is connected to external 5 volt power supply.

 

This is an image i used with great results, and a little bit less ambitious :imsohappy:

 

 

post-25131-0-24627600-1482060929_thumb.jpgI

 

 

 

 

If I used this circuit/image, how many Servo's could use per UNO board. many thanks Terry 

Link to post
Share on other sites

Hi Robin, thanks for your reply, it is all very confusing and conflicting, one person tells me I can only use a total of 5 servo's with a UNO board and you tell I can use 12 :scratchhead:(on the Arduino forum) . I am that new to all of this that even a sentence like "There is no need for external pull-up resistors if you use pinMode(pin, INPUT_PULLUP);" is at this moment in time is beyond me, but I do appreciate  your input.Terry

I will happily try to help if you pursue this in The Arduino Forum - but I am not going to do it in two places. And I am only giving the Arduino Forum priority because I had already responded there before I (just now) made the connection with you here. At the time I wrote Reply #2 here there was almost nothing in your Original Post here.

 

...R

Link to post
Share on other sites

I see you have met at least one of the many "helpful" people on the Arduino forum with exaggerated sense of importance.  Need a gnome inserted. :O

 

I would strongly advise that you take Robin2's advice regarding Input-pullup and rewiring the button as many add-on circuits are low for active (occupancy, etc) and you need less components.  It is a very good habit to get into.

 

CFJ

Link to post
Share on other sites

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...