Gump's Universal K'NEX Coaster System
#21
Posted 19 March 2012 - 01:40 PM
#22
Posted 21 March 2012 - 03:26 PM
When I built Whirlwind one of the motors I had ran in the opposite direction of the others I used. It actually made combining motors on the same drive axle much better looking as I could put them on opposite sides of the white gear.
I now have 8 electric motors in total. I checked them all last night and found that 2 of them run opposite the other 6. Pretty significant in my small sample size.
How uncommon is this in your experience Gump? obviously if you are not expecting it it can really break things.
Comet Recreation still underway.
Proof you never grow up if you keep playing with toys!
#23
Posted 21 March 2012 - 04:32 PM
SSCoasters Administrator
The SSCoasters Forum Rules
#24
Posted 25 April 2012 - 11:48 AM
//Gump's Universal K'NEX Coaster System applied on Balrog /*-------------------------------------------------------------- -------------------------------PINS----------------------------- --------------------------------------------------------------*/ /* ER IS EEN PROBLEEM MET 12!!! PINS 47 en 52 Hij wordt niet positief, maar wel negatief. Pin 47 wil dus niet high worden. Slechte soldeerverbinding? */ ///////////////////////////////////////////////////////////12////14/// int motor_non_pwm[] = {33,34,35,36,37,38,39,40,41,42,43,44,47,46,45,48}; //0-15 motors TOTAL int motor_pwm[] = {12,11,10, 9, 8, 7, 6, 5, 4, 3, 2,53,52,51,50,49}; //0-10 motors PWM ; 11-16 motors non-PWM int sensor_pin[] = {22,23,24,25,26,27,28,29,30,31,32,A15,A14,A13,A12,A11,A10,A9,A8,A7}; //20 sensors int button_pin = A1; //Start button int LED_pin = 13; //LED start button /*-------------------------------------------------------------- -----------------------------VARIABLES-------------------------- --------------------------------------------------------------*/ //Servos #include <Servo.h> Servo servo_gates; //Servo servo_1; //Servo servo_2; //Servo servo_3; //Servo servo_4; //Blocks boolean block_station_in; boolean block_station_uit; boolean block_remmen; boolean block_mcbr; boolean block_lift; boolean block_lift_down; //Enkel voor initialisatie. //States int Init_State = 0; int Station_In_State = 0; int Station_Uit_State = 0; int Remmen_State = 0; int Mcbr_State = 0; int Lift_State = 0; //Motor variables int motor_dead_zone_high = 100; int motor_dead_zone_low = -100; int skip_dead_zone; int motor_current_speed[16] = {0}; int speed_step[16] = {0}; int xMotor_non_pwm[16] = {0}; int xMotor_pwm[16] = {0}; //Sensors boolean sensor_post_station; boolean sensor_station_in; boolean sensor_station_uit; boolean sensor_pre_station; boolean sensor_transfer_back; boolean sensor_transfer_front; boolean sensor_remmen; boolean sensor_post_mcbr; boolean sensor_stop_mcbr; boolean sensor_pre_mcbr; boolean sensor_post_lift_top; boolean sensor_pre_lift_top; //Button and LED boolean LED_State = LOW; boolean button_State = LOW; //Timers unsigned long currentMillis = 0; unsigned long previousMillisMotor[16] = {0}; unsigned long BlinkPrevious = 0; long InitPrevious; long StationInPrevious; long StationUitPrevious; int InitTimer; int StationInTimer; int StationUitTimer; //Misc boolean internal_station_move; /*-------------------------------------------------------------- -------------------------------SETUP---------------------------- --------------------------------------------------------------*/ void setup() { Serial.begin(9600); for(int i = 0; i<=15; i++) { pinMode(motor_non_pwm[i],OUTPUT); pinMode(motor_pwm[i],OUTPUT); } pinMode(LED_pin,OUTPUT); for(int i = 0; i<=19; i++) { pinMode(sensor_pin[i],INPUT); } pinMode(button_pin,INPUT); servo_gates.attach(A6); //servo_1.attach(A5); //servo_2.attach(A4); //servo_3.attach(A3); //servo_4.attach(A2); } /*-------------------------------------------------------------- -------------------------------LOOP----------------------------- --------------------------------------------------------------*/ void loop() { PII(); currentMillis = millis(); if(Init_State == -1) { station_in(); station_uit(); eindremmen(); mcbr(); lift(); } else { initialisatie(); } PIQ(); } /*-------------------------------------------------------------- --------------------------USER FUNCTIONS------------------------ --------------------------------------------------------------*/ void PII(){ //Proces Image Input (Ingangsregister) button_State = digitalRead(button_pin); sensor_post_station = digitalRead(sensor_pin[0]); sensor_station_in = digitalRead(sensor_pin[1]); sensor_station_uit = digitalRead(sensor_pin[2]); sensor_pre_station = digitalRead(sensor_pin[3]); sensor_transfer_back = digitalRead(sensor_pin[4]); sensor_transfer_front = digitalRead(sensor_pin[5]); sensor_remmen = digitalRead(sensor_pin[6]); sensor_post_mcbr = digitalRead(sensor_pin[7]); sensor_stop_mcbr = digitalRead(sensor_pin[8]); sensor_pre_mcbr = digitalRead(sensor_pin[9]); sensor_post_lift_top = digitalRead(sensor_pin[10]); sensor_pre_lift_top = digitalRead(sensor_pin[11]); //sensoren 12-19 niet in gebruik } void PIQ(){ //Proces Image Output (Uitgangsregister) for(int i = 0; i<=15; i++) { digitalWrite(motor_non_pwm[i],xMotor_non_pwm[i]); analogWrite(motor_pwm[i],xMotor_pwm[i]); } } void motor(int motor, int value, int time) { //possible values from -255 to +255 currentMillis = millis(); if((currentMillis - previousMillisMotor[motor]) >= time) { previousMillisMotor[motor] = currentMillis; if (motor_current_speed[motor] < value) {speed_step[motor] = 1; skip_dead_zone = motor_dead_zone_high;} else if(motor_current_speed[motor] > value) {speed_step[motor] = -1; skip_dead_zone = motor_dead_zone_low;} else if(motor_current_speed[motor] = value) {speed_step[motor] = 0;} if(motor_current_speed[motor] <= motor_dead_zone_low) { motor_current_speed[motor] = motor_current_speed[motor] + speed_step[motor]; xMotor_non_pwm[motor] = LOW; xMotor_pwm[motor] = abs(motor_current_speed[motor]); } if((motor_current_speed[motor] > motor_dead_zone_low) && (motor_current_speed[motor] < motor_dead_zone_high)) { if((value > motor_dead_zone_low) && (value < motor_dead_zone_high)) { motor_current_speed[motor] = 0; xMotor_non_pwm[motor] = LOW; xMotor_pwm[motor] = 0; } else { motor_current_speed[motor] = skip_dead_zone; } } if(motor_current_speed[motor] >= motor_dead_zone_high) { motor_current_speed[motor] = motor_current_speed[motor] + speed_step[motor]; xMotor_non_pwm[motor] = HIGH; xMotor_pwm[motor] = 255-abs(motor_current_speed[motor]); } } } void motor_lift(int value, int time) { motor(0,value,time); motor(1,value,time); motor(2,value,time); motor(3,value,time); motor(4,value,time); motor(5,value,time); motor(6,value,time); motor(7,value,time); } void motor_mcbr(int value, int time) { //Deels andersom gepolariseerd in de achtbaan motor(8,value,time); motor(9,-value,time); motor(10,value,time); motor(11,-value,time); } void motor_remmen(int value, int time) { //Andersom gepolariseerd in de achtbaan motor(12,-value,time); } void motor_station_uit(int value, int time) { motor(13,value,time); } void motor_station_in(int value, int time) { motor(14,value,time); } /*---------------------------------------------------- --------------------INITIALISATIE--------------------- ----------------------------------------------------*/ void initialisatie() { if(currentMillis - InitPrevious > 1000) { InitPrevious = currentMillis; InitTimer++; } switch(Init_State) { case 0: //Wachten op druk op knop if(currentMillis - BlinkPrevious > 500) { //Elke halve seconde BlinkPrevious = currentMillis; //Knippertimer resetten LED_State = !LED_State; //LED aan- of uitschakelen digitalWrite(LED_pin, LED_State); } if(button_State == HIGH) { //Als knop wordt ingedrukt Init_State = 10; //Gaan wachten op loslaten knop } break; case 10: //Wachten op loslaten knop LED_State = HIGH; digitalWrite(LED_pin, LED_State); if(button_State == LOW) { LED_State = LOW; digitalWrite(LED_pin, LED_State); InitTimer = 0; Init_State = 20; } break; case 20: //Lift controleren if(InitTimer <= 50) { //Max 50 seconden draaien motor_lift(255,15); if(sensor_pre_lift_top == HIGH) { //Trein blijft bovenaan de lift motor_lift(0,15); block_lift = HIGH; InitTimer = 0; Init_State = 30; } else if(sensor_post_lift_top == HIGH) { //Trein gaat van lift naar mcbr motor_lift(0,15); block_lift = LOW; Init_State = 21; } } else { //Geen trein op de lift motor_lift(0,15); block_lift = LOW; InitTimer = 0; Init_State = 30; } break; case 21: //Wachten op mcbr if(sensor_pre_mcbr == HIGH) { //Trein rijdt mcbr op motor_mcbr(255,15); Init_State = 22; } break; case 22: //Positioneren op mcbr if(sensor_stop_mcbr == HIGH) { //Trein staat gepositioneerd motor_mcbr(0,15); block_mcbr = HIGH; InitTimer = 0; Init_State = 30; } break; case 30: //Station INSTAP controleren if(InitTimer <= 10) { //Max 10 seconden draaien motor_station_in(255,0); if(sensor_post_station == HIGH) { //Trein van station instap naar onderkant lift motor_station_in(0,0); block_lift_down = HIGH; InitTimer = 0; Init_State = 40; } } else { //Geen trein in station instap motor_station_in(0,0); block_lift_down = LOW; InitTimer = 0; Init_State = 40; } break; case 40: //Station UITSTAP controleren if(InitTimer <= 10) { //Max 10 seconden draaien motor_station_in(255,0); motor_station_uit(255,0); if(sensor_station_in == HIGH) { //Trein van station uitstap naar station instap motor_station_in(0,0); motor_station_uit(0,0); block_station_in = HIGH; InitTimer = 0; Init_State = 50; } } else { //Geen trein in station uitstap motor_station_in(0,0); motor_station_uit(0,0); block_station_in = LOW; InitTimer = 0; Init_State = 50; } break; case 50: //Transfer aligned? if((sensor_transfer_front == HIGH) && (sensor_transfer_back == HIGH)) { InitTimer = 0; Init_State = 51; } break; case 51: //Eindremmen controleren if(InitTimer <= 30) { //Max 30 seconden draaien motor_remmen(255,0); motor_station_uit(255,0); if(sensor_station_uit == HIGH) { //Trein van eindremmen naar station uitstap motor_remmen(0,0); motor_station_uit(0,0); block_station_uit = HIGH; InitTimer = 0; Init_State = 60; } else if((sensor_transfer_front == LOW) || (sensor_transfer_back == LOW)) { motor_remmen(0,0); motor_station_uit(0,0); Init_State = 50; } } else { //Geen trein op eindremmen motor_remmen(0,0); motor_station_uit(0,0); block_station_uit = LOW; InitTimer = 0; Init_State = 60; } break; case 60: //Mcbr controleren if(InitTimer <= 10) { //Max 10 seconden draaien motor_mcbr(255,0); if(sensor_post_mcbr == HIGH) { //Trein verlaat mcbr motor_mcbr(0,0); block_mcbr = LOW; Init_State = 65; } } else { //Geen trein op mcbr motor_mcbr(0,0); block_mcbr = LOW; Init_State = 70; } break; case 65: //Wachten op eindremmen if(sensor_remmen == HIGH) { //Trein rijdt eindremmen in block_remmen = HIGH; InitTimer = 0; Init_State = 70; } break; case 70: //Lift nogmaals controleren if(block_lift == HIGH) { //Trein bovenaan lift motor_lift(255,15); if(sensor_post_lift_top == HIGH) { //Trein van lift naar mcbr motor_lift(0,15); block_lift = LOW; Init_State = 71; } } else { //Geen trein bovenaan lift Init_State = 80; } break; case 71: //Wachten op mcbr if(sensor_pre_mcbr == HIGH) { //Trein rijdt mcbr op motor_mcbr(255,0); Init_State = 72; } break; case 72: //Positioneren op mcbr if(sensor_stop_mcbr == HIGH) { //Trein staat gepositioneerd motor_mcbr(0,0); block_mcbr = HIGH; Init_State = 80; } break; case 80: //Lift nogmaals controleren if(block_lift_down == HIGH) { //Trein onderaan lift motor_lift(255,15); if(sensor_pre_lift_top == HIGH) { //Trein bovenaan lift aangekomen motor_lift(0,0); block_lift = HIGH; block_lift_down = LOW; } } else { //Geen trein onderaan lift Init_State = 90; } break; case 90: //Posities van alle treinen bekend, door naar ritprogramma if(block_station_in == HIGH) {Station_In_State = 20;} if(block_station_uit == HIGH) {Station_Uit_State = 20;} if(block_remmen == HIGH) {Remmen_State = 10;} if(block_mcbr == HIGH) {Mcbr_State = 20;} if(block_lift == HIGH) {Lift_State = 20;} Init_State = -1; break; } } /*---------------------------------------------------- -----------------------RIT-CYCLUS--------------------- ----------------------------------------------------*/ void station_in() { if(currentMillis - StationInPrevious > 1000) { StationInPrevious = currentMillis; StationInTimer++; } switch(Station_In_State) { case 0: //Station_in is vrij if(internal_station_move == HIGH) { //Trein rijdt station_uit in motor_station_in(255,0); Station_In_State = 10; } break; case 10: //Station_in is bezet, trein rijdt naar midden station_in if(sensor_station_in == HIGH) { //Trein wacht in station_uit, poortjes openen motor_station_in(0,0); servo_gates.write(90); StationInTimer = 0; Station_In_State = 20; } break; case 20: //Station_in is bezet, trein wacht in station_in if(StationInTimer > 6) { //Na 6 seconden sluiten de poortjes servo_gates.write(0); } if((StationInTimer > 8) && (block_lift == LOW)) { //Trein heeft 8 seconden stilgestaan in station_in en lift is vrij motor_station_in(255,0); Station_In_State = 30; } break; case 30: //Station_in is bezet, trein vertrekt uit station_in if(sensor_post_station == HIGH) { //Trein heeft station_in verlaten block_station_in = LOW; block_lift = HIGH; motor_station_in(0,0); Station_In_State = 0; } break; } } void station_uit() { if(currentMillis - StationUitPrevious > 1000) { StationUitPrevious = currentMillis; StationUitTimer++; } switch(Station_Uit_State) { case 0: //Station_uit is vrij if((sensor_pre_station == HIGH)) {//Trein rijdt vlak voor station_uit Station_Uit_State = 5; } break; case 5: //Station_uit is vrij, trein is vlak voor station_uit if((sensor_transfer_front == HIGH) && (sensor_transfer_back == HIGH)) { //Staat de transfer track goed? motor_station_uit(255,0); Station_Uit_State = 10; } break; case 10: //Station_uit is bezet, trein rijdt naar midden station_uit if(sensor_station_uit == HIGH) { //Trein wacht in station_uit motor_station_uit(0,0); StationUitTimer = 0; Station_Uit_State = 20; } break; case 20: //Station_uit is bezet, trein wacht in station_uit if((StationUitTimer > 5) && (block_station_in == LOW)) { //Trein heeft 5 seconden stilgestaan in station_uit en station_in is vrij motor_station_uit(255,0); internal_station_move = HIGH; Station_Uit_State = 30; } break; case 30: //Station_uit is bezet, trein vertrekt uit station_uit if(sensor_station_in == HIGH) { //Trein heeft station_uit verlaten en is aangekomen in station_in block_station_uit = LOW; block_station_in = HIGH; motor_station_uit(0,0); internal_station_move = LOW; Station_Uit_State = 0; } break; } } void eindremmen() { switch(Remmen_State) { case 0: //Remmen zijn vrij if(sensor_remmen == HIGH) { //Trein rijdt remmen in Remmen_State = 10; } break; case 10: //Remmen zijn bezet, trein staat stil if((block_station_uit == LOW) && (sensor_transfer_front == HIGH) && (sensor_transfer_back == HIGH)) { motor_remmen(255,0); Remmen_State = 20; } break; case 20: //Remmen zijn bezet, trein rijdt door if(sensor_pre_station == HIGH) { //Trein nadert station, remmen weer vrij block_remmen = LOW; block_station_uit = HIGH; motor_remmen(0,0); Remmen_State = 0; } else if((sensor_transfer_front == LOW) || (sensor_transfer_back == LOW)) { motor_remmen(0,0); Remmen_State = 10; } break; } } void mcbr() { switch(Mcbr_State) { case 0: //Mcbr is vrij if(sensor_pre_mcbr == HIGH) { //Trein rijdt mcbr op motor_mcbr(255,0); Mcbr_State = 10; } break; case 10: //Mcbr is bezet, trein rijdt naar midden mcbr if((sensor_stop_mcbr == HIGH) && (block_remmen == HIGH)) { //Trein gepositioneerd op mcbr, eindremmen NIET vrij motor_mcbr(0,0); Mcbr_State = 20; } else if((sensor_stop_mcbr == HIGH) && (block_remmen == LOW)) { //Trein gepositioneerd op mcbr, eindremmen WEL vrij Mcbr_State = 30; } break; case 20: //Mcbr is bezet, trein wacht op mcbr op vrijkomen van eindremmen if(block_remmen == LOW) { //Trein wacht op mcbr, eindremmen komen weer vrij motor_mcbr(255,0); Mcbr_State = 30; } break; case 30: //Mcbr is bezet, trein vertrekt uit mcbr if(sensor_post_mcbr == HIGH) { //Trein heeft de mcbr verlaten block_mcbr = LOW; block_remmen = HIGH; motor_mcbr(0,0); Mcbr_State = 0; } break; } } void lift() { switch(Lift_State) { case 0: //Lift is vrij if(sensor_post_station == HIGH) { //Trein rijdt richting lift motor_lift(255,15); Lift_State = 10; } break; case 10: //Lift is bezet, trein rijdt omhoog if((sensor_pre_lift_top == HIGH) && (block_mcbr == HIGH)) { //Trein komt boven, mcbr NIET vrij motor_lift(0,15); Lift_State = 20; } else if((sensor_pre_lift_top == HIGH) && (block_mcbr == LOW)) { //Trein komt boven, mcbr WEL vrij Lift_State = 30; } break; case 20: //Lift is bezet, trein wacht boven op vrijkomen van mcbr if(block_mcbr == LOW) { //Trein wacht boven, mcbr komt weer vrij motor_lift(255,15); Lift_State = 30; } break; case 30: //Lift is bezet, trein gaat over de top if(sensor_post_lift_top == HIGH) { //Trein verlaat de lift block_lift = LOW; block_mcbr = HIGH; motor_lift(0,15); Lift_State = 0; } break; } }
SSCoasters Administrator
The SSCoasters Forum Rules
#25
Posted 25 April 2012 - 02:10 PM
#26
Posted 25 April 2012 - 02:34 PM
SSCoasters Administrator
Read The Forum Rules(smart)
#27
Posted 25 April 2012 - 07:09 PM
I'm rather proud of this motor function. I hope to fully exploit it after the Balrog project, when I start using other IC's for more possibilities with this 'Universal K'NEX Coaster System'.I really like the motorcontrol code! Very clever! May I give you compliment on the clean-ness of coding? Very easy to understand!
I tried to make the code as understandable as possible. It's still a mix of Dutch and English, though.
SSCoasters Administrator
The SSCoasters Forum Rules
#28
Posted 25 April 2012 - 07:15 PM
Member of a few physics experiments; Orchestrator and/or Copyist for a few musicals.
#29
Posted 25 April 2012 - 07:19 PM
I think that sense for clean coding came from having experience in building PHP websites.for someone who says they don't know a lot of code/coding.
SSCoasters Administrator
The SSCoasters Forum Rules
#30
Posted 09 July 2012 - 10:58 AM
SSCoasters Administrator
The SSCoasters Forum Rules
#31
Posted 24 July 2012 - 09:43 AM
A few questions could help save me a lot of time researching things.
Did you make your own motor shield because nothing out there will control as many motors as you needed? I see there are standard motor shields available but it looks like the most you can control is 4 motors. But I think most of those shields can provide up to 2A per H bridge. Could I wire multiple motors up to the same bridge circuit if they were always going to run at the same speed? For instance a set of motors driving a lift.
I am a software engineer but it has been over 25 years since I programmed anything as simple as a microcontroller. Your code is nicely organized and has some nice safety features built in. Did you develop that login incrementally because of issues you had in early versions or did you just try to cover all the bases when you first wrote it?
Also do you have any picutres of your servo controlled brakes either here or in the Balrog thread?
Comet Recreation still underway.
Proof you never grow up if you keep playing with toys!
#32
Posted 26 July 2012 - 05:40 AM
I use IC's called 'L293D'. Each IC can drive two motors in both directions or four motors in one direction. Have a look at this page. I wrote a function with which I can drive these motors with ease. Two logic pins (one is PWM, meaning that I can determine the output voltage within the code) decide the speed and polarity. After Balrog I will completely revamp my Universal K'NEX Coaster System, with lots of added debugging tools, which I really missed during Balrog's assembly and testing. So the whole L293D configuration will be done in another way, too.Did you make your own motor shield because nothing out there will control as many motors as you needed? I see there are standard motor shields available but it looks like the most you can control is 4 motors. But I think most of those shields can provide up to 2A per H bridge. Could I wire multiple motors up to the same bridge circuit if they were always going to run at the same speed? For instance a set of motors driving a lift.
Actually I had most of the code written all in one day and there were only a few extra safety features that I added later, but still before the Balrog assembly. I only adjusted the timing constants in the initialization process during Balrog tests. In the end some problems arose, so I thought they were code-related. I had a lot of trouble trying to debug the shit out of Balrog, but it turned out to be hardware-related (motor plugs didn't stay in the motors properly). The code appeared to be good after all. But like I said before, I will completely revamp the system, so the code will be completely different, too.I am a software engineer but it has been over 25 years since I programmed anything as simple as a microcontroller. Your code is nicely organized and has some nice safety features built in. Did you develop that login incrementally because of issues you had in early versions or did you just try to cover all the bases when you first wrote it?
I decided not to use servo controlled brakes. Integrating servos into K'NEX appeared to be a tough job and the combination with magnetic brakes sucked too. Perhaps in a later project.Also do you have any pictures of your servo controlled brakes either here or in the Balrog thread?
SSCoasters Administrator
The SSCoasters Forum Rules
#33
Posted 26 July 2012 - 08:46 AM
I think the only issue with simply wiring more than one motor to the output of the L293D chips is drawing too much current and overheating the chip. But I read elsewhere just putting a heat sink on the chip will work if you are going to be pushing it close to it's design limit (600ma). You can also stack L293Ds by simply soldering the pins on stacked chips together. The article said a stack of 2 is almost 2 times the current capacity, 3 stackcked aboutr 2.5 times... after 3 there is diminishing returns. So another option is instead of stacking shields you can use a single shield and get a couple extra chips to stack on the ones already there.
If I decide to go this route I'd rather just by components than build them. They are so cheap and I don't have tons of spare time.
I'm also on the fence about going with a Mega vs. an Uno. If I use the premade shields I think I am only going to have access to 4 of the PWM outputs that are common to the Uno and Mega the Uno probably can do just about anything I would want to do.
Thanks for sharing your design. All very cool.
Comet Recreation still underway.
Proof you never grow up if you keep playing with toys!
#34
Posted 29 December 2012 - 11:47 AM
- dylpickled likes this
#35
Posted 27 November 2017 - 09:41 PM
Can you use this to power 15 individual flat rides? I am back at it again building funfair rides with my knex. I would be willing to buy a complete system in a suitcase for my knex carnival rides.