неделя, 4 ноември 2018 г.

Самоделни подвижни буфери от подръчни материали

Тук искам да представя моята идея за подвижни буфери
изработени от подръчни материали .

Използвах за диска на буфера пласмаса от дискета за компютър
изрязах дисковете със замби 4мм но не через сечене а я закачих на дрелката и с въртене
става по хубав срез отколкото через чукане по замбата
За стебло използвах черен филър за 3Д принтер .
Слагам една капка моментно лепило на парчето филър и се стремим да уцелим средата на
диска и се получава нещо такова

дисковете са залепени на блонкит да не мърдат че ми треперят ръцете и да мога да нацеля горе долу средата не съм се справил блестящо очевидно

И като изсъхне лепилото след около 20 мин се получава така


За цилиндър на буфера ползвах тръбичка от клечка за уши от тея дето са с памучето
обаче трябва да се раздуе с ос 2мм за да се плъзга буфера свободно.
Не съм експерементирал просто така си мисля че буфера трябва да се движи дето се вика с поглед само да се прибира.

Тек идва и по проблемната част какво по дяволите да кара буфера да пружинира
Мислих умувах чесах се там дето не ме сърби щото пружини имам хиляди видове ама
много твърди подяволите не става нито от химикалка нито от запалка нито от разни
контактори и релета . А и ще е проблем също и самото закрепване. Първо рекох с пърче дунапрен или гума ама дунапрена няма достатъчно сила да върне а кумата пък иска повече натиск което на мен ми се стори че не е желателно нали идеята е буфера да се движи с поглед
но и надеждно да се връща напред когато няма натиск.
И накрая рекох да пробвам с прозрачна пласмаса това е за изолация на електроники
конкретно тази която ползвам е от електроники за палене на луминисцентни лампи
аз е ползвам и за направата на прозорци на вагони и локомотиви.

Изрязва се тънка лентичка и се сгъва на две по средата и с пинсетите стискаме хубаво згъвката


Забравих да каже че изрязаните тръбички се набиват във вагона мушкаме буфера и нагряваме леко плоска отверка или некво друго плоско железце да натиснем с него отзад бефера така че филара леко да се сплеска за да не излиза вече от тръбичката . Трябва му съвсем малко една идея просто

И вече може да преминем към залепяне на пружиното устройство . Съвсем малко лепило просто по двата ръба се слака намества се на вагона плътно до буфера и стискаме известно време с пинсетата докато залепне.



трябва да се залепи само по края за да може тая пласмаска да пружинира
И така вече буферите се движат съвсем свободно 

Тук представям просто идеята ясно е че изпълнението може да бъде много по добро от мойто
а и материалите може да са съвсем различни
Накрая се получава ей това 












неделя, 30 септември 2018 г.

Стенд за локомотиви - HO Rollenprüfstand

Това е стенд за локомотиви в мащаб Н0

В ибей разбирасе се продават готови но цените им са баснословни
и за това реших да си изработя самоделен . На мен лично ми трябва за да мога да си
тествам и замервам самоделните декодери и да им правя настройки и промени
в кода направо в движение. Разбира се стенда може да се използва и за много други цели.
Още една полезна функция е както в показаното по долу видео е да подавате захранване
само на една колоса и да си проверите коя евентуално има проблеми с токоснемането
прекъсва или не дава добър контакт.


Како ще ни е необходимо

Първо ще ни трябва подходяща основа
такава че да позволява да се плъзгат ролките и да може да се настройва разстоянието
за различни типове локомотиви.
Най елементарното което ми хрумна е кабелен канал има ги в магазините за ел материали




този е с размери 40х25 мм  но може да се ползва и друг размер подходящ

Второто нещо което ще ни е нужно са лагерчета коио обаче не е лесно да се намерят
В магазина успях да намеря само 8бр с диаметър 8мм това беше цялата наличност
освен това са и скъпи по 3лв бройката. За мой късмет нали съм техник ми попаднаха от едни изгорели вентираторчета още 8бр но с диаметър 9мм оказа се в последствие че не е проблем.

освен лагерчета ще трябват и болчета 3мм и гайка.
На болчетата е необходимо да се вземат главите на шмиргелче или с дрелка и шкурка така че да се намали диаметъра . Това се налага защото се оказа че ръбът на колелото на локомотива
опира в главата на болта вместо да контактува само с лагерчетата

И последно ще трябва и нещо на което да закрепим лагерите
аз ползвам алуминиево ъгълче продават се в железарийте за декорация на стени мебели и т.н.

моито е с размери 20х10мм но и 20х20 ще стане а и друг размер

нарязва се на по 15мм примерно 8бр понеже разполагаме с 16бр лагерчета
Нарязваме и от капака на кабелния канал 4бр по 20мм
На ъгълчетата се пробиват дупки за закрепване на лагерчетата.
От изключителна важност е дупките да се пробият на една височина на всички ъгълчета
и да са с подходящо отстояние една от друга така че като се сложат лагерчетата между тях да остане разстояние не да се опират едно в друго защото се въртят в различни посоки.
Размерите зависят изцяло от лагерчетата с които разполагате
примерно на мойте с диаметър 8мм направих дупките на 9мм а на тези 9мм на 10мм
За височината аз използвах единия канал на мойта лайсна ако вашата няма такава декорация предварително си начертайте линия преди да ги изрежете за да ви служи за ориентир
и да се получат всички на една височина защото това е важно. От прецизноста на изработката
ще зависи и качеството и функциолноста на стенда.

