derde toestand: stand onbepaald
Bas: je lijkt booleans niet leuk te vinden? Waarom niet?
struct { unsigned int seinStand: 2; // 2 bits unsigned int wisselStand : 2; // 2 bits unsigned int terugmelder : 1; // 1 bit} status; // gebruikt 1 byte aan geheugen// gebruik:#define STRAIGHT 0#define CURVED 1#define MOVING 2 // of UNDEFINED of TRANSITIONING of net wat je wilt// nog een 4e stand voor een drieweg wissel is ook nog mogelijk.status.wisselStand = MOVING ;if( status.terugmelder ) {// etc
public: // // Turntable constructor // Turntable(int anHallSensorPin, int aBounceSize, AccelStepper *aStepper, long aFullRotation); // // Set a new turntable position and start the movement // to the new position. // void gotoTTPosition(long newTTPosition); // // Keep the turntable moving if necessary // void heartBeat(); // // This method performs a calibration operation for the turntable. During this operation it // executes a full turn counter clockwise looking for the hall sensor. When found, it will // skip past the sensor and do a turn clockwise until the sensor is again found. // Based on the four points (2 points counter clockwise and 2 points clockwise) where the sensor // tripped, the 0 position of the TT is calculated and the TT will go to its last known position. // This whole process is blocking, during the execution of this method no other DCC commands are honored. // void calibrate(); // // This method performs a calibration operation for the turntable. During this operation it // executes a full turn counter clockwise looking for the hall sensor. When found, it will // skip past the sensor and do a turn clockwise until the sensor is again found. // Based on the four points (2 points counter clockwise and 2 points clockwise) where the sensor // tripped, the 0 position of the TT is calculated and the TT will go to the specified new position. // This whole process is blocking, during the execution of this method no other DCC commands are honored. // void calibrate(long newTTPosition);
#include <Servo.h>#include <TMC2130Stepper.h>#include <AccelStepper.h>#include "CanBus.h"#include "KB_Eeprom.h"#include "KB_Turntable.h"#include "KB_Servo.h"
//// KB_CB-TurntableController Turntable control//// Author: Meino de Graaf// email: meino@innerside.demon.nl//// This program controls a NEMA-17 bi-polar stepper motor, which turns a Peco LK-55 turntable.// The stepper motor has 400 full steps/rotation (0.9 degree per step). The motor is driven// by an TMC2130 SilentDrive using micro stepping (32 micro steps/full step).//// Further two micro servos are also controlled by this program. These two servos are responsible for// opening or closing of the doors of a two track loco shed.//// The program listens for DCC commands (coming from the Canbus) that activates the different functions // (moving to a track or opening/closing of a door).// Currently there are 9 tracks defined in the program, each track has it's own DCC address and has two// positions for the stepper motor defined. One position defines the 0 degree ('-') position for the// control platform and the other one defines the 180 degree ('/') opposite position.//// Due to the fact that an unpowered stepper motor is free to turn (contrary to a micro servo, which stays// put due to the friction of it's gears), the position of the stepper motor is unknown after a power-up.// Therefore the turntable performs a calibration during the initialisation phase. This calibration is done// by locating a Hall sensor using a small magnet attached to the turntable. The location of the Hall sensor// defines the zero position from which all track positions are derived.//// Two door servos are defined. Each has it's own DCC address and the open/close position for the servo.// If a DCC command for a servo is received, the '-' command activates a door close, while the reception// of a '/' command activates the opening of the door. Further the speed of the movement is also part of// the servo definition.// At this moment all definitions are part of the code and no provision are made to make these remotely// configurable.//
#define SERVO_DEBUG 0#define DEBUG 0//// Pins used for the Hall sensor on the Turntable//#define HALL_SENSORPIN 5//// Pin definitions for the TMC2130 SilentStepper on the UNO//#define EN_PIN 7 // enable (CFG6)#define DIR_PIN 8 // direction#define STEP_PIN 6 // step#define CS_PIN 10 // chip select TMC2130 (Silent stepper driver)//// Pins used by the SPI interface (only for documentation)//#define MOSI_PIN 11 //SDI/MOSI (ICSP: 4, Uno: 11, Mega: 51)#define MISO_PIN 12 //SDO/MISO (ICSP: 1, Uno: 12, Mega: 50)#define SCK_PIN 13 //CLK/SCK (ICSP: 3, Uno: 13, Mega: 52)//// Pin for the CanBus//#define CB_CS_PIN 9 // Chip select MCP2515 (Canbus)//// The door servo pins//#define SERVO_2_PIN 4#define SERVO_1_PIN 3
//// The CanBus//CanBus *canBus;//// Data that is stored in EEPROM to remember the state of the// turnouts. It is handled by a eepromController class//EepromController *EepromControl = new EepromController();
//// The definitions for the geometry of the TT-stepper combination//#define MICROSTEPS 32L // This parameter defines the number of microsteps used for the stepper.// 16 is the minimum you may use (otherwise you have to change the// ADJUSTMENT define). Settings of 16 & 32 are save to use. // Higher values (64,128 or 256) are also save to use for controlling the stepper// however these values create such an interrupt load, that the DCC commands// will fail while the stepper is moving.//#define FULL_STEPS 400L // A Nema 17/23 motor with steps of 0.9degree per step#define HALF_STEPS 200L#define FULL_ROTATION (MICROSTEPS * FULL_STEPS) // The nr of steps for a 360degree turn#define ROTATION180 (MICROSTEPS * HALF_STEPS) // The nr of steps needed for 180degree turn#define BOUNCE (MICROSTEPS/4) // In real life there is always an // overshoot and a rebounce//// The following defines give a full rotation in aprox. 2 minutes like the prototype//#define MAX_SPEED (2.8*MICROSTEPS) // Avoid speed settings 2.3-2.7 (step time 1400-1700 microsec). All // with 256 microsteps, because in this speed window a faint whine// is noticeble, probably caused by interference.// This is valid when stealthChop is active.#define ACCELERATION (MICROSTEPS/1.4)#define START_SPEED (MICROSTEPS/1.4)//// Rough Definitions for the Turntable track positions//#define TRACK_POSITION1 (376L*MICROSTEPS) // DCC address 201 #define TRACK_POSITION2 (350L*MICROSTEPS) // DCC address 202 #define TRACK_POSITION3 (293L*MICROSTEPS) // DCC address 203 #define TRACK_POSITION4 (281L*MICROSTEPS) // DCC address 204 #define TRACK_POSITION5 (269L*MICROSTEPS) // DCC address 205 #define TRACK_POSITION6 (257L*MICROSTEPS) // DCC address 206#define TRACK_POSITION7 (245L*MICROSTEPS) // DCC address 207#define TRACK_POSITION8 (233L*MICROSTEPS) // DCC address 208#define TRACK_POSITION9 (215L*MICROSTEPS) // DCC address 209//// Structure which defines the coupling between the used Accessory address and turntable// position//typedef struct{ short address; // Accessory address long position0; // Straight (-) location long position180; // Diverging (/) location, 180 degrees turned.}TrackPosition;const int nrOfTracks = 10;//// A table with all the track positions. Each track position is fine tuned using small amounts// of microsteps. All these position have to be derived by Error and trial from the physical Turntable//TrackPosition trackPositions[nrOfTracks] = { {200, 0, 0}, // Triggers a Calibration action {201, TRACK_POSITION1 + 0, TRACK_POSITION1 + ROTATION180 - 4}, {202, TRACK_POSITION2 + 2, TRACK_POSITION2 + ROTATION180 - 2}, {203, TRACK_POSITION3 + 0, TRACK_POSITION3 + ROTATION180 + 0}, {204, TRACK_POSITION4 + 6, TRACK_POSITION4 + ROTATION180 + 6}, {205, TRACK_POSITION5 + 6, TRACK_POSITION5 + ROTATION180 + 4}, {206, TRACK_POSITION6 + 0, TRACK_POSITION6 + ROTATION180 - 2}, {207, TRACK_POSITION7 + 6, TRACK_POSITION7 + ROTATION180 + 0}, {208, TRACK_POSITION8 + 0, TRACK_POSITION8 + ROTATION180 + 0}, {209, TRACK_POSITION9 + 4, TRACK_POSITION9 + ROTATION180 + 4}};
//// Structure which defines the coupling between the used Accessory address and a door servo//typedef struct{ short address; // Accessory address DoorServo *doorServo;}Door;//// Number of door servo's//#define NR_OF_DOORS 2Door doors[NR_OF_DOORS] = { { 108, new DoorServo(SERVO_1_PIN, 20, 108, 48)}, // DCC address 108, 20mS between steps, pos 108 open, pos 48 closed { 109, new DoorServo(SERVO_2_PIN, 20, 54, 116)} // DCC address 109, 20mS between steps, pos 54 open, pos 116 closed};
//// Create an interface to the TMC2130 driver card//TMC2130Stepper driver = TMC2130Stepper(EN_PIN, DIR_PIN, STEP_PIN, CS_PIN);//// Two methods used by the AccelStepper object for driving the stepper.// This is done by using the defined STEP_PIN and the shaft_dir method// on the TMC2130 interface object//void forwardStep(){ driver.shaft_dir(1); digitalWrite(STEP_PIN, LOW); //delayMicroseconds(1); // Make sure that the pulse is detected digitalWrite(STEP_PIN, HIGH); //delayMicroseconds(10);}void backwardStep(){ driver.shaft_dir(0); digitalWrite(STEP_PIN, LOW); //delayMicroseconds(1); // Make sure that the pulse is detected digitalWrite(STEP_PIN, HIGH); //delayMicroseconds(10);}//// Time to wrap the stepper in an AccelStepper object//AccelStepper stepper(forwardStep, backwardStep);
//// Create the Turntable object, give it the pin for the Hall Sensor, the AccellStepper object and // the nr of steps for doing a full rotation//Turntable TT(HALL_SENSORPIN, BOUNCE, &stepper, FULL_ROTATION);
//// A function that executes whenever a DCC_ACC message is received from the Canbus// It's purpose is to analyze the received event (Signal or turnout) and// update the track position of the TT or update the position of the doors.//void dccAccReceiver(unsigned char aMsgLen, DCC_ACC_MSG *msgData){#if (DEBUG) Serial.print("[dccAccReceiver] dccId: "); Serial.print(msgData->address); Serial.print(", dccState: "); Serial.println(msgData->direction); Serial.flush();#endif //DEBUG unsigned short address = msgData->address; // // Do we perform a straight(-) or a diverging(/) operation? // For a straight operation enable is true, for a diverging operation // enable is false. // bool enable = (msgData->direction) ? 0 : 1; // // Search for the specified accessory address, when found lookup the // specified position for the straight or diverging operation and start moving // to that target position. // for (int i = 0; i < nrOfTracks; i++) { if ( address == trackPositions[i].address ) {#if (DEBUG) Serial.print("[dccAccReceiver] TT Address: "); Serial.print(address, DEC);#endif //DEBUG // // The new position of the TT // long newTargetPosition = 0; if (enable) // Received a "-" command {#if (DEBUG) Serial.print(" (-)");#endif //DEBUG // // Go to the straight position (0 degree) // newTargetPosition = trackPositions[i].position0; EepromControl->setTTposition(i); EepromControl->saveData(); } else // Received a "/" command {#if (DEBUG) Serial.print(" (/)");#endif //DEBUG // Go to the diverging (180 degree) position. // newTargetPosition = trackPositions[i].position180; EepromControl->setTTposition(i+nrOfTracks); EepromControl->saveData(); }#if (DEBUG) Serial.print(" Position: "); Serial.println(newTargetPosition, DEC); Serial.flush();#endif //DEBUG // // If the choosen position equals 0, then we have to recalibrate // if (newTargetPosition == 0) { TT.calibrate(); } else { // // Not a recalibrate, goto the choosen position // TT.gotoTTPosition(newTargetPosition); } return; } } // // If we didn't find an address match with a track location // check if a door servo matches the received address // for (int i = 0; i < NR_OF_DOORS; i++) { if ( address == doors[i].address ) {#if (DEBUG) Serial.print("[dccAccReceiver] Door address: "); Serial.print(address, DEC);#endif //DEBUG if (enable) {#if (DEBUG) Serial.println(" (-)"); Serial.flush();#endif //DEBUG // // Go to the closed position // doors[i].doorServo->closeDoor(); EepromControl->setDoorPosition(i,DoorClosed); EepromControl->saveData(); } else {#if (DEBUG) Serial.println(" (/)"); Serial.flush();#endif //DEBUG // // Go to the open position. // doors[i].doorServo->openDoor(); EepromControl->setDoorPosition(i,DoorOpen); EepromControl->saveData(); } return; } }#if (DEBUG) Serial.print("[dccAccReceiver] Unknown address: "); Serial.println(address, DEC); Serial.flush();#endif //DEBUG}
void setup(){#if (DEBUG || TT_DEBUG || SERVO_DEBUG || EEPROM_DEBUG) //Serial.begin(9600); Serial.begin(115200); while (!Serial); Serial.println("Starting");#endif //DEBUG || TT_DEBUG || SERVO_DEBUG ||EEPROM_DEBUG // // Setup the TMC2130 silent driver // driver.begin(); // Initiate pins and registeries driver.rms_current(900); // Set stepper current to 900/1100mA. The stepper is rated at 0.9A. // The command is the same as command TMC2130.setCurrent(900, 0.11, 0.5); driver.hold_current(22); // Hold current 70% driver.run_current(31); // Run current 100% driver.hold_delay(1); // Time between switch from run to hold 1sec // driver.microsteps(MICROSTEPS); // Set the nr of microsteps // driver.interpolate(1); // Use internally always the maximum nr of microsteps (256). This creates // the smoothest movement, when not set a small hum of the stepping is // noticeble driver.diag1_steps_skipped(1); // driver.stealthChop(1); // Enable extremely quiet stepping digitalWrite(EN_PIN, LOW); // // Enabling of the TMC2130 driver done //
#if (DEBUG) for (int i = 0; i < nrOfTracks; i++) { Serial.print(trackPositions[i].address); Serial.print(", pos0 "); Serial.print(trackPositions[i].position0); Serial.print(", pos180 "); Serial.println(trackPositions[i].position180); }#endif //DEBUG // // Load the EEPROM data for the turnout directions // EepromControl->loadData(); byte eePromData = EepromControl->getTTposition();#if (DEBUG) Serial.print("[setup] eePromData: "); Serial.println(eePromData); Serial.flush();#endif if (eePromData > 2*nrOfTracks) { eePromData = 1; } // // Get the in EEPROM stored track position, it wil be used when we calibrate the // turntable // long ttPosition; if (eePromData < nrOfTracks) { ttPosition = trackPositions[eePromData].position0; } else { ttPosition = trackPositions[eePromData-nrOfTracks].position180; } // // Initialize the door servos with the in EEPROM stored position // for (int i = 0; i < NR_OF_DOORS; i++) { if (EepromControl->getDoorPosition(i) == DoorOpen) {#if (DEBUG) Serial.print("[setup] door: "); Serial.print(i); Serial.println(" open"); Serial.flush();#endif // // Go to the open position // doors[i].doorServo->initDoorOpen(); } else {#if (DEBUG) Serial.print("[setup] door: "); Serial.print(i); Serial.println(" closed"); Serial.flush();#endif // // Go to the closed position // doors[i].doorServo->initDoorClosed(); } }
// // Set some parameters of the AccelStepper object // stepper.setMaxSpeed(MAX_SPEED); stepper.setAcceleration(ACCELERATION); stepper.setSpeed(START_SPEED); // // Initialy the 0 position of the stepper motor is not known, so we // have to do a calibration to find the Hall sensor and establish a // known position for the stepper motor. // TT.calibrate(ttPosition);
// // Create an interface to the CanBus and start the CanBus communication // canBus = new CanBus(TT_CONTROLLER_ID, nullptr, new Mcp2515(CB_CS_PIN)); // Only a Receiver // // Register a callback routine for handling the Accessory(DCC_ACC type) messages // canBus->setMsgReceiver(DCC_ACC, dccAccReceiver); canBus->begin();#if (DEBUG) Serial.println("[setup], Canbus ready"); Serial.println("[setup] ready");#endif}//--(end setup )---
void loop(){ // // Check for Canbus messages // canBus->heartBeat(); // // Activate the door servos // for (int i = 0; i < NR_OF_DOORS; i++) { // // Activate the servo, so it can go to it's next position. // doors[i].doorServo->heartBeat(); } // // Check for CanBus packets // canBus->heartBeat(); // // Keep the turntable running // TT.heartBeat();}