[MOC] Kenworth Road Train
: 2012-05-15, 22:19
Dane techniczne:
Wymiary: dł: 67s / szer. 20s / wys. 31s
Waga: 2.891 kg
Długość przyczep: 103, 122 i 97 studów
Waga przyczep: 2.378, 1.440 i 2.194 kg
Łącznie: ponad 3 metry długości, 8.903 kg wagi
Zawieszenie: brak
Napęd: silnikiem NXT na obie tylne osie z redukcją 3:1
Silniki: 3xNXT
I tak oto zapchane serwery Diablo potrafią doprowadzić do publikacji MOCa. Ech...
Przed Wami eksperyment w łączeniu bebechów z NXT z obudową z Model Teamu. Wyniki dyskusyjne, ale o tym później. Model przedstawia Kenwortha T900 w wersji australijskiego Road Traina, przy czym robiłem go bez specjalnego parcia na dokładność i ani nie jest to czysty T900 ani nie jest to typowy Road Train. Z drugiej strony Australijczycy nie takie rzeczy robią z ciężarówkami (i owcami).
Sercem modelu jest kostka NXT upchnięta w sleeperze za kabiną. Jako że całe podwozie zajmują dwa silniki NXT (tak, one naprawdę są takie ogromne), jeden do napędu i jeden do skrętu, to sleeper mieści całą listę cudów. W tym trzeci silnik NXT do zapinania siodła, baterię 8878 do zasilania świateł i kierunkowskazów, wieżę IR do sterowania tymi kierunkowskazami i sensor IR Link do sterowania tą wieżą. Tak, właśnie, model ma IR linka zabudowanego w środku prawie na styk z wieżą, bo w normalnych warunkach jego zasięg jest fatalny. Kusiło mnie żeby IR Linka zamontować w kontrolerze, a kierunkowskazy i kolejne wieże IR na tym samym kanale schować w przyczepach, ale przy MOCu tej wielkości praktycznie nie ma szans żeby IR Link łapał wszystkie wieże naraz, a ja nie po to używam NXT żeby sterować ciężarówką z odległości centymetra.
Funkcji modelu jest niewiele. Zawieszenie sobie podarowałem bo w modelu który nigdy nie wyjedzie poza moje mieszkanie byłaby to sztuka dla sztuki. Oprócz skrętu i napędu na obie tylne osie mamy jeszcze zapinanie i odpinanie siodła realizowane poziomą zębatką z40 z liftarmem na jednym boku, która po odpowiednim obróceniu blokuje tym liftarmem "wylot" siodła. Rozwiązanie małe, proste i dostatecznie mocne.
Oprócz funkcji czysto mechanicznych mamy przednie kierunkowskazy zrealizowane przez oprogramowanie, a ściślej przez IR Linka który przesyła odpowiednie komendy do PFowej wieży. Tylnych kierunkowskazów nie ma bo nie chciało mi się psuć wyglądu ciężarówki większą liczbą kabli i wystających diod, ale za to są kontrolki na desce rozdzielczej kierowcy. Oprócz tego kostka w modelu może trąbić (czytaj: piszczeć) na komendę, oraz pikać (czytaj: piszczeć) przy cofaniu, ale to jest programowanie na poziomie wczesnoprzedszkolnym.
Sleeper jest wypchany mechaniką i kablami do granic wytrzymałości, w zasadzie niemal rozłazi się w szwach. Dostęp do bebechów zapewniają trzy klapki: górna do baterii 8878, tylna do przycisków z przodu modułu NXT, oraz boczna pozwalająca wyciągnąć cały moduł na zewnątrz celem wymiany baterii. Kable zajmują przy tej okazji cały tył kabiny, nie tylko dlatego że są sztywne (damn you NXT), ale też dlatego że ich ułożenie musi pozwalać na wyciągnięcie kostki. Przez całe to wypychanie boczna klapka w prawym boku sleepera ma niestety tendencję do krzywego wystawania.
Do sterowania całym tym majdanem o długości półtora Longera, który ledwie jest w stanie zakręcić w moim mieszkaniu, złożyłem sobie ordynarnie prosty kontroler z drugą kostką, którego działanie całkowicie obrzydziło mi RobotC (opóźnienia). Lepszą alternatywą jest sterowanie padem podłączonym do komputera - nie tylko czas reakcji jest lepszy ale i przycisków do wykorzystania więcej a gałki pada działają analogowo, dlatego rozwiązanie to bije poprzednie na głowę. Wszystkie trzy programy spłodzone na ten użytek zamieszczam poniżej, a sam zacznę się chyba wreszcie wgryzać w Lejosa.
Podsumowując, z ciężarówki jestem średnio zadowolony. Działa słabo, z NXT jest od cholery zachodu już żeby tylko połączyć obie kostki, a jak przychodzi do wymiany baterii w tej w modelu to w ogóle jest dramat. Wygląda tak sobie - ma ewidentne błędy i uproszczenia, i obawiam się że jest to ten rodzaj MOCa który robi niezłe pierwsze wrażenie a potem jest już tylko gorzej. Acha, co do marudzenia na cały ten chrom - no niestety, budowałem już ciężarówki z jasnoszarymi przodami i udawałem że przypomina to oryginał. Nie przypominało.
Acha, pomysł na malowanie oraz na układ przyczep (wariant G) pochodzi stąd:
Byłbym zapomniał - wielkie podziękowania dla Auriego za niezawodne jak zwykle chromowanie.
Galeria
Galeria WIP
Zdjątka:
Film:
[youtube]http://www.youtube.com/watch?v=dWxTg150maU[/youtube]
Oraz programy:
Do sterowania padem:
Kod: Zaznacz cały
#pragma config(Sensor, S4, HTIRL, sensorI2CCustom)
#include "drivers/HTIRL-driver.h"
#include "JoystickDriver.c"
tPFmotor SignalLeft = pfmotor_S4_C1_A;
tPFmotor SignalRight = pfmotor_S4_C1_B;
task Signals()
{
while(true)
{
if(joy1Btn(2) == 1)
{
PFMotor(SignalRight, 7);
nxtDisplayCenteredTextLine(5, " < [>]");
}
else if(joy1Btn(4) == 1)
{
PFMotor(SignalLeft, 7);
nxtDisplayCenteredTextLine(5, "[<] > ");
}
else
{
PFMotor(SignalRight, 0);
PFMotor(SignalLeft, 0);
nxtDisplayCenteredTextLine(5, " < > ");
}
wait1Msec(250);
PFMotor(SignalRight, 0);
PFMotor(SignalLeft, 0);
}
}
task main()
{
bMotorReflected[motorB] = true;
bMotorReflected[motorC] = true;
StartTask(Signals);
while(true)
{
getJoystickSettings(joystick);
motor[motorB] = 0;
motor[motorC] = 0;
motor[motorC] = joystick.joy1_y1 / 1.28;
motor[motorB] = joystick.joy1_x1 / 1.28;
nxtDisplayCenteredTextLine(0, "BATTERY: %3.1fV", nImmediateBatteryLevel / (float) 1000);
nxtDisplayTextLine(2, "B: %d", motor[motorB]);
nxtDisplayTextLine(3, "C: %d", motor[motorC]);
if(joy1Btn(1) == 1)
motor[motorA] = -100;
else if(joy1Btn(3) == 1)
motor[motorA] = 100;
else
motor[motorA] = 0;
}
}
Kod: Zaznacz cały
#pragma config(Sensor,S1,touch1,sensorTouch)
#pragma config(Sensor,S2,touch2,sensorTouch)
bool leftturn = false;
bool rightturn = false;
bool soundhorn = false;
task BatLev()
{
ubyte valueReceived[1];
valueReceived[0] = 0;
while(true)
{
cCmdMessageRead(valueReceived, 1, 1);
nxtDisplayCenteredTextLine(0, "BAT: L%3.1f / R%3.1f", nImmediateBatteryLevel / (float) 1000, valueReceived[0] / (float) 10);
wait1Msec(50);
}
return;
}
task Buttons() //0 = Gray Rectangle 1 = Right Arrow 2 = Left Arrow 3 = Orange Square
{
nNxtButtonTask = -2;nNxtExitClicks = 2;
nxtDisplayCenteredTextLine(2, " < > ");
while(true)
{
if(nNxtButtonPressed == 1)
{
if (rightturn == false)
{
nxtDisplayCenteredTextLine(2, " < [>]");
rightturn = true;
leftturn = false;
}
else
{
nxtDisplayCenteredTextLine(2, " < > ");
rightturn = false;
leftturn = false;
}
}
else if(nNxtButtonPressed == 2)
{
if (leftturn == false)
{
nxtDisplayCenteredTextLine(2, "[<] > ");
rightturn = false;
leftturn = true;
}
else
{
nxtDisplayCenteredTextLine(2, " < > ");
rightturn = false;
leftturn = false;
}
}
else if(nNxtButtonPressed == 3)
{
soundhorn = true;
}
wait1Msec(350);
}
}
task main()
{
StartTask(BatLev);
StartTask(Buttons);
bFloatDuringInactiveMotorPWM = true;
btConnect(1, "NXT2");
while(true)
{
ubyte valueToSend[7];
valueToSend[0] = nMotorEncoder[motorA];
valueToSend[1] = nMotorEncoder[motorB];
valueToSend[2] = SensorValue(touch1);
valueToSend[3] = SensorValue(touch2);
valueToSend[4] = rightturn;
valueToSend[5] = leftturn;
valueToSend[6] = soundhorn;
cCmdMessageWriteToBluetooth(valueToSend, 7, 1);
nxtDisplayTextLine(3, "Drive: %d", valueToSend[0]);
nxtDisplayTextLine(4, "Steering: %d", valueToSend[1]);
nxtDisplayTextLine(5, "Touch BLUE: %d", valueToSend[2]);
nxtDisplayTextLine(6, "Touch RED: %d", valueToSend[3]);
wait1Msec(50);
}
}
Kod: Zaznacz cały
#pragma config(Sensor, S4, HTIRL, sensorI2CCustom)
#include "drivers/HTIRL-driver.h"
tPFmotor SignalLeft = pfmotor_S4_C1_A;
tPFmotor SignalRight = pfmotor_S4_C1_B;
// config start
//bMotorReflected[motorA] = true;
//bMotorReflected[motorB] = true;
//bMotorReflected[motorC] = true;
bool buzzOnRev = true; // buzzing while on reverse
int steerAcc = 10; // steering accuracy margin (degrees)
// config end
int turnSignals = 0;
task Signals()
{
while(true)
{
if(turnSignals == 1)
{
PFMotor(SignalRight, 7);
}
else if(turnSignals == 2)
{
PFMotor(SignalLeft, 7);
}
else
{
PFMotor(SignalRight, 0);
PFMotor(SignalLeft, 0);
}
wait1Msec(250);
PFMotor(SignalRight, 0);
PFMotor(SignalLeft, 0);
}
wait1Msec(50);
}
task BatLev()
{
while(true)
{
nxtDisplayCenteredTextLine(0, "BAT: L %3.1fV", nImmediateBatteryLevel / (float) 1000);
ubyte valueToSend[1];
valueToSend[0] = nImmediateBatteryLevel / (float) 100;
cCmdMessageWriteToBluetooth(valueToSend, 1, 1);
wait1Msec(50);
}
return;
}
task main()
{
StartTask(BatLev);
StartTask(Signals);
nVolume = 3; // starting volume
ubyte valueReceived[7];
valueReceived[0] = 0;
valueReceived[1] = 0;
valueReceived[2] = 0;
valueReceived[3] = 0;
valueReceived[4] = 0;
valueReceived[5] = 0;
valueReceived[6] = 0;
while(true)
{
cCmdMessageRead(valueReceived, 7, 1);
nxtDisplayTextLine(2, "Drive: %d", valueReceived[0]);
nxtDisplayTextLine(3, "Steering: %d", valueReceived[1]);
nxtDisplayTextLine(4, "Touch BLUE: %d", valueReceived[2]);
nxtDisplayTextLine(5, "Touch RED: %d", valueReceived[3]);
// motorC (drive)
motor[motorC] = 0;
int afactor = valueReceived[0] / 5;
if (afactor > 1 && afactor < 25)
{
afactor = afactor * 10;
if (afactor > 100) afactor = 100;
motor[motorC] = afactor;
if (buzzOnRev == true) PlaySound(soundException);
}
else if (afactor > 1 && afactor > 25)
{
afactor = (51 - afactor) * -10;
if (afactor < -100) afactor = -100;
motor[motorC] = afactor;
if (buzzOnRev == true) ClearSounds();
}
// motorB (steering)
motor[motorB] = 0;
int bfactor = valueReceived[1];
if (bfactor > 1 && bfactor < 75) bfactor = bfactor;
else if (bfactor > 1 && bfactor > 75) bfactor = (256 - bfactor) * -1;
nxtDisplayTextLine(7,"Mtr B: %d/%d",nMotorEncoder[motorB], bfactor);
bfactor = bfactor * 4;
if (nMotorEncoder[motorB] < (bfactor + steerAcc)) while(nMotorEncoder[motorB] < bfactor) motor[motorB] = 10;
else if (nMotorEncoder[motorB] > (bfactor - steerAcc)) while(nMotorEncoder[motorB] > bfactor) motor[motorB] = -10;
else motor[motorB] = 0;
// motorA
motor[motorA] = 0;
if (valueReceived[2] == 1) motor[motorA] = 100;
else if (valueReceived[3] == 1)motor[motorA] = -100;
// turn signals
if (valueReceived[4] == 1) turnSignals = 1;
else if (valueReceived[5] == 1) turnSignals = 2;
else turnSignals = 0;
// horn
if (valueReceived[6] == 1) PlayTone(784, 50);
else ClearSounds();
wait1Msec(50);
}
}