Като свършим с рязането пробиването и закрепването на лагерите към лайсничките
идва най трудната част да се залепят към капачетата на канала .
Трудно е защото трябва да се центроват така че после всички да са на една линия
и освен това срещуположно да са перфектно позиционирани така че колосата да е
точно перпиндикулярна малко разминаване да има и колосата ще застава крива и ще излиза



Аз ги залепих с хелметекс защото не съхне прекалено бързо и позволява корекций


И като всичко е готово ще имаме нещо подобно на това


Сложих в канала дунапрен за да го държи разпънат по стабилно е и без него работи
ама с него е по стабилно и дава и усилие да не се местят прекалено лесно ролките

И вече може да тестваме кво сме сътворили за препоръчване е първо със стар и поочукан
локомотив да не стане некой сакътлък


подава се захранване на блотовете те от своя страна ще го прехвърлят на лагерите а от там на колосите . Може да си направите кабелчета с крокодилчета за да захранвате повече от една ролка но и само на една колоса да подавате захранване пак става .
Имам подготвено и парче релса когато не са всички колоси движещи на паразитните може да
стои и релса .

Ето и малко видео на всичко в действие








неделя, 8 юли 2018 г.

101Hero PYLON 3D Printer първи сполучлив опит

Първото което трябва да се каже за принтера 101Hero е абсолютна трагедия
не струва и половината от парите си .

А сега по същество да споделя опита си и постигнатите резултати.

Исках да си отпечатам спирачен кран за вагон в мащаб Н0
понеже имам доста на които им липсват.
Рових се много за готови файлове в нета и наистина има доста
но никой от тях не отговаряше на мащаба .
За това аз се опитвах да ги преоразмеря в моя случай да ги намаля
Има обаче важна подробност че не може да намалите само едно от измеренията
ако намалите едно от тях и другите две се намаляват автоматично със същия процент.

Никой от намерените файлове не ми свърши работа и за това си нарисувах собствен
с програмата пайнт на уиндос

Вижда се ча съм го нарисувал с левия си крак
но понеже изобщо не се надявах че може да се обърне в 3д за принтиране
не се старах особено . Обаче програмата Cura_15.04.6 (само с тази версия работи принтера )
се справи и ми генерира така наречения G-код

ето снимка на първите ми опити


На първия ред са отпечатаци от файлове свалени от мрежата
на втория ред е моята картинка с различни настройки
и на пиедестал от ляво челното е оригинален кран в средата най доброто ми постижение
и две стинки за мащаб и престиж


След малко шкурене с шкурка 240

Следва боядисване бегло със черен спрей

И поставяне на мястото му



Резултата някой биха го определили като трагичен
аз ще си позволя да кажа задоволителен.
Да не забравяме че това колелеце е с диаметър 8мм
и дебелина 1мм.
Тоест опитах се да прерисувам картината Мона Лиза на Микеланджало с
валяк за боядисване и то от най големите размери . Еми с четката за боядисване на огради толкова .

понеделник, 2 юли 2018 г.

Преработване на колоси от АС за DC

Тук ще ви покажа моя метод за преработване на колоси на мерклин за променлив ток
тоест такива които не са изолирани така че да станат изолирани и да могат да се движат
по постоянно токови системи или по цифрови


Първо с клещи човки хващам оста и с въртеливи движения изваждам
двете колелца. Ако не се получава може да се нагреят с пистолет за горещ въздух.
Оста и колелцата са от различни метали и колелото се изважда много лесно
след като се нагрее


Виждал съм и други методи примерно да се среже оста по средата и да се снади после с тръбичка но това не е надеждно навсякъде.
Примерно на тоя тип вагони може да се види на снимката че шахтата за колелата е
изцяло метална и куполонга също е захванат за шахтата така че изолирането на оста по средата не върши работа. Няма да свърши работа и колело за DC системи то е изолирано само едното оста и другото колело са във верига съответно или + или - ще излязат на куполонга
и ако следващия вагон е наобратно в двата купулунга ще се серещат + и - и ще искри
много кофти даже и да се движи системата понеже връзката е хлабава и не може да даде силно късо пак е неприятно и опасно особено за DCC.


За това трябва и двете колелца да се изолират от оста.


Следваща стъпка с бургия 2,2мм защото повечето оси на мерклин са 2мм
разпробиваме отворите на колелата.
Това е хубаво да се направи на стендова бормашина или такава със стойка за да може да
се пробият отворите точно вертикално . Важно е да се стремим да са вертикални защото ако има някакъв ъгъл различен от 90 градуса после колелото ще играе .


Трета стъпка отрязваме две парченца около 1см от термосвиваема шлаухка 2мм
нанизваме едното на оста така че тя да не се подава и нагряваме само края с запалка или пистолет съвсем малко колкото да се свие и да придобие формата на оста .


Взимаме едното колело и с две ръце със силен натиско но много плавно го нанизваме
така че да се подаде оста около 4мм .После и другото по същия начин .
след това с макетен нож изрязваме от външната страна шлаухката плътно до колелата.
И сега идва пипкавата част да напаснем разстоянието между колелата
Аз процедирам така защото меренето с шублери линий и други подобни ме изнервят по принцип.
Взимаме една стрелка ква и да е
първо мерим колелата на правия участък да влязат в релсите и то не плътно да има малко свободен ход около 2мм наляво и надясно.
След това слагаме колелото на участъка от стрелката между езика и двете разклонения.
Там където е изолирано с пласмасов триъгълник а от другата страна къв релсата има
пласмасов ограничител водач който води колелото да не хване в грешната посока на стрелката.
Точно в тоя участък най важния напасваме колелото да минава свободно
това гарантира безпроблемно движение на вагоните и с максимална скорост.
Ето така ще изглежда готовото колело


