Home > Mindstorms, Trucks > Kenworth Road Train

Kenworth Road Train

Model of the Kenworth T900 truck in the Australian road train variant. Features proportional steering using the NXT unit, remotely locked fifth wheel, working turn signals, three trailers, lights and custom stickers.  

Datasheet:

Completion date: 14/05/2012
Power: electric (Power Functions / NXT)
Dimensions: truck: length 67 studs / width 20 studs / height 31 studs, trailer #1: length 103 studs / width: 18 studs / height: 28 studs, trailer #2: length 122 studs / width 18 studs / height 9 studs, trailer #3: length 97 studs / width 18 studs / height 24 studs
Weight: truck: 2.891 kg, trailer #1: 2.378 kg, trailer #2: 1.440 kg, trailer #3: 2.194 kg
Suspension: none
Propulsion: 1 x NXT motor geared 3:1
Motors: 3 x NXT motor

This model was based on the Kenworth T900 truck converted to an Australian road train version. At the same time, it was an experiment on merging NXT functionality with a Model Team look.

I have started by modeling a pure T900 truck, adding some modifications typical for road trains along the way. The result is neither a stock Kenworth T900 nor a classic road train, but it still fits within the wide array of customizations popular among Australian drivers (and sheep).

The heart of the model was a NXT unit located at the back of the sleeper module. Since the chassis was entirely taken by two NXT motors (yes, they are this big), the sleeper was actually where almost all mechanical and electric elements were housed. Among them was a third NXT motor used to lock and unlock the fifth wheel, the 8878 rechargeable Power Functions battery for powering lights and turn signals, a Power Functions IR receiver for controlling the turn signals and HiTechnic IR Link sensor for allowing the NXT unit to send commands to the IR receiver.

It may come as a surprise that the model had an IR receiver housed inside next to the IR link sensor, but it resulted from sensor’s poor IR range. I was initially hoping to be able to install the sensor on an external NXT controller, thus having a chance to add IR receivers and turn signals in the trailers too, but with a model of that size the sensor simply wouldn’t reach the truck and all trailers at the same time. Also, with all the effort put into steering the model over a Bluetooth link, it would be a waste to be limited by the poor IR range.

The model had just a few functions. Both rear axles were driven by a single NXT motor geared 3:1, and the front axle was steered by another NXT motor without a clutch. There was no suspension, as it would affect the look of the model and it was hardly needed since it was never supposed to leave my apartment’s floor.  The fifth wheel was locked and unlocked using a horizontal 40-tooth gear with a short beam on its side, driven by the third NXT motor located in the sleeper. By rotating the wheel, the beam would block and unblock the fifth wheel’s only “exit”.

The front turn signals were controlled remotely and operated by the software, that is by the NXT unit turning them on and off repeatedly using the IR Link sensor. I did not install rear or any other turn signals for the fear of compromising the truck’s look with too many exposed wires and LEDs, but I have added working turn signals indicators on driver’s dashboard. I have also used the speaker of the truck’s NXT unit to honk (or rather beep) on command, and to beep while on reverse. It was a very simple thing and I have omitted it when trying to shorten the video.

The sleeper module was literally bursting at seams with electric elements and wires. There were three access hatches in it: top one for the 8878 battery, rear one for the NXT unit’s front panel, and a side one for taking the entire NXT unit out for battery replacement. The wires, especially the stiff NXT wires, proved problematic because they had to be arranged so as to allow moving the NXT unit out and back in. Eventually, the whole space at the back of the cabin was taken by wires and the side access hatch tended to stick out a little.

The entire set-up, that is the truck and three trailers, was controlled by a very simple external controller using another NXT unit. I have initially attempted to use the Hailfire Droid’s wheel as a steering wheel, but it proved unusable because using it to drive any regular gear wheel created very high gear acceleration which generated plenty of resistance. Gearing down in the latter stage was not an option, as a very considerable backlash in gear wheels was created. I was also tempted to build a pedal-like device to control the throttle, but with the NXT wires being quite short and impossible to connect in series, it proved pointless – I would have to keep such a pedal right next to the NXT unit.

The controller  was a variation of my NXT brick-to-brick remote, allowing proportional steering and drive with a speed control, as well as controlling all the remaining functions with touch sensors and NXT unit’s buttons. It was running the RobotC software, resulting in delay in the other NXT unit’s reactions over Bluetooth link. A secondary, more comfortable way of controlling the model was to use a computer with a gaming pad. Using a Bluetooth link and the RobotC software, it allowed to control the model with minimum delays and the gaming pad provided plenty of buttons and two analog joysticks which were used for speed-control for both drive and steering.

I was not fully happy with the model. Its functionality was troublesome, with a lot of effort required to start and connect the two NXT units, with delays in steering, and most importantly with the enormous amount of space taken by the NXT elements. Its look was somewhat compromised, with some simplifications in the bonnet and cabin’s roof area, and with the side air filters shortened to allow to open the bonnet up – the only alternative here was to cut the front bumper to move the bonnet’s hinge lower, which I didn’t want to do. I was afraid it was the kind of model that makes a good first impression, and goes downhill from there. Still, it was an interesting experience in using the NXT elements and in merging them with the PF ones.

Gaming pad control program:

#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;
  }
}
									

NXT-to-NXT control sender program:

#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);
  }
}
									

NXT-to-NXT control receiver program:

#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);
  }
}

									

Work in progress photos:

dsc08409.jpg dsc08417.jpg dsc08443.jpg dsc08458.jpg dsc08465.jpg dsc08586.jpg dsc08591.jpg dsc08605.jpg dsc08962.jpg dsc09015.jpg

Photos:

01.jpg 02.jpg 03.jpg 04.jpg 05.jpg 06.jpg 07.jpg 08.jpg 09.jpg 10.jpg 11.jpg 12.jpg 13.jpg dsc09046.jpg dsc09053.jpg dsc09073.jpg dsc09089.jpg dsc09097.jpg dsc09106.jpg dsc09109.jpg dsc09111.jpg dsc09114.jpg dsc09127.jpg dsc09132.jpg dsc09136.jpg dsc09138.jpg dsc09157.jpg dsc09178.jpg dsc09179.jpg dsc09184.jpg dsc09185.jpg dsc09193.jpg dsc09198.jpg dsc09200.jpg dsc09202.jpg dsc09205.jpg dsc09214.jpg dsc09220.jpg dsc09228.jpg dsc09234.jpg dsc09238.jpg dsc09240.jpg dsc09244.jpg dsc09245.jpg dsc09258.jpg dsc09268.jpg dsc09271.jpg dsc09277.jpg dsc09282.jpg dsc09287.jpg dsc09289.jpg original1.jpg original2.jpg original_configurations.png

Video:

YouTube Preview Image

Media reference:

8 studs, The Brothers Brick, The LEGO Car Blog

  1. Sariel
    July 12th, 2014 at 10:21 | #1

    @Lego man
    I’m pretty sure you can built it from photos if you try.

  2. Lego man
    July 12th, 2014 at 08:51 | #2

    Hello can I get instructions or some way to build that fifth wheel. And pin type

Comment pages
1 2 2299
  1. May 18th, 2012 at 16:40 | #1