Hello,
if using the citizen software mocca with ubuntu and a pcsc reader like the “Reiner SCT Pinpad” you should notice that java searches in the wrong dirs for the pcsclite lib.
So you can do following:
ln -sf /lib/x86_64-linux-gnu/libpcsclite.so.1.0.0 /usr/lib64/libpcsclite.so
Have fun!
A super live boot manager.
See http://www.supergrubdisk.org/
Have fun!
See http://www.opendcc.de/s88/gbm_bidi/gbm_bidi.html
Have fun!
-3 rails
-dc motor
-10 turn poti for position
-arduino uno board
-controlled by rocrail
-minimized feedback sensors (see T4 to T6)
The code:
#include <NmraDcc.h>
//init DCC
NmraDcc Dcc;
DCC_MSG Packet ;
//Addresses
const byte Addr1 = Dcc.getCV(CV_ACCESSORY_DECODER_ADDRESS_LSB);
const byte Addr2 = Addr1 + 1;
//declaring outputs
const int MotorPinPWMA = 9; // PWM motor pin
const int MotorPinPWMB = 6; // motor relais
const int fb0 = 12; // feedback to rocrail positon reached
const int CVAckPin = 13; // dcc ack pin for programming the cv's
const byte rails = 3; // number of rails
const int rail[] = {7,8,11}; // disconnecting/connection the rail feedback sensors
int railPos[] = { // positions of the rails
(Dcc.getCV(519) << 8) | Dcc.getCV(520),
(Dcc.getCV(521) << 8) | Dcc.getCV(522),
(Dcc.getCV(523) << 8) | Dcc.getCV(524)
};
//declaring analog inputs
int sensorPin = A3; // poti pin for position detection
int MotorPinCurrent = A0; // motor current measurement
// variables will change:
int posState[] = {0,0,0,0}; // setting correct position from dcc to motor function 0,1,2,3
byte posNew = 0; // new position
int i = 0; // loops
int j = 0; // loops
int pos; // var for position
byte railtimes = 1; // loop breaker
int posIST; // position registered
int posSOLL; // position should be
int DIFF; // difference between position registered and position should be
long previousMillis = 0; // breaking var within the millis() funtion
byte maxCurrent = Dcc.getCV(515);// maximum current the motor drives
byte maxSpeed = Dcc.getCV(516); // maximum voltage the motor drives
byte minSpeed = Dcc.getCV(517); // minimum voltage the motor drives
byte Speed = 0; // actual speed set motor
int Current = 0; // actual current motor
byte CVbyte1; // helper var for CVSet()
byte CVbyte2; // helper var for CVSet()
void setup() {
// init the serial port
Serial.begin(115200); // setup serial
// init dcc
Dcc.init( MAN_ID_DIY, 10, FLAGS_OUTPUT_ADDRESS_MODE | FLAGS_DCC_ACCESSORY_DECODER | FLAGS_ENABLE_INT0_PULL_UP, 0);
// Configure the DCC CV Programing ACK pin for an output
pinMode( CVAckPin, OUTPUT );
// initialize the outputs:
pinMode(MotorPinPWMA, OUTPUT);
pinMode(MotorPinPWMB, OUTPUT);
// initialize the feedback outputs
pinMode(fb0, OUTPUT); // position reached output
for (i = 0; i < rails; i++) { // actual rail sensor outputs
pinMode(rail[i], OUTPUT);
}
}
void loop(){
// keep the dcc lib running
Dcc.process();
// read the motor current
Current = readAO(MotorPinCurrent);
// read the actual position value
posIST = readAO(sensorPin);
if (posNew==2) { // if order to change the rail
posSOLL=railPos[pos]; // get the correct destination value
DIFF=posIST-posSOLL; // compute the difference to drive to
if (DIFF >= 0) { // positive difference setting the relais to low
digitalWrite(MotorPinPWMB, LOW);
}
else { // negative difference setting the relais to low
digitalWrite(MotorPinPWMB, HIGH);
}
if (abs(DIFF) > 20) { // high speed motor control dir a
Speed = maxSpeed;
}
if (abs(DIFF) <= 20) { // low speed motor control dir a + b
Speed = minSpeed;
}
if (DIFF != 0) { // destination not arrived
while(railtimes) {
for (j=0;j<rails;j++) {
digitalWrite(rail[j],LOW);
}
railtimes=0;
}
}
if (DIFF == 0) { // destination arrived
Speed = 0;
digitalWrite(fb0, HIGH);
delay (100);
railtimes=1;
while(railtimes) {
for (j=0;j<rails;j++) {
if (pos==j) {
digitalWrite(rail[j],HIGH);
}
else {
digitalWrite(rail[j],LOW);
}
}
railtimes=0;
}
saveposIST();
delay(300);
posNew=0;
}
analogWrite(MotorPinPWMA, Speed);
}
else {
digitalWrite(fb0, LOW);
railtimes=1;
}
if (posNew==3) { // pusbutton low speed dir a; addr2 - output 2 - straight
digitalWrite(MotorPinPWMB, LOW);
analogWrite(MotorPinPWMA, minSpeed);
delay (400);
analogWrite(MotorPinPWMA, 0);
posNew = 0;
saveposIST();
}
if (posNew==4) { // pusbutton low speed dir b; addr2 - output 2 - turnout
digitalWrite(MotorPinPWMB, HIGH);
analogWrite(MotorPinPWMA, minSpeed);
delay (400);
analogWrite(MotorPinPWMA, 0);
digitalWrite(MotorPinPWMB, LOW);
posNew = 0;
saveposIST();
}
if (posNew==5) { // pusbutton high speed dir a; addr2 - output 3 - straight
digitalWrite(MotorPinPWMB, LOW);
analogWrite(MotorPinPWMA, maxSpeed);
delay (200);
analogWrite(MotorPinPWMA, 0);
posNew = 0;
}
if (posNew==6) { // pusbutton high speed dir b; addr2 - output 3 - turnout
digitalWrite(MotorPinPWMB, HIGH);
analogWrite(MotorPinPWMA, maxSpeed);
delay (200);
analogWrite(MotorPinPWMA, 0);
digitalWrite(MotorPinPWMB, LOW);
posNew = 0;
}
if (posNew==7) { // save positions; addr2 - output 4 - straight
switch (pos) {
case 0:
Dcc.setCV(519,Dcc.getCV(513));
Dcc.setCV(520,Dcc.getCV(514));
case 1:
Dcc.setCV(521,Dcc.getCV(513));
Dcc.setCV(522,Dcc.getCV(514));
case 2:
Dcc.setCV(523,Dcc.getCV(513));
Dcc.setCV(524,Dcc.getCV(514));
}
posNew = 0;
}
if (Current >= maxCurrent) {
analogWrite(MotorPinPWMA, 0);
}
}
//FUNCTIONS
// This function is called whenever a normal DCC Turnout Packet is received
void notifyDccAccState( uint16_t Addr, uint16_t BoardAddr, uint8_t OutputAddr, uint8_t State) {
/*Serial.print("notifyDccAccState: ") ;
Serial.print(Addr,DEC) ;
Serial.print(',');
Serial.print(BoardAddr,DEC) ;
Serial.print(',');
Serial.print(OutputAddr,DEC) ;
Serial.print(',');
Serial.println(State, HEX) ;*/
if (BoardAddr == Addr1 && State == 8) { // Sollposition
switch (OutputAddr) { // ungerade Zahl ist gerade (0) und abzweigend ist gerade Zahl (1)
case 1:
posState[0] = 0;
break;
case 0:
posState[0] = 1;
break;
case 3:
posState[1] = 0;
break;
case 2:
posState[1] = 1;
break;
case 5:
posState[2] = 0;
break;
case 4:
posState[2] = 1;
break;
case 7:
posState[3] = 0;
break;
case 6:
posState[3] = 1;
break;
}
}
if (BoardAddr == Addr2 && OutputAddr == 0 && State == 8) {
posNew = 1;
}
/*if (BoardAddr == Addr2 && OutputAddr == 0 && State == 0) {
posNew = 3;
}*/
if (BoardAddr == Addr2 && OutputAddr == 1 && State == 8 && posNew == 1) {
bitWrite(pos, 3, posState[3]); //binary to decimal int nr. of rail
bitWrite(pos, 2, posState[2]);
bitWrite(pos, 1, posState[1]);
bitWrite(pos, 0, posState[0]);
posNew = 2;
}
if (BoardAddr == Addr2 && OutputAddr == 3 && State == 8) {
posNew = 3;
}
if (BoardAddr == Addr2 && OutputAddr == 2 && State == 8) {
posNew = 4;
}
if (BoardAddr == Addr2 && OutputAddr == 5 && State == 8) {
posNew = 5;
}
if (BoardAddr == Addr2 && OutputAddr == 4 && State == 8) {
posNew = 6;
}
if (BoardAddr == Addr2 && OutputAddr == 7 && State == 8) { //Save position to CV
posNew = 7;
}
}
// reads the analogue inputs
int readAO(int AI){
int sum = 0;
int temp;
int i;
for (i=0; i<10; i++) { // loop through reading raw adc values AVG_NUM number of times
if (analogRead(AI) > 0) {
temp = analogRead(AI); // read the input pin
sum += temp; // store sum for averaging
//delayMicroseconds(10); // pauses for 50 microseconds
}
}
return(sum / 10); // divide sum by AVG_NUM to get average and return it
}
// saves actual position value
void saveposIST() {
CVbyte1 = (posIST >> 8) & 0x03;
CVbyte2 = posIST & 0xff;
Dcc.setCV(513,CVbyte1);
Dcc.setCV(514,CVbyte2);
}
// at programming sends acknowledge
void notifyCVAck(void)
{
Serial.println("notifyCVAck") ;
digitalWrite(CVAckPin,HIGH);
delay(6);
digitalWrite(CVAckPin,LOW);
}
// Uncomment to print all DCC Packets
/*void notifyDccMsg( DCC_MSG * Msg)
{
Serial.print("notifyDccMsg: ") ;
for(uint8_t i = 0; i < Msg->Size; i++)
{
Serial.print(Msg->Data[i], HEX);
Serial.write(' ');
}
Serial.println();
}*/
/*
unsigned long currentMillis = millis();
if (currentMillis - previousMillis > 1000) {
// save the last time you blinked the LED
previousMillis = currentMillis;
Serial.print(" posIST ");
Serial.print(posIST);
}
*/
The schematic:
Have fun!
It’s controlled by an arduino uno controller.
Software controlling is rocrail.
Hardware is very basic an supports programming in the pt mode (currently only for the address).
The arduino’s program:
tt.pde:
#include <NmraDcc.h>
#include <Stepper.h>
#define EN1 10
#define EN2 11
//init stepper
//Stepper stepper(48,3, 5, 6, 9);
Stepper stepper(48,5, 3, 6, 9);
//init DCC
NmraDcc Dcc;
DCC_MSG Packet ;
//Addresses
const byte Addr1 = Dcc.getCV(CV_ACCESSORY_DECODER_ADDRESS_LSB);
const byte Addr2 = Addr1 + 1;
const byte Addr3 = Addr1 + 2;
//declaring outputs
byte fb0 = 4; // feedback to rocrail positon reached
byte CVAckPin = 13; // dcc ack pin for programming the cv's
//int offset = { (Dcc.getCV(112) << 8) | Dcc.getCV(113) };// steps from point 0 to rail 0
//declaring inputs
byte sensorPin = 7; // pin for position detection
// variables will change:
int posState[6]; // setting correct position from dcc to motor function 0-23
int steps = 518; // steps for one lap
byte posNew = 0; // new position
byte pos; // var for position
long previousMillis = 0; // breaking var within the millis() funtion
byte CVbyte1; // helper var for CVSet()
byte CVbyte2; // helper var for CVSet()
int i;
int stepperarray[48];
int offset[48];
void setup() {
// init the serial port
Serial.begin(115200); // setup serial
// init dcc
Dcc.init( MAN_ID_DIY, 10, FLAGS_OUTPUT_ADDRESS_MODE | FLAGS_DCC_ACCESSORY_DECODER | FLAGS_ENABLE_INT0_PULL_UP, 0);
// Configure the DCC CV Programing ACK pin for an output
pinMode(CVAckPin, OUTPUT);
// initialize the outputs
pinMode(fb0, OUTPUT); // position reached output
pinMode(EN1, OUTPUT);
pinMode(EN2, OUTPUT);
// initialize the inputs
pinMode(sensorPin, INPUT);
stepper.setSpeed(30);
}
void loop() {
offset[0] = 26;
offset[24] = 26;
offset[2] = 27;
offset[26] = 27;
offset[46] = 25;
offset[22] = 25;
offset[44] = 24;
offset[20] = 24;
offset[25] = 23;
offset[1] = 24;
for (i=0;i<48;i++) {
stepperarray[i] = (int (float(steps) / float(48) * float(i)) +.5) + offset[i];
}
// keep the dcc lib running
Dcc.process();
if (posNew==2) { // if order to change the rail
digitalWrite(fb0, LOW);
analogWrite(EN1,150);
analogWrite(EN2,150);
if (pos == 63) {
// stepping to point zero
stepper.step(10);
while (digitalRead(sensorPin) == HIGH) {
stepper.step(1);
}
stepper.step(stepperarray[Dcc.getCV(114)]);
pos=Dcc.getCV(114);
}
else {
stepper.step(10);
while (digitalRead(sensorPin) == HIGH) {
stepper.step(1);
}
stepper.step(stepperarray[pos]);
}
delay(50);
analogWrite(EN1,0);
analogWrite(EN2,0);
// position - ready
digitalWrite(fb0, HIGH);
// save position
Dcc.setCV(114,pos);
posNew=0;
}
if (posNew==3) { // pusbutton step 1 left
Serial.println("stepping 1 left");
analogWrite(EN1,255);
analogWrite(EN2,255);
stepper.step(1);
delay(100);
analogWrite(EN1,0);
analogWrite(EN2,0);
posNew=0;
}
if (posNew==4) { // pusbutton step 1 left
Serial.println("stepping 1 right");
analogWrite(EN1,255);
analogWrite(EN2,255);
stepper.step(-1);
delay(100);
analogWrite(EN1,0);
analogWrite(EN2,0);
posNew=0;
}
}
//FUNCTIONS
// count the steps for one lap
/*stepper.step(10); //go out of the sensor
steps = 10;
while (digitalRead(sensorPin) == HIGH) {
stepper.step(1);
steps = steps++;
}
Serial.println(steps,DEC);
*/
// This function is called whenever a normal DCC Turnout Packet is received
void notifyDccAccState( uint16_t Addr, uint16_t BoardAddr, uint8_t OutputAddr, uint8_t State) {
/*Serial.print("notifyDccAccState: ") ;
//Serial.print(Addr,DEC) ;
//Serial.print(',');
Serial.print(BoardAddr,DEC) ;
Serial.print(',');
Serial.print(OutputAddr,DEC) ;
Serial.print(',');
Serial.println(State, HEX) ;*/
if (BoardAddr == Addr1 && State == 8) { // Sollposition
switch(OutputAddr) { // ungerade Zahl ist gerade (0) und abzweigend ist gerade Zahl (1)
case 1:
posState[0] = 0;
break;
case 0:
posState[0] = 1;
break;
case 3:
posState[1] = 0;
break;
case 2:
posState[1] = 1;
break;
case 5:
posState[2] = 0;
break;
case 4:
posState[2] = 1;
break;
case 7:
posState[3] = 0;
break;
case 6:
posState[3] = 1;
break;
}
}
if (BoardAddr == Addr2 && State == 8) { // Sollposition
switch(OutputAddr) { // ungerade Zahl ist gerade (0) und abzweigend ist gerade Zahl (1)
case 1:
posState[4] = 0;
break;
case 0:
posState[4] = 1;
break;
case 3:
posState[5] = 0;
break;
case 2:
posState[5] = 1;
break;
}
}
if (BoardAddr == Addr2 && OutputAddr == 5 && State == 8) {
posNew = 1;
}
if (posNew == 1) {
bitWrite(pos, 5, posState[5]); //binary to decimal int nr. of rail
bitWrite(pos, 4, posState[4]);
bitWrite(pos, 3, posState[3]);
bitWrite(pos, 2, posState[2]);
bitWrite(pos, 1, posState[1]);
bitWrite(pos, 0, posState[0]);
posNew = 2;
}
if (BoardAddr == Addr2 && OutputAddr == 7 && State == 8 ) { //Step 1 left
posNew = 3;
}
if (BoardAddr == Addr2 && OutputAddr == 6 && State == 8 ) { //Step 1 left
posNew = 4;
}
}
// saves actual position value
/*
void saveposIST() {
CVbyte1 = (posIST >> 8) & 0x03;
CVbyte2 = posIST & 0xff;
Dcc.setCV(513,CVbyte1);
Dcc.setCV(514,CVbyte2);
}
*/
//while programming sends acknowledge
void notifyCVAck(void) {
Serial.println("notifyCVAck");
digitalWrite(CVAckPin,HIGH);
delay(6);
digitalWrite(CVAckPin,LOW);
}
// Uncomment to print all DCC Packets
/*void notifyDccMsg( DCC_MSG * Msg) {
Serial.print("notifyDccMsg: ") ;
for(uint8_t i = 0; i < Msg->Size; i++) {
Serial.print(Msg->Data[i], HEX);
Serial.write(' ');
}
Serial.println();
}*/
/*
unsigned long currentMillis = millis();
if (currentMillis - previousMillis > 1000) {
//save the last time you blinked the LED
previousMillis = currentMillis;
Serial.print(" sensorPin ");
int a = digitalRead(sensorPin);
Serial.print(a);
}
*/
Here’s the schematic:
Have fun!