Като завършим горните процедури хващаме мултицет и на пищялка с клема крокодилче
едната сонда захващаме за оста и с другата първо чукваме на оста от външния край на колелцата да писне да сме сигурни че има връзка и после проверяваме двете колелца
да не пищи.
Обикновено всичко е наред но по някога се случва шлаухката де се скъса и да прави късо
колелото с оста а това е кофти . Ако е станало така вадим колелото и повтаряме процедурата

И като сме готови слагаме ги на вагончето и си джиткаме с кеф
че сме си спестили маса пари за колела и купалунзи



неделя, 24 юни 2018 г.

DCC Dekoder с Ардуино Pro-Mini и LB1838

Това е четвъртия ми декодер изпълнен с Ардуино Pro-Mini и
този път използвах моторен драйвър LB1838.
Използвах него защото имах локомотив на фирма Joef
на който поставих мотор от сд ром който работи на 9v захранване.
Както може да се види от описанието на LB1838 тя също има макс захранване 10,5v
което е направи подходяща за моя случай.

https://www.onsemi.com/pub/Collateral/LB1838M-D.PDF


Ако разгледате файла ще забележите че се управлява малко по различно
от предходните чипове и това налага леки корекций на кода .
Впредните схеми съм забравил да отбележа че масата на ардуино също се връзва към общата маса надявам се да сте се сетили и сами за това .

Ето я и самата електлическа схема

Използвал съм друг тип оптрон и стабилизатор на 9в .
Също така използвах за осветление два светодиода вместо само един
и стойноста на съпротивлението от 300 намалих на 100 ома
разбира се двата диода трябва да са абсолютно еднакви аз използвах два от светодиодна лента.


Това е и кода който трябва да заредите в ардуино



/* Декодер за локомотиви H0 с Arduino nano и Н-bridge
 * Библиотека NmraDcc.h
 * Стандартният адрес на локомотива е #define This_Decoder_Address
 * Изходите PWM на Arduino Nano са 5 и 6 
 * Светлините са свързани към пинове 3 и 4 на Arduino Nano
  * Основни CV: CV2 = Начално напрежение; CV3 = скорост на ускоряване; CV4 = степен на спиране; CV5 = максимално скоростно напрежение
*/
#include <NmraDcc.h>

#define This_Decoder_Address 4 //Променете този номер, за да промените адреса на локомотива
const int FunctionPin0 = 3;// pin 3 and 4 light
//const int FunctionPin1 = 7;
const int FunctionPin1 = LED_BUILTIN;
const int FunctionPin2 = 8;
const int FunctionPin3 = 9;
const int FunctionPin4 = 10;
const int DccAckPin = 15 ;//за индикация на промяна на CV
const int PWM_MAX = 254;
//const int left = 10;        //Pin изход към left L293
//const int right = 11;       //Pin изход към right L293
const int velPwm0 = 5;  //PWM     
const int velPwm1 = 6;  // L-напред   H-назад
const int lucesDelanteras = 3; //pin изход към предни светлини
const int lucesTraseras = 4;   //pin изход към задни светлини
int currentSpeed = 0;
int rateSteps;
int acSpeed;
int locSpeed = 0;
int rateSpeed = 0;
int dirState = 0;     //Променлива промяна на посоката
int dirFlag1 = 0;
int dirFlag2 = 0;
int steps;            //Pasos (14, 28, 128) стъпки
//int maniobras = 0;    //маневрени
int Luces = 0;        //Variable включване на светлините
//-------------CV конфигуриране
int CV2 = 40;        //начално напрежение за скорост 1
int CV3 = 4;          //Степен на ускоряване (CV3 * intervalAcc)
int CV4 = 4;          //Скорост на спиране (CV4 * intervalDec)
int CV5 = 254;        //Максимално напрежение
//-------------
int topSpeed =  CV5;
long previousDebug = 0;
long previousAcc = 0;
long previousDec = 0;
long intervalDebug = (500);
long intervalAcc = (25 * CV3);
long intervalDec = (25 * CV4);
struct CVPair
{
  uint16_t  CV;
  uint8_t   Value;
};

CVPair FactoryDefaultCVs [] =
{
  // The CV Below defines the Short DCC Address
  {CV_MULTIFUNCTION_PRIMARY_ADDRESS, This_Decoder_Address},
  {CV_ACCESSORY_DECODER_ADDRESS_MSB, 0},
  // These two CVs define the Long DCC Address
  {CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB, 0},
  {CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB, This_Decoder_Address},

  // ONLY uncomment 1 CV_29_CONFIG line below as approprate
  //  {CV_29_CONFIG,                                      0}, // Short Address 14 Speed Steps
  {CV_29_CONFIG,                       CV29_F0_LOCATION}, // Short Address 28/128 Speed Steps
  //  {CV_29_CONFIG, CV29_EXT_ADDRESSING | CV29_F0_LOCATION}, // Long  Address 28/128 Speed Steps
};

NmraDcc  Dcc ;
DCC_MSG  Packet ;

uint8_t FactoryDefaultCVIndex = 0;

// Uncomment this line below to force resetting the CVs back to Factory Defaults
// FactoryDefaultCVIndex = sizeof(FactoryDefaultCVs)/sizeof(CVPair);

void notifyCVResetFactoryDefault()
{
  // Make FactoryDefaultCVIndex non-zero and equal to num CV's to be reset
  // to flag to the loop() function that a reset to Factory Defaults needs to be done
  FactoryDefaultCVIndex = sizeof(FactoryDefaultCVs) / sizeof(CVPair);
};

// Uncomment the #define below to print all Speed Packets
#define NOTIFY_DCC_SPEED
#ifdef  NOTIFY_DCC_SPEED
void notifyDccSpeed( uint16_t Addr, DCC_ADDR_TYPE AddrType, uint8_t Speed, DCC_DIRECTION Dir, DCC_SPEED_STEPS SpeedSteps )
{
  //  locSpeed = Speed;
  acSpeed = Speed;
  int SpeedStep = (SpeedSteps - 1);
  steps = SpeedStep;
  dirState = Dir;
};
#endif

// Uncomment the #define below to print all Function Packets
#define NOTIFY_DCC_FUNC
//#ifdef  NOTIFY_DCC_FUNC
void notifyDccFunc(uint16_t Addr, DCC_ADDR_TYPE AddrType, FN_GROUP FuncGrp, uint8_t FuncState)
{
  
  switch ( FuncGrp )
  {
#ifdef NMRA_DCC_ENABLE_14_SPEED_STEP_MODE
    case FN_0:
      //  Serial.print(" FN0: ");
      //  Serial.println((FuncState & FN_BIT_00) ? "1  " : "0  ");
      break;
#endif
    case FN_0_4:
      exec_function( 0, (FuncState & FN_BIT_00) >> 4 );
      exec_function( 1, (FuncState & FN_BIT_01));
      exec_function( 2, (FuncState & FN_BIT_02) >> 1);
      exec_function( 3, (FuncState & FN_BIT_03) >> 2 );
      exec_function( 4, (FuncState & FN_BIT_04) >> 3 );
      if (Dcc.getCV(CV_29_CONFIG) & CV29_F0_LOCATION) // Only process Function 0 in this packet if we're not in Speed Step 14 Mode
      {
        //  Serial.print(" FN 0: ");
        //  Serial.print((FuncState & FN_BIT_00) ? "1  " : "0  ");
        // delay (100);
      }
      break;

    case FN_5_8:
      exec_function( 5, (FuncState & FN_BIT_05));
      exec_function( 6, (FuncState & FN_BIT_06) >> 1 );
      exec_function( 7, (FuncState & FN_BIT_07) >> 2 );
      exec_function( 8, (FuncState & FN_BIT_08) >> 3 );
      break;

    case FN_9_12:
      exec_function( 9, (FuncState & FN_BIT_09));
      exec_function( 10, (FuncState & FN_BIT_10) >> 1 );
      exec_function( 11, (FuncState & FN_BIT_11) >> 2 );
      exec_function( 12, (FuncState & FN_BIT_12) >> 3 );
      break;
  }
}
void exec_function (int f_index, int FuncState)  
{
  switch (f_index) {
     case 0:
    FuncState ? Luces = 1 : Luces = 0;
      break;
    case 1:
    FuncState ? digitalWrite(FunctionPin1, 1) : digitalWrite(FunctionPin1, 0);
      break;
    case 2:
    FuncState ? digitalWrite(FunctionPin2, 1) : digitalWrite(FunctionPin2, 0);
      break;
    case 3:
    FuncState ? digitalWrite(FunctionPin3, 1) : digitalWrite(FunctionPin3, 0);  
      break;
    case 4:
    FuncState ? digitalWrite(FunctionPin4, 1) : digitalWrite(FunctionPin4, 0);  
      break;  
    default:
      break;
  }
}

// This function is called by the NmraDcc library when a DCC ACK needs to be sent
// Calling this function should cause an increased 60ma current drain on the power supply for 6ms to ACK a CV Read

void notifyCVAck(void)
{
  digitalWrite( DccAckPin, HIGH );
  delay( 8 );
  digitalWrite( DccAckPin, LOW );
}

void setup()
{
  pinMode(velPwm0, OUTPUT);//pin 5
  pinMode(velPwm1, OUTPUT);//pin 6
  pinMode (lucesDelanteras, OUTPUT);//pin 3
  pinMode (lucesTraseras, OUTPUT);//pin 4
  pinMode (FunctionPin1, OUTPUT);//pin 7
  digitalWrite(FunctionPin1, 0);
  pinMode (FunctionPin2, OUTPUT);//pin 8
  digitalWrite(FunctionPin2, 0);
  pinMode (FunctionPin3, OUTPUT);//pin 9
  digitalWrite(FunctionPin3, 0);
  pinMode (FunctionPin4, OUTPUT);//pin 10
  digitalWrite(FunctionPin4, 0);

  // Configure the DCC CV Programing ACK pin for an output
  pinMode( DccAckPin, OUTPUT );
  digitalWrite( DccAckPin, LOW );

  // Setup which External Interrupt, the Pin it's associated with that we're using and enable the Pull-Up
  // Първият параметър е номерът за прекъсване, вторият е pin, а третият е състоянието на вътрешния pullup резистор (1 означава разрешено )
  Dcc.pin(0, 2, 0);

  // Call the main DCC Init function to enable the DCC Receiver
  //Dcc.init( MAN_ID_DIY, 10, CV29_ACCESSORY_DECODER | CV29_OUTPUT_ADDRESS_MODE, 0 );
//Първите два параметъра са производителят и версията на декодера С третия параметър можете да промените по подразбиране поведението на библиотеката: последният е адресът EEPROM, от който библиотеката съхранява своите стойности
  Dcc.init( MAN_ID_DIY, 10, FLAGS_MY_ADDRESS_ONLY, 0 );

  // Uncomment to force CV Reset to Factory Defaults
  notifyCVResetFactoryDefault();
}

void loop()
{
  // You MUST call the NmraDcc.process() method frequently from the Arduino loop() function for correct library operation
  Dcc.process();

  if ( FactoryDefaultCVIndex && Dcc.isSetCVReady())
  {
    FactoryDefaultCVIndex--; // Decrement first as initially it is the size of the array
    Dcc.setCV( FactoryDefaultCVs[FactoryDefaultCVIndex].CV, FactoryDefaultCVs[FactoryDefaultCVIndex].Value);
  }

  if (dirState == 0) {
    if (dirFlag1 == 1) {
      int locSpeedup = locSpeed;
      for (int locSpeed = locSpeedup; locSpeed > CV2; locSpeed--) {
        digitalWrite (velPwm1, LOW);
        analogWrite (velPwm0, locSpeed);
        delay(intervalDec);
      }
      dirState0();

      for (int locSpeed = CV2; locSpeed < locSpeedup; locSpeed++) {
        digitalWrite (velPwm1, LOW);
        analogWrite (velPwm0, locSpeed);
        delay(intervalAcc);
      }
      dirFlag1 = 0;
    }
    dirFlag2 = 1;
    dirState0();
  }

if (dirState == 1) {
    if (dirFlag2 == 1) {
      int locSpeedup = locSpeed;
      for (int locSpeed = locSpeedup; locSpeed > CV2; locSpeed--) {
        digitalWrite (velPwm1, HIGH);
        analogWrite (velPwm0, locSpeed);
        delay(intervalDec);
      }
      dirState1();

      for (int locSpeed = CV2; locSpeed < locSpeedup; locSpeed++) {
        digitalWrite (velPwm1, HIGH);
        analogWrite (velPwm0, locSpeed);
        delay(intervalAcc);
      }
      dirFlag2 = 0;
    }
    dirFlag1 = 1;
    dirState1();
  }
  if (currentSpeed <= 1) {
    locSpeed = 0;
    digitalWrite (velPwm0, LOW);
    digitalWrite (velPwm1, LOW);
  }
  else {
    rateSpeed = ((PWM_MAX - CV2) / steps);
  }
  if (currentSpeed != acSpeed ) { //ако currentSteps е различен от стъпките
    if (currentSpeed < acSpeed) {
      Acc();
    }
    if (currentSpeed > acSpeed) {
      Dec();
    }
  }
  
}
void Acc() 
{
  unsigned long currentAccMillis = millis();
  if (currentAccMillis - previousAcc > intervalAcc ) {
    previousAcc = currentAccMillis;
    locSpeed = (CV2 + (currentSpeed * rateSpeed));

    if (locSpeed >= CV5) {  //ако скоростта на локомотива е по - голяма от CV5
      locSpeed = CV5;
    }
    currentSpeed = (currentSpeed + 1);
    if (currentSpeed >= acSpeed) {
      currentSpeed = acSpeed;
    }
  }
  return;
}
void Dec() 
{
  unsigned long currentDecMillis = millis();
  if (currentDecMillis - previousDec > intervalDec) {
    previousDec = currentDecMillis;
    locSpeed = (CV2 + (currentSpeed * rateSpeed));
    currentSpeed = (currentSpeed - 1);
    if (currentSpeed <= acSpeed) {
      currentSpeed = acSpeed;
   }
    return;
  }
}
void dirState0() 
{
  digitalWrite (velPwm1, LOW);
  //analogWrite (velPwm0, locSpeed);
locSpeed > (CV5-1) ? digitalWrite(velPwm0, HIGH) : analogWrite (velPwm0, locSpeed); //ако locSpeed е на макс пуска макс захранване не импулси

  if (Luces == 1) {
    digitalWrite (lucesDelanteras, HIGH);
    digitalWrite (lucesTraseras, LOW);
  }
  else {
    digitalWrite (lucesDelanteras, LOW);
    digitalWrite (lucesTraseras, LOW);
  }
  return;
}
void dirState1() 
{
  digitalWrite (velPwm1, HIGH);
  //analogWrite (velPwm1, locSpeed);
locSpeed > (CV5-1) ? digitalWrite(velPwm0, HIGH) : analogWrite (velPwm0, locSpeed); //ако locSpeed е на макс пуска макс захранване не импулси

  if (Luces == 1) {
    digitalWrite (lucesDelanteras, LOW);
    digitalWrite (lucesTraseras, HIGH);
  }
  else {
    digitalWrite (lucesDelanteras, LOW);
    digitalWrite (lucesTraseras, LOW);
  }
  return;
}

Ето и две снимки на готовия вече лок
изпълнението ми може да получи оценка ужасно 
но обещавам следващия вече да е направен както трябва


И малко видео за нагледност как се държи на релсите локомотива



понеделник, 23 април 2018 г.

DCC Dekoder с Ардуино Pro-Mini и BA6209

Това ще бъде третия ми декодер изпълнен с Ардуино Pro-Mini
Този път за управление на мотора ще използвам интеграла BA6209
Кода ще бъде абсолютно същия като от първия ми пост
защото този интеграл се управлява с два входа пиновете 5 и 6
които по случайност съвпадат с пиновете 5 и 6 на Ардуино Pro-Mini
и ща бъдат вързани 5 със 5 и 6 със 6 като може да се види от следната
схема която ще ползвам




Ето и самия код за ардуино същия е като в първия ми проект
с малки промени адреса е вече 6 и CV2 = 100 но това
са настройки които зависят от конкретния двигател и драйвъра за управлението му
За функцията F1 съм закачил вградения светодиот на ардуиното понеже за конкретния локомотив няма за какво да я ползвам друго

