Introduction

This tutorial describes how to use the HiTechnic IR Link with pbLua. The IR Link can be used to control the new PF style motors that are part of the standard Technic line now, as well as other LEGO remote control products such as the RC Trains, the big Technic Bulldozer, or even the RC Dino.

You can buy the IR Link directly from directly from HiTechnic or from the LEGO S@H Website.

By the end of this tutorial, you'll be able to use the HiTechnic IR Link in your own robotic creations.

HiTechnic IR Link Basics

The HiTechnic IR Link is a third party sensor that connects to an I2C port on the bottom of the NXT. You may want to familiarize yourself with the pbLua I2C API and read over the pbLua I2C Tutorial for detailed examples of how it's used.

You can also download a PDF with detailed information on the IR Link which will be really helpful as we continue this discussion.

To get started, plug your IRLink sensor into Port 1 and run the following example code to verify that you can communicate with the IRLink.

-- setupI2C() - sets up the specified port to handle an I2C sensor

function setupI2C(port)
  nxt.InputSetType(port,2)
  nxt.InputSetDir(port,1,1)
  nxt.InputSetState(port,1,1)

  nxt.I2CInitPins(port)
end

-- Now put the standard I2C messages into the nxt table
nxt.I2Cversion    = string.char( 0x02, 0x00 )
nxt.I2Cproduct    = string.char( 0x02, 0x08 )
nxt.I2Ctype       = string.char( 0x02, 0x10 )
nxt.I2Ccontinuous = string.char( 0x02, 0x41, 0x02 )
nxt.I2Cdata       = string.char( 0x02, 0x42 )
-- waitI2C() - sits in a tight loop until the I2C system goes idle

function waitI2C( port )
  while( 0 ~= nxt.I2CGetStatus( port ) ) do
  end
end

-- Put it all together in a function that prints out a report of which
-- sensor is connected to a port

function checkI2C(port)
  setupI2C(port)

  nxt.I2CSendData( port, nxt.I2Cversion, 8 )
  waitI2C( port )
  print( "Version    -> " .. nxt.I2CRecvData( port, 8 ) )

  nxt.I2CSendData( port, nxt.I2Cproduct, 8 )
  waitI2C( port )
  print( "Product ID -> " .. nxt.I2CRecvData( port, 8 ) )

  nxt.I2CSendData( port, nxt.I2Ctype, 8 )
  waitI2C( port )
  print( "SensorType -> " .. nxt.I2CRecvData( port, 8 ) )
end

And then verify that it's working:

-- And use it - make sure you specify the port you have plugged the
-- IR Link in to:

checkI2C(1)

-- Gives these results:

-- Version    -> ýV1.2
-- Product ID -> HiTechnc
-- SensorType -> IRLink

Simple Control Of Motor A

There is really not much to figuring out the protocol. The IR Link spec outlines the meaning of all of the bits, so it's just a matter of figuring out which bits to turn on in the 3 nibbles of the data stream.

The real magic happens in the nxt.EncodeIR() function. It's responsible for taking the three nibbles, calculating the checksum, and formatting the bit stream into a string suitable for sending to the IRLink sensor.

To save time in your programs, you can generate the strings for the IRLink ahead of time, or you generate them as needed if you'll be changing the contents often.

The example below is set up to simply turn MotorA on forward for as long as IRTest() is running, which is until you press the orange button on the NXT.

-- Set up the two strings that we'll use alternately. The only difference
-- is the toggle bit. It will send the combo-direct command on channel 0 to
-- turn OutputA onfwd and OutputB float. The mode byte is 2 for PF motors.
-- If the IR signal is lost, the motors will turn off.

s0 = nxt.EncodeIR( 0x011, 2 )
s1 = nxt.EncodeIR( 0x811, 2 )

-- And this is the test function

function IRTest(port)
  -- Set up the port and report on the sensor type
  checkI2C(port)

  repeat
    nxt.I2CSendData( port, s0, 0 )
    waitI2C( port )
    nxt.I2CSendData( port, s1, 0 )
    waitI2C( port )
  until( 8 == nxt.ButtonRead() )
end

-- And using the function - press the orange button on the NXT to stop it
IRTest()

Try covering the IRLink to verify that the motor stops after about 2 seconds with no signal, then expose the IRLink to turn the motor on again.

Turn MotorA Fwd/Off/Rev

The next example just expands of the previous one. It will generate IRLink strings on the fly depending on which button is pressed. If you stop pressing the button, the motor stops immediately.

-- Set up strings for brake, fwd, rev for motor A

b0 = nxt.EncodeIR( 0x013, 2 )
b1 = nxt.EncodeIR( 0x813, 2 )

f0 = nxt.EncodeIR( 0x011, 2 )
f1 = nxt.EncodeIR( 0x811, 2 )

r0 = nxt.EncodeIR( 0x012, 2 )
r1 = nxt.EncodeIR( 0x812, 2 )

-- And this is the test function

function IRTest(port)
  -- Set up the port and report on the sensor type
  checkI2C(port)

  repeat
    if nxt.ButtonRead() == 2 then       -- Set up for FWD
      s0, s1 = f0, f1                   -- multi-assignment, cool!
    elseif nxt.ButtonRead() == 4 then   -- Set up for REV
      s0, s1 = r0, r1
    else                                -- Set up for BRAKE
      s0, s1 = b0, b1
    end

    nxt.I2CSendData( port, s0, 0 )
    waitI2C( port )
    nxt.I2CSendData( port, s1, 0 )
    waitI2C( port )
  until( 8 == nxt.ButtonRead() )
end

-- And using the function - press the orange button on the NXT to stop it
IRTest()

That's not too hard, is it?

Going Further

Now that you have some idea how it works with one IRLink try the following exercises to see if you can make the IRLink part of your everyday robotics toolkit: