Jump to content
 

Dave Anderson

Members
  • Posts

    4
  • Joined

  • Last visited

Everything posted by Dave Anderson

  1. A question on a Facebook group a while back asking about modular connectors to keep things simple. While the following is perhaps not simple it is modular and works for me. There are many reasons to do it another way etc, but hey it's my layout . I wanted to be able to run dropper wires from the tracks to some form of plugin system under the board in an attempt to reduce the requirement to use a soldering iron above my head as my layout isn't easily separated into it's constituent parts and raised on it's edge. This has expanded into running three wire extension cables for servo's back to PCA9685 servo controller boards and even the I2C, VCC and GND loom from an Arduino to these PCA9685 cards. My solution was to buy in a load of 'dupot' connector pins and sockets along with 1pin, 2pin and 3pin cases, and a cheap crimp tool all off ebay. This allows me to make up any type of wiring loom that has connectors at each end so I can plug and play once the wires are below the baseboard. To start I create a 'distribution board' and use a number of 2 pins cut from a run of single PCB header pins and solder these to stripboard in groups of 4 or 5 with a 2pin screw terminal at each end - see pic below with the blue screw terminals on stripboard for example. This gets screwed to the underside of my baseboard at various locations. Heavy duty zip wire (white and white/black) is run between then as a "mains bus." I then manufacture dropper wires with a dupont sockets on the end in a double pin case: These then plug onto the distribution board: The servo extension wires use both plugs and sockets made up from dupont connectors in 3pin casings: This enables me to have a balance between servo controller boards in locations close to servos and not to have many long runs of servo control cables. A note on dupont crimping. It takes a while to get into the hang of it. The cheaper tools don't really produce a great crimp without a little fettling after the initial crimp. I've found the insulation part of the crimp may need a gentle squeeze with a pair of pliers and perhaps a general straightening out of the metal socket/pin. What I have found is that the insertion of the socket/pin into the housing should be very easy with no resistance and there should be a little click as the socket/pin reaches the correct location within the housing.
  2. So this is the first post in my Arduino servo control system for my OO gauge layout. I've spent a fair bit of time learning Arduino project construction and sketch writing to get to this stage. If, on reading this, you want to explore then do start off with simple 'experiments' and build up your knowledge and experience gradually. I'm not going to explain servos, servos and turnouts(points), shift registers etc - there is a ton of stuff on the web that covers that. I would suggest DroneBot Workshop for loads on Arduino, and Toms Trains and Things for model railway Arduino and servo's, both on YouTube to start off with. The main idea is to be able to process switch activation - either (on)-off-(on) momentary mini leaver switches or simple (on)-off "push to make" buttons - and transfer that into activating appropriate servos to change the direction turnouts or pairs of turnouts in the case of a pair of crossover to enable the movement of a train from one track to another. Below is a "Fristzing" wiring diagram for an Arduino Nano, some test push buttons, a couple of 74HC165 input shift registers and a 16x2 LCD display (just for the fun of it). The diagram is missing the connections to the PCA9865 servo controllers. These servo controllers are handled via I2C from analog pins 1 and 2 to the SCL and SDA lines respectively. Because I2C is a 'bus' I've quickly knocked together a distribution board that individual PCA9685 boards can plug into. That being said there are posts and questions elsewhere on the web that indicate that I2C bus length of over 1m can have issues. I'll have a play and see. If I do end up over 1m but the servo's do their task then I'll not overly worry about it. The code below has a load of code that prints information out to the serial monitor (serial.print lines) that won't be included in the final revision. This version 'works' but has bits that need to pulled or changed as they are artifacts from the development of the code from an empty sketch to working. This is very much a work in progress. // include the PWMServo library #include <Adafruit_PWMServoDriver.h> // include the library code: #include <LiquidCrystal.h> // Setup pwm objects and their addresses Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(0x40); Adafruit_PWMServoDriver pwm1 = Adafruit_PWMServoDriver(0x41); #define NUMSERVOS 5 // Enter the number of servos being controlled #define SERVOMIN 125 // this is the 'minimum' pulse length count (out of 4096) #define SERVOMAX 575 // this is the 'maximum' pulse length count (out of 4096) // Setup servio struct that holds pwm card, socket number and open/close angles. struct ServoData { Adafruit_PWMServoDriver pwmcard; // PCA9685 card number byte pwmcard_socket; // Socket on PCA9685 card byte openangle; // User Configurable servo angle for open point byte closeangle; // User Configurable servo angle for close point }; ServoData servo[NUMSERVOS]; /* 74hc165 Width of pulse to trigger the shift register to read and latch. */ #define PULSE_WIDTH_USEC 5 /* 74hc165 Optional delay between shift register reads. */ #define POLL_DELAY_MSEC 20 int clockEnablePin = 10; // Connects to Clock Enable pin the 165 (15) int dataPin = 11; // Connects to the Q7 pin the 165 (9) int clockPin = 12; // Connects to the Clock pin the 165 (2) int ploadPin = 13; // Connects to Parallel load pin the 165 (1) byte old_incoming1; // old values for first 74HC165 chip byte incoming1; // new values for first 74HC165 chip byte old_incoming2; // old values for second 74HC165 chip byte incoming2; // new values for first 74HC165 chip // initialize the library with the numbers of the interface pins LiquidCrystal lcd(7 , 6, 5, 4, 3, 2); /* 2 - LCD D7 3 - LCD D6 4 - LCD D5 5 - LCD D4 6 - LCD Enable 7 - LCD RS LCD R/W pin to ground LCD VSS pin to ground LCD VCC pin to 5V 10K resistor: ends to +5V and ground wiper to LCD VO pin (pin 3) */ void setup() { // Setup Serial Monitor Serial.begin(9600); // Setup LCD screen lcd.begin(16,2); lcd.print("Setup.."); // Setup 74HC165 connections pinMode(ploadPin, OUTPUT); pinMode(clockEnablePin, OUTPUT); pinMode(clockPin, OUTPUT); pinMode(dataPin, INPUT); // Initialise first 74HC165 values. // For one chip only use incoming1. // For two chips use incoming1 and incoming2 // For more 75HC165 chips added new variables as required up to incoming4. read_values(); old_incoming1 = incoming1; old_incoming2 = incoming2; // Setup PWM PCA9685 cards pwm.begin(); pwm.setPWMFreq(60); // Analog servos run at ~60 Hz updates pwm1.begin(); pwm1.setPWMFreq(60); // Analog servos run at ~60 Hz updates pwm2.begin(); pwm2.setPWMFreq(60); // Analog servos run at ~60 Hz updates // Setup NUMSERVOS servos // Remember to update ths number when new servos are added. servo[0].pwmcard = pwm; servo[0].pwmcard_socket = 0; servo[0].openangle = 115; servo[0].closeangle = 60; servo[1].pwmcard = pwm; servo[1].pwmcard_socket = 4; servo[1].openangle = 145; servo[1].closeangle = 70; servo[2].pwmcard = pwm1; servo[2].pwmcard_socket = 1; servo[2].openangle = 140; servo[2].closeangle = 60; servo[3].pwmcard = pwm1; servo[3].pwmcard_socket = 5; servo[3].openangle = 120; servo[3].closeangle = 60; // Start board in safe positions with all junctions "closed" lcd.setCursor(0,1); lcd.print("Closing : 0"); move_servo (servo[0].pwmcard, servo[0].pwmcard_socket, servo[0].closeangle); move_servo (servo[1].pwmcard, servo[1].pwmcard_socket, servo[1].closeangle); delay(1000); lcd.setCursor(0,1); lcd.print("Closing : 1"); move_servo (servo[2].pwmcard, servo[2].pwmcard_socket, servo[2].closeangle); move_servo (servo[3].pwmcard, servo[3].pwmcard_socket, servo[3].closeangle); delay(1000); lcd.setCursor(0,0); lcd.print("Setup..done"); delay(2000); lcd_clear_line(0); delay(1000); lcd_clear_line(1); } void read_values() { // Write pulse to load pin digitalWrite(ploadPin, LOW); delayMicroseconds(PULSE_WIDTH_USEC); digitalWrite(ploadPin, HIGH); delayMicroseconds(PULSE_WIDTH_USEC); // Get data from 74HC165 chips digitalWrite(clockPin, HIGH); digitalWrite(clockEnablePin, LOW); incoming1 = shiftIn(dataPin, clockPin, MSBFIRST); incoming2 = shiftIn(dataPin, clockPin, MSBFIRST); digitalWrite(clockEnablePin, HIGH); } void lcd_clear_line (int line) { // clear line on lcd display lcd.setCursor(0,line); lcd.print(" "); } void move_points ( ) { // Print to serial monitor // Move either one or two servos based on which button has been pressed if (incoming1 > 0 ) { switch (incoming1) { case B00000001: // Button "1:" - close juction one // This is a cross over so throws two servos Serial.print("Buton 1. 74HC615 BIN value : "); Serial.println(incoming1, BIN); lcd_clear_line(1); lcd.setCursor(0,0); lcd.print("Closing : 1"); move_servo (servo[0].pwmcard, servo[0].pwmcard_socket, servo[0].closeangle); move_servo (servo[1].pwmcard, servo[1].pwmcard_socket, servo[1].closeangle); delay(1000); break; case B00000010: // Button "2" - open juntion one // This is a cross over so throws two servos Serial.print("Buton 2. 74HC615 BIN value : "); Serial.println(incoming1, BIN); lcd_clear_line(1); lcd.setCursor(0,0); lcd.print("Opening : 1"); move_servo (servo[0].pwmcard, servo[0].pwmcard_socket, servo[0].openangle); move_servo (servo[1].pwmcard, servo[1].pwmcard_socket, servo[1].openangle); delay(1000); break; case B00000100: // Button "3" - close Juction two; // This is a cross over so throws two servos Serial.print("Buton 3. 74HC615 BIN value : "); Serial.println(incoming1, BIN); lcd_clear_line(1); lcd.setCursor(0,0); lcd.print("Closing : 2"); move_servo (servo[2].pwmcard, servo[2].pwmcard_socket, servo[2].closeangle); move_servo (servo[3].pwmcard, servo[3].pwmcard_socket, servo[3].closeangle); delay(1000); break; case B00001000: // Button "4" - open Juction two; // This is a cross over so throws two servos Serial.print("Buton 4. 74HC615 BIN value : "); Serial.println(incoming1, BIN); lcd_clear_line(1); lcd.setCursor(0,0); lcd.print("Opening : 2"); move_servo (servo[2].pwmcard, servo[2].pwmcard_socket, servo[2].openangle); move_servo (servo[3].pwmcard, servo[3].pwmcard_socket, servo[3].openangle); delay(1000); break; case B00010000: Serial.print("Five : "); Serial.println(incoming1, BIN); break; case B00100000: Serial.print("Six : "); Serial.println(incoming1, BIN); break; case B01000000: Serial.print("Seven : "); Serial.println(incoming1, BIN); break; case B10000000: Serial.print("Eight : "); Serial.println(incoming1, BIN); break; default: Serial.print ("Default: "); Serial.println(incoming1, BIN); break; } } else if (incoming2 > 0 ) { switch (incoming2) { case B00000001: Serial.print("Nine : "); Serial.println(incoming2, BIN); break; case B00000010: Serial.print("Ten : "); Serial.println(incoming2, BIN); break; case B00000100: Serial.print("Eleven : "); Serial.println(incoming2, BIN); break; case B00001000: Serial.print("Twelve : "); Serial.println(incoming2, BIN); break; case B00010000: Serial.print("Thirteen : "); Serial.println(incoming2, BIN); break; case B00100000: Serial.print("Fourteen : "); Serial.println(incoming2, BIN); break; case B01000000: Serial.print("Fifteen : "); Serial.println(incoming2, BIN); break; case B10000000: Serial.print("Sixteen : "); Serial.println(incoming2, BIN); break; default: Serial.print ("Default: "); Serial.println(incoming2, BIN); break; } } } int angleToPulse(int ang){ int pulse = map(ang,0, 180, SERVOMIN,SERVOMAX);// map angle of 0 to 180 to Servo min and Servo max Serial.print("Angle: ");Serial.print(ang); Serial.print(" pulse: ");Serial.println(pulse); return pulse; } void move_servo (Adafruit_PWMServoDriver pwmcard, int srv,int ang ) { pwmcard.setPWM(srv, 0, angleToPulse(ang)); Serial.print("moving servo "); Serial.print(srv); Serial.print(" to angle "); Serial.println(ang); } void loop() { lcd.setCursor(0,0); lcd.print("Ready ....."); read_values(); if (incoming1 != old_incoming1 || incoming2 != old_incoming2) { move_points(); old_incoming1 = incoming1; old_incoming2 = incoming2; } delay(200); } The Arduino wiring. The main bread board has 4 pairs of micro push to make switches. The Resistors are pull down resistors to ground so that when the button is pressed a 'high' voltage is registered on the appropriate 74HC165 input pin. The pair of buttons is to simulate the 'opening' or 'closing' of the point blades on the turnout. To test the ability to read values from two 74HC165 chips 4 of the switches are on the second chip rather than just using all 8 of the pins on chip1. The two 74HC165 chips are daisy chained together - chip1 on the diagram is the left one and chip2 is the right one. The wiring of the 16x2 LCD is pulled directly from the adafruit tutorial page. Some comments on the code I've cobbled it together from all over the web - snippets here and snippets there. shift registers - they are complicated and I don't fully understand how they work. I have enough though to get the circuits to work. I suspect more by luck than design! A button can control either a single turnout direction or a pair of turnouts - for example a cross over between tracks. I refer to this as a 'Junction' in the code. Each junction requires two buttons. This 'choice' is hard coded in to the logic of the code. I probably could make it more dynamic but for my needs it works. The code is ugly. I'm not a coder by profession. I've included a picture that shows the development hookup on the kitchen surface. It shows the connections to the Arduino, the I2C distribution strip board and the two PCA9685 cards connected to it which I've indicated above are missing from the Fritzing diagram. For testing I have just three servos connected just now out of a possible 32. The Power supply is an old steel case from Maplins (from 1990 ish) with a DC-DC 100W 12A High Power Adjustable Converter Buck Step-down Module providing the voltage to drive the servos and then monitored via a Digital LED 100V Voltmeter, 10A Ammeter, Panel mount volt amp meter. I'm sure there is stuff I've missed explaining or could be clearer - just ask.
  3. From Facebook - Harburn Hobbies are having their annual Bachmann & Graham Farish Promotional Days taking place in the shop on Friday 24th and Saturday 25th August with 20% off most Bachmann and Graham Farish products. There's a free prize draw to win Harburn Hobbies Gift Vouchers and the usual refreshments are available. Pre-production samples of new products, kindly loaned to us by Bachmann, will be here to admire! More info:- Time & Place:- Friday 24th & Saturday 25th August 2018 from 9.30am - 6.00pm at Harburn Hobbies, 67 Elm Row, on Leith Walk, Edinburgh EH7 4AQ By Train:- Half a mile from Waverley Station. By Bus:- Lothian Buses 7, 10, 11, 12, 14, 16, 22, 25, & 49 also "The Majestic Tour" pass the door. By Tram:- Nearest stop is "York Place" (the current terminus) By Car:- Free parking is available for one hour on both sides of Leith Walk. On the surrounding side streets, ticket parking bays are also available and these are free of charge on Saturdays. Contact:- Phone: 0131 - 556 3233. Email: sales@harburnhobbies.co.uk Our website addresses: harburnhobbies.com - harburnhobbies.co.uk - harburns.co.uk
  4. Hi - great thread and awesome modelling. I've been reading your Hornby Ex Works 29 and Bachman/Hornby Rat Sandwich threads with interest. Would you be able/willing to give an overview of how you get such excellent etches in this thread at all ? Thanks.
×
×
  • Create New...