/* Декодер за локомотиви H0 с Arduino nano и BA6209
 * Библиотека NmraDcc.h
 * Стандартният адрес на локомотива е #define This_Decoder_Address
 * Изходите PWM на Arduino Nano са 5 и 6 
 * Светлините са свързани към пинове 3 и 4 на Arduino Nano
  * Основни CV: CV2 = Начално напрежение; CV3 = скорост на ускоряване; CV4 = степен на спиране; CV5 = максимално скоростно напрежение
*/
#include <NmraDcc.h>

#define This_Decoder_Address 6 //Променете този номер, за да промените адреса на локомотива
const int FunctionPin0 = 3;// pin 3 and 4 light
//const int FunctionPin1 = 7;
const int FunctionPin1 = LED_BUILTIN;
const int FunctionPin2 = 8;
const int FunctionPin3 = 9;
const int FunctionPin4 = 10;
const int DccAckPin = 15 ;//за индикация на промяна на CV
const int PWM_MAX = 254;
//const int left = 10;        //Pin изход към left L293
//const int right = 11;       //Pin изход към right L293
const int velPwm0 = 5;       
const int velPwm1 = 6;
const int lucesDelanteras = 3; //pin изход към предни светлини
const int lucesTraseras = 4;   //pin изход към задни светлини
int currentSpeed = 0;
int rateSteps;
int acSpeed;
int locSpeed = 0;
int rateSpeed = 0;
int dirState = 0;     //Променлива промяна на посоката
int dirFlag1 = 0;
int dirFlag2 = 0;
int steps;            //Pasos (14, 28, 128) стъпки
//int maniobras = 0;    //маневрени
int Luces = 0;        //Variable включване на светлините
//-------------CV конфигуриране
int CV2 = 100;        //начално напрежение за скорост 1
int CV3 = 4;          //Степен на ускоряване (CV3 * intervalAcc)
int CV4 = 4;          //Скорост на спиране (CV4 * intervalDec)
int CV5 = 254;        //Максимално напрежение
//-------------
int topSpeed =  CV5;
long previousDebug = 0;
long previousAcc = 0;
long previousDec = 0;
long intervalDebug = (500);
long intervalAcc = (25 * CV3);
long intervalDec = (25 * CV4);
struct CVPair
{
  uint16_t  CV;
  uint8_t   Value;
};

CVPair FactoryDefaultCVs [] =
{
  // The CV Below defines the Short DCC Address
  {CV_MULTIFUNCTION_PRIMARY_ADDRESS, This_Decoder_Address},
  {CV_ACCESSORY_DECODER_ADDRESS_MSB, 0},
  // These two CVs define the Long DCC Address
  {CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB, 0},
  {CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB, This_Decoder_Address},

  // ONLY uncomment 1 CV_29_CONFIG line below as approprate
  //  {CV_29_CONFIG,                                      0}, // Short Address 14 Speed Steps
  {CV_29_CONFIG,                       CV29_F0_LOCATION}, // Short Address 28/128 Speed Steps
  //  {CV_29_CONFIG, CV29_EXT_ADDRESSING | CV29_F0_LOCATION}, // Long  Address 28/128 Speed Steps
};

NmraDcc  Dcc ;
DCC_MSG  Packet ;

uint8_t FactoryDefaultCVIndex = 0;

// Uncomment this line below to force resetting the CVs back to Factory Defaults
// FactoryDefaultCVIndex = sizeof(FactoryDefaultCVs)/sizeof(CVPair);

void notifyCVResetFactoryDefault()
{
  // Make FactoryDefaultCVIndex non-zero and equal to num CV's to be reset
  // to flag to the loop() function that a reset to Factory Defaults needs to be done
  FactoryDefaultCVIndex = sizeof(FactoryDefaultCVs) / sizeof(CVPair);
};

// Uncomment the #define below to print all Speed Packets
#define NOTIFY_DCC_SPEED
#ifdef  NOTIFY_DCC_SPEED
void notifyDccSpeed( uint16_t Addr, DCC_ADDR_TYPE AddrType, uint8_t Speed, DCC_DIRECTION Dir, DCC_SPEED_STEPS SpeedSteps )
{
  // Serial.print("notifyDccSpeed: Addr: ");
  // Serial.print(Addr, DEC);
  // Serial.print( (AddrType == DCC_ADDR_SHORT) ? "-S" : "-L" );
  // Serial.print(" Speed: ");
  // Serial.print(Speed, DEC);
  //  locSpeed = Speed;
  acSpeed = Speed;
  // Serial.print(" Steps: ");
  int SpeedStep = (SpeedSteps - 1);
  steps = SpeedStep;
  //  Serial.print(SpeedStep, DEC);
  //  Serial.print(" Dir: ");
  //  Serial.println( (Dir == DCC_DIR_FWD) ? "Forward" : "Reverse" );
  dirState = Dir;
};
#endif

// Uncomment the #define below to print all Function Packets
#define NOTIFY_DCC_FUNC
//#ifdef  NOTIFY_DCC_FUNC
void notifyDccFunc(uint16_t Addr, DCC_ADDR_TYPE AddrType, FN_GROUP FuncGrp, uint8_t FuncState)
{
  // Serial.print("notifyDccFunc: Addr: ");
  //Serial.print(Addr, DEC);
  //Serial.print( (AddrType == DCC_ADDR_SHORT) ? 'S' : 'L' );
  //Serial.print("  Function Group: ");
  //Serial.print(FuncGrp, DEC);
  switch ( FuncGrp )
  {
#ifdef NMRA_DCC_ENABLE_14_SPEED_STEP_MODE
    case FN_0:
      //  Serial.print(" FN0: ");
      //  Serial.println((FuncState & FN_BIT_00) ? "1  " : "0  ");
      break;
#endif
    case FN_0_4:
      exec_function( 0, (FuncState & FN_BIT_00) >> 4 );
      exec_function( 1, (FuncState & FN_BIT_01));
      exec_function( 2, (FuncState & FN_BIT_02) >> 1);
      exec_function( 3, (FuncState & FN_BIT_03) >> 2 );
      exec_function( 4, (FuncState & FN_BIT_04) >> 3 );
      if (Dcc.getCV(CV_29_CONFIG) & CV29_F0_LOCATION) // Only process Function 0 in this packet if we're not in Speed Step 14 Mode
      {
        //  Serial.print(" FN 0: ");
        //  Serial.print((FuncState & FN_BIT_00) ? "1  " : "0  ");
        // delay (100);
      }
      break;

    case FN_5_8:
      exec_function( 5, (FuncState & FN_BIT_05));
      exec_function( 6, (FuncState & FN_BIT_06) >> 1 );
      exec_function( 7, (FuncState & FN_BIT_07) >> 2 );
      exec_function( 8, (FuncState & FN_BIT_08) >> 3 );
      break;

    case FN_9_12:
      exec_function( 9, (FuncState & FN_BIT_09));
      exec_function( 10, (FuncState & FN_BIT_10) >> 1 );
      exec_function( 11, (FuncState & FN_BIT_11) >> 2 );
      exec_function( 12, (FuncState & FN_BIT_12) >> 3 );
      break;
  }
}
void exec_function (int f_index, int FuncState)  
{
  switch (f_index) {
    case 0:
      if (FuncState == 1) {
        Luces = 1;
      }
      else {
        Luces = 0;
      }
    case 1:
    FuncState ? digitalWrite(FunctionPin1, 1) : digitalWrite(FunctionPin1, 0);
      break;
    case 2:
    FuncState ? digitalWrite(FunctionPin2, 1) : digitalWrite(FunctionPin2, 0);
      break;
    case 3:
    FuncState ? digitalWrite(FunctionPin3, 1) : digitalWrite(FunctionPin3, 0);  
      break;
    case 4:
    FuncState ? digitalWrite(FunctionPin4, 1) : digitalWrite(FunctionPin4, 0);  
      break;  
    default:
      break;
  }
}

// This function is called by the NmraDcc library when a DCC ACK needs to be sent
// Calling this function should cause an increased 60ma current drain on the power supply for 6ms to ACK a CV Read

void notifyCVAck(void)
{
  //Serial.println("notifyCVAck") ;

  digitalWrite( DccAckPin, HIGH );
  delay( 8 );
  digitalWrite( DccAckPin, LOW );
}

void setup()
{
  pinMode(velPwm0, OUTPUT);//pin 5
  pinMode(velPwm1, OUTPUT);//pin 6
  pinMode (lucesDelanteras, OUTPUT);//pin 3
  pinMode (lucesTraseras, OUTPUT);//pin 4
  pinMode (FunctionPin1, OUTPUT);//pin 7
  digitalWrite(FunctionPin1, 0);
  pinMode (FunctionPin2, OUTPUT);//pin 8
  digitalWrite(FunctionPin2, 0);
  pinMode (FunctionPin3, OUTPUT);//pin 9
  digitalWrite(FunctionPin3, 0);
  pinMode (FunctionPin4, OUTPUT);//pin 10
  digitalWrite(FunctionPin4, 0);
  Serial.begin(115200);
  Serial.println("NMRA Dcc Multifunction Decoder Demo 1");

  // Configure the DCC CV Programing ACK pin for an output
  pinMode( DccAckPin, OUTPUT );
  digitalWrite( DccAckPin, LOW );

  // Setup which External Interrupt, the Pin it's associated with that we're using and enable the Pull-Up
  // Първият параметър е номерът за прекъсване, вторият е pin, а третият е състоянието на вътрешния pullup резистор (1 означава разрешено )
  Dcc.pin(0, 2, 0);

  // Call the main DCC Init function to enable the DCC Receiver
  //Dcc.init( MAN_ID_DIY, 10, CV29_ACCESSORY_DECODER | CV29_OUTPUT_ADDRESS_MODE, 0 );
//Първите два параметъра са производителят и версията на декодера С третия параметър можете да промените по подразбиране поведението на библиотеката: последният е адресът EEPROM, от който библиотеката съхранява своите стойности
  Dcc.init( MAN_ID_DIY, 10, FLAGS_MY_ADDRESS_ONLY, 0 );

  // Uncomment to force CV Reset to Factory Defaults
  notifyCVResetFactoryDefault();
}

void loop()
{
  // You MUST call the NmraDcc.process() method frequently from the Arduino loop() function for correct library operation
  Dcc.process();

  if ( FactoryDefaultCVIndex && Dcc.isSetCVReady())
  {
    FactoryDefaultCVIndex--; // Decrement first as initially it is the size of the array
    Dcc.setCV( FactoryDefaultCVs[FactoryDefaultCVIndex].CV, FactoryDefaultCVs[FactoryDefaultCVIndex].Value);
  }

  if (dirState == 0) {
    if (dirFlag1 == 1) {
      int locSpeedup = locSpeed;
      for (int locSpeed = locSpeedup; locSpeed > CV2; locSpeed--) {
        digitalWrite (velPwm1, LOW);
        analogWrite (velPwm0, locSpeed);
        delay(intervalDec);
      }
      dirState0();

      for (int locSpeed = CV2; locSpeed < locSpeedup; locSpeed++) {
        digitalWrite (velPwm1, LOW);
        analogWrite (velPwm0, locSpeed);
        delay(intervalAcc);
      }
      dirFlag1 = 0;
    }
    dirFlag2 = 1;
    dirState0();
  }

if (dirState == 1) {
    if (dirFlag2 == 1) {
      int locSpeedup = locSpeed;
      for (int locSpeed = locSpeedup; locSpeed > CV2; locSpeed--) {
        digitalWrite (velPwm0, LOW);
        analogWrite (velPwm1, locSpeed);
        delay(intervalDec);
      }
      dirState1();

      for (int locSpeed = CV2; locSpeed < locSpeedup; locSpeed++) {
        digitalWrite (velPwm0, LOW);
        analogWrite (velPwm1, locSpeed);
        delay(intervalAcc);
      }
      dirFlag2 = 0;
    }
    dirFlag1 = 1;
    dirState1();
  }
  if (currentSpeed <= 1) {
    locSpeed = 0;
    digitalWrite (velPwm0, LOW);
    digitalWrite (velPwm1, LOW);
  }
  else {
    rateSpeed = ((PWM_MAX - CV2) / steps);
  }
  if (currentSpeed != acSpeed ) { //ако currentSteps е различен от стъпките
    if (currentSpeed < acSpeed) {
      Acc();
    }
    if (currentSpeed > acSpeed) {
      Dec();
    }
  }
  //analogWrite (velPwm, locSpeed);
  Debugger();
}
void Acc() 
{
  unsigned long currentAccMillis = millis();
  if (currentAccMillis - previousAcc > intervalAcc ) {
    previousAcc = currentAccMillis;
    locSpeed = (CV2 + (currentSpeed * rateSpeed));

    if (locSpeed >= CV5) {  //ако скоростта на локомотива е по - голяма от CV5
      locSpeed = CV5;
    }
    currentSpeed = (currentSpeed + 1);
    if (currentSpeed >= acSpeed) {
      currentSpeed = acSpeed;
    }
  }
  return;
}
void Dec() 
{
  unsigned long currentDecMillis = millis();
  if (currentDecMillis - previousDec > intervalDec) {
    previousDec = currentDecMillis;
    locSpeed = (CV2 + (currentSpeed * rateSpeed));
    currentSpeed = (currentSpeed - 1);
    if (currentSpeed <= acSpeed) {
      currentSpeed = acSpeed;
   }
    return;
  }
}
void dirState0() 
{
  digitalWrite (velPwm1, LOW);
  analogWrite (velPwm0, locSpeed);

  if (Luces == 1) {
    digitalWrite (lucesDelanteras, HIGH);
    digitalWrite (lucesTraseras, LOW);
  }
  else {
    digitalWrite (lucesDelanteras, LOW);
    digitalWrite (lucesTraseras, LOW);
  }
  return;
}
void dirState1() 
{
  digitalWrite (velPwm0, LOW);
  analogWrite (velPwm1, locSpeed);

  if (Luces == 1) {
    digitalWrite (lucesDelanteras, LOW);
    digitalWrite (lucesTraseras, HIGH);
  }
  else {
    digitalWrite (lucesDelanteras, LOW);
    digitalWrite (lucesTraseras, LOW);
  }
  return;
}
void Debugger() 
{
  unsigned long currentDebugMillis = millis();
  if (currentDebugMillis - previousDebug > intervalDebug) {
    previousDebug = currentDebugMillis;
    Serial.print(" Adr N: ");
    Serial.print(This_Decoder_Address);
    Serial.print(" sped PWM : ");
    Serial.print(locSpeed);
    Serial.print(" step : ");
    Serial.print(steps, DEC);
    Serial.print(" Dir: ");
    //Serial.println( (dirState == DCC_DIR_FWD) ? "Forward" : "Reverse" );
    Serial.println(dirState);
  }
  return;
}

Накрая ми се ще да спомена някой проблеми които могат да възникнат
поради факта че аз използвам най различни оптрони каквито имам същото е и за диода
Ако декодера не разпознава командите тоест на ардуиното свети червения диот
че има захранване от релсите но не реагира на командите на станцията
на мен ми се наложи да намаля стойноста на съпротивлението R3 по схемата
това което е във веригата на светодиода на оптрона .За различните оптрони стойноста е различна и варира от 4,7 к до 2,2к . Това ми отне малко време докато го разбера
защото го гледам на осцилоскопа импулсите са си перфектни и чак като се загледах по внимателно видях че при голяма стойност на съпротивлението дефакто П-образния импулс не слиза под 1волт и съответно ардуиното не го разпознавакато логическа 0 .
С намаляването на стойноста на съпротивлението от 4,7к на 3,6к или даже и по малко на 2,4к
нещата вече се оправят .Разбира се това зависи и от използвания диот така че аз закачвам на мястото на съпротивлението един потенциометър от 6,8к и едно ардуино уно с инсталирано на него примера от NmraDcc библиотеката NmraDccMultiFunctionDecoder_1 
закачва се пин 2 и + и - и отваряте серйния монитор и започвате бавно да намалявате потенциометара докато на екрана започнат да вървят командите след това измервате съпротивлението и слагате стандартна по малка стойност от измерената .
И друго нещо което може да възникне като проблем е да объркате колектор и емитер на транзистора на оптрона .Въпреки че аз за всеки отварям файла на производителя
това не гарантира че инфото е коректно казвам го защото два пъти ми се е случвало .
Ако всичко е вързано както трябва схемата тръгва от раз
и единствените настройки които трябва да направите в последствие евентуално е
стойноста на CV2 = 100  В зависимост от използвания мотор и драйвър може да варира от 60 до 120 . Но тя може и от централата да се настройва както и останалите от CV1 до CV5
Аз обаче предпочитам да го настроя в програмата и да презаредя много по лесно ми е .

Ето и две снимки на монтираните части към шасито на локомотива