Home > Arduino, Development boards, Guides > NXT Motor Shield

NXT Motor Shield

Update
The NXT Shield is for sale in our shop: http://shop.tkjelectronics.dk/product_info.php?products_id=29. A easy to use library is also provided: https://github.com/TKJElectronics/NXTShield.
Three examples that demonstrates reading the encoders, turning the motors and using the ultrasonic sensor is found in the library as well: https://github.com/TKJElectronics/NXTShield/tree/master/examples.

More pictures of the NXT Shield can be found at the following blog post: http://blog.tkjelectronics.dk/2012/04/nxt-shield-library/.


The shield mounted on a Arduino

Hallo everybody

I recently made a NXT motor shield for my arduino. It can control two NXT motors and also read the onboard encoders. In true Arduino spirit I decided to share it with the rest of the community. But first i will talk about how everything works, and then show the finished shield including a short video demonstration.

Physically connecting the motors
The NXT cable is a RJ12-like cable. The only diference is the latch is offset to the right side. The schematic for the output port are as follows:

Output schematic

Pin 1 (white) and 2 (black) are pwm output signals for the motor. This should be approximatly 9 volts.
Pin 3 (red) are the ground wire needed by the encoders.
Pin 4 (green) are the 4.3 volts power signal for the encoders.
Pin 5 (yellow) and 6 (blue) are the inputs from the encoders.

For more information look in the LEGO MINDSTORMS NXT Hardware Developer Kit.

Encoders
Encoders works by sending out a pulse every time you rotate the shaft. There are two encoders in each motor. When rotating the shaft, the pulses will look like this:

Two square waves in quadrature (clockwise rotation)

By reading the pulses and counting them, the Arduino can figure out what direction the wheel is turning and for how many degrees.
To read the signal I simple use an interrupt. The problem is that the output can be a bit noise, to smooth this out I use a schmitt trigger circuit identical to the one inside the NXT (see the datasheet and LEGO MINDSTORMS NXT Hardware Developer Kit at “Appendix 1-LEGO MINDSTORMS NXT hardware schematic”).
This will smooth out the the signal, so the Arduino can measure it precisely.
For further explanation look at: http://www.brickengineer.com/pages/2008/09/05/lego-nxt-motor-wiring/ and http://en.wikipedia.org/wiki/Rotary_encoder#Incremental_rotary_encoder.

By using one interrupt per motor, one can get 1 degrees of resolution. But if two are used 0.5 degrees can be obtained – this could for example be done with the Arduino mega.

The code for reading the encoders looks like this:

#define Tach01 2
#define Tach02 4
#define Tach03 3
#define Tach04 5

volatile int TachPos1 = 0;
volatile int TachPos2 = 0;

void setup(){
  pinMode(Tach01, INPUT);
  pinMode(Tach02, INPUT);
  pinMode(Tach03, INPUT);
  pinMode(Tach04, INPUT);

  attachInterrupt(0, Tach01encoder, CHANGE); //pin 2
  attachInterrupt(1, Tach02encoder, CHANGE); //pin 3

  Serial.begin(9600);
}

void loop(){
  Serial.print(TachPos1);Serial.print("\t");
  Serial.print(TachPos2);Serial.print("\t");
  Serial.println("");
}
void Tach01encoder(){
  if((PIND & B00010100) == 0 || (PIND & B00010100) == 20)//pin 2 == pin 4
  {
    TachPos1--;
  }
  else{
    TachPos1++;
  }
}
void Tach02encoder(){
  if((PIND & B00101000) == 0 || (PIND & B00101000) == 40)//pin 3 == pin 5
  {
    TachPos2--;
  }
  else{
    TachPos2++;
  }
}

I read directly from the port registers in the interrupt to use the smallest amount of time. For further information see http://www.arduino.cc/en/Reference/PortManipulation and http://www.arduino.cc/playground/Code/BitMath.

Motors
The motors are control with a pwm signal. By increasing the pwm signal, the speed of the motor will also increase. The motor is connected with two wires as explained earlier (the white and black wire). If the white is connected to positive and the black wire is connected to negative the motor will turn one way and if connected opposite the motor will turn the other direction. This is done with a IC called a H-bridge. I use the L293D (see this datasheet) which can deliver enough current for the motors. It also has internal protection diodes, which is needed for protecting your circuit from high voltage spikes from the motors.
For more information on how a H-bridge works. Look at this excellent guide: http://itp.nyu.edu/physcomp/Labs/DCMotorControl for further details.

The code for the motors could look like this:

#define logicleft1 8
#define logicleft2 10
#define pwm1 11

#define logicright1 7
#define logicright2 12
#define pwm2 6

void setup()
{
  pinMode(pwm1, OUTPUT);
  pinMode(logicleft1, OUTPUT);
  pinMode(logicleft2, OUTPUT);

  pinMode(pwm2, OUTPUT);
  pinMode(logicright1, OUTPUT);
  pinMode(logicright2, OUTPUT);
}

void loop()
{
  for(int i=0;i<255;i++)
  {
    analogWrite(pwm1, i);
    digitalWrite(logicleft1, HIGH);
    digitalWrite(logicleft2, LOW);
    analogWrite(pwm2, i);
    digitalWrite(logicright1, HIGH);
    digitalWrite(logicright2, LOW);
    delay(10);
  }
  delay(1000);
  for(int i=255;i>0;i--)
  {
    analogWrite(pwm1, i);
    digitalWrite(logicleft1, HIGH);
    digitalWrite(logicleft2, LOW);
    analogWrite(pwm2, i);
    digitalWrite(logicright1, HIGH);
    digitalWrite(logicright2, LOW);
    delay(10);
  }
  delay(1000);
}

This will just keep increasing the motor speed, and then decrease again from full speed.

The shield
The finished shield look like this:

The finished shield

The shield mounted on a Arduino

I have uploaded the schematic and the PCB made in eagle, together with the gerber files ready for shipping at www.dorkbotpdx.org. All the files can be found in this .zip file: NXT Motor Shield PCB.

NB: The shield is licensed under a Creative Commons Attribution Noncommercial Share-Alike license, see this link for details: http://creativecommons.org/licenses/by-nc-sa/3.0/

Features:

  • Full motor control
  • 1 degrees resolution encoders on both motors
  • Socket for IR reciever
  • Reset button mounted on top
  • Power LED
  • Status LED on pin 13
  • I got two spare shields, so if anyone is interested I will sell them as a kit – just send me a personal message here at the forum, and we will figure out a price.

    Demonstration
    The first demonstration shows the robot controlled by my Apple Remote using Ken Shirriff’s excellent IR library.

    The code look like this:

    #include <IRremote.h>

    const long iup = 0x77E1D0BE;
    const long idown = 0x77E1B0BE;
    const long iright = 0x77E1E0BE;
    const long ileft = 0x77E110BE;
    const long icenter = 0x77E1BABE;
    const long imenu = 0x77E140BE;
    const long iplay = 0x77E17ABE;
    const long irepeat = 0xFFFFFFFF;

    int RECV_PIN = 9;
    IRrecv irrecv(RECV_PIN);
    decode_results results;

    //Right motor
    #define logicright1 8
    #define logicright2 10
    #define pwm1 11
    //Left motor
    #define logicleft1 7
    #define logicleft2 12
    #define pwm2 6

    int left = 0;
    int right = 1;
    int backward = 0;
    int forward = 1;

    int pwm;
    int logic1;
    int logic2;

    int count = 0;

    void setup(){
      irrecv.enableIRIn(); // Start the receiver

      pinMode(pwm1, OUTPUT);
      pinMode(logicleft1, OUTPUT);
      pinMode(logicleft2, OUTPUT);

      pinMode(pwm2, OUTPUT);
      pinMode(logicright1, OUTPUT);
      pinMode(logicright2, OUTPUT);
    }

    void loop(){
      if(irrecv.decode(&results)){
        count = 0;
        //Serial.println(results.value, HEX);
        switch(results.value){
        case iup:
          move(left,forward,100);
          move(right,forward,100);
          break;
        case idown:
          move(left,backward,100);
          move(right,backward,100);
          break;
        case iright:
          move(left,forward,100);
          stop(0);
          break;
        case ileft:
          move(right,forward,100);
          stop(1);
          break;
        case icenter:
          break;
        case imenu:
          break;
        case iplay:
          break;
        case irepeat:
          break;
        }
        delay(10);
        irrecv.resume(); // Receive the next value
      }
      else{
        count++;
        delay(1);
        if(count == 100){
          stop(0);
          stop(1);
        }
      }
    }
    void move(int motor, int way, int power){
      if(motor == 1){//right
        pwm = pwm1;
        logic1 = logicleft1;
        logic2 = logicleft2;
      }
      if(motor == 0){//left
        pwm = pwm2;
        logic1 = logicright1;
        logic2 = logicright2;
      }
      power = map(power,0,100,0,255);
      analogWrite(pwm, power);
      if(way == 0){//backward
        digitalWrite(logic1, LOW);
        digitalWrite(logic2, HIGH);
      }
      if(way == 1){//forward
        digitalWrite(logic1, HIGH);
        digitalWrite(logic2, LOW);
      }
    }
    void stop(int motor){
      if(motor == 0){//left
        digitalWrite(pwm1, HIGH);
        digitalWrite(logicleft1, HIGH);
        digitalWrite(logicleft2, HIGH);
      }
      if(motor == 1){//right
        digitalWrite(pwm2, HIGH);
        digitalWrite(logicright1, HIGH);
        digitalWrite(logicright2, HIGH);
      }
    }

    The next example is a bit mote complicated. It is controlled by a PS3 controller connected to Processing via Bluetooth. It then sends serial data through a XBee to the Arduino:

    The arduino code:

    //Right motor
    #define logicright1 8
    #define logicright2 10
    #define pwm1 11
    //Left motor
    #define logicleft1 7
    #define logicleft2 12
    #define pwm2 6

    int pwm;
    int logic1;
    int logic2;

    int buffer[2];

    void setup(){
      pinMode(pwm1, OUTPUT);
      pinMode(logicleft1, OUTPUT);
      pinMode(logicleft2, OUTPUT);

      pinMode(pwm2, OUTPUT);
      pinMode(logicright1, OUTPUT);
      pinMode(logicright2, OUTPUT);
     
      Serial.begin(9600);
    }

    void loop(){
      if(Serial.available()>1){
        for(int i=0;i<2;i++){
          buffer[i] = Serial.read()-48;
        }
        if(buffer[1] == 0){
          stop(buffer[0]);
        }
        else{
          move(buffer[0], buffer[1], 100);
        }
      }  
    }

    void move(int motor, int way, int power){
      if(motor == 0){//right
        pwm = pwm1;
        logic1 = logicleft1;
        logic2 = logicleft2;
      }
      if(motor == 1){//left
        pwm = pwm2;
        logic1 = logicright1;
        logic2 = logicright2;
      }
      power = map(power,0,100,0,255);
      analogWrite(pwm, power);
      if(way == 1){//backward
        digitalWrite(logic1, LOW);
        digitalWrite(logic2, HIGH);
      }
      if(way == 2){//forward
        digitalWrite(logic1, HIGH);
        digitalWrite(logic2, LOW);
      }
    }
    void stop(int motor){
      if(motor == 0){//right
        digitalWrite(pwm1, HIGH);
        digitalWrite(logicleft1, HIGH);
        digitalWrite(logicleft2, HIGH);
      }
      if(motor == 1){//left
        digitalWrite(pwm2, HIGH);
        digitalWrite(logicright1, HIGH);
        digitalWrite(logicright2, HIGH);
      }
    }

    I have uploaded the processing code as a .zip file. Click here to download.

    Sources:
    All information can be found in the LEGO MINDSTORMS NXT Hardware Developer Kit.

    To do:

  • Make a new version with custom RJ12 female sockets from Mindsensors
  • Make the Ultrasonic Sensor work as well. My plan is to add two sensor inputs to the shield. Right now I am struggling to get the Ultrasonic sensor to work. If anyone have some ideas or experience with it please visit my post here on the Arduino forum.
  • Categories: Arduino, Development boards, Guides Tags:
    1. Robert Libby
      August 24th, 2011 at 17:25 | #1

      How do I go about ordering the board with those files? I have never ordered a board and am not sure the information I need to give them. Board type, 2 layers that kind of stuff.

      thanks

    2. Lauszus
      August 25th, 2011 at 09:05 | #2

      Hello
      It is called gerber files. It is a standard format for manufactoring PCB’s. It is send directly to the manufactory. They are made in eagle or any other design program, using a CAM-job. The one in the .zip file, are made with the CAM job found here: http://content.laen.org/pcb/LaenPCBOrder.cam
      If you want one of your own. You can just send them to this mail pcb-order@laen.org. You can also send him your eagle files, but it is better to send him gerber files, as you can decide exactly what you want -- like silkscreen and so on đŸ™‚
      -- Lauszus

    3. Ă©tienne
      January 28th, 2012 at 20:03 | #3

      can I buy it ?

    4. January 28th, 2012 at 20:42 | #4

      Yes sure.
      You can buy it directly from our online shop -> shop.tkjelectronics.dk

    5. Ajay
      October 11th, 2012 at 10:58 | #5

      Hi there,

      Are you still selling the shield?

      Thanks in advance.

    6. October 11th, 2012 at 11:38 | #6

      @Ajay
      Yes I made a new version which support the Ultrasonic sensor as well and use the custom NXT connectors.

      See these two pages for more information: http://blog.tkjelectronics.dk/2012/04/nxt-shield-library/ and http://blog.tkjelectronics.dk/2011/10/nxt-shield-ver2/

      And here is the link to the NXT shield in our store: http://shop.tkjelectronics.dk/product_info.php?products_id=29

    7. September 24th, 2013 at 19:24 | #7

      if I can provide a suggestion: those small boards are less useful than a standard nxt brick (cause you know, less ports than it).

      if you want to make a useful board, make a board that can control 8 nxt sensors and 8 nxt motors: such a configuration is difficult to work with standard nxt bricks, cause you are forced to network them together via bluetooth or usb

    8. September 25th, 2013 at 13:56 | #8

      @b73 plus plus
      You can actually get something like that at the following site: http://www.mindsensors.com/index.php?module=pagemaster&PAGE_user_op=view_page&PAGE_id=182, but the reason why I decided to create the shield is that I simply wanted to be able to drive two motors for a robot I was building.

      Also since it is Arduino compatible you can use it for a lot more, as you are not limited to the limitations of the NXT brick.

    9. June 10th, 2014 at 01:29 | #9

      Very nice project! Congrats!!

    10. Pat Rogers
      January 29th, 2016 at 17:29 | #10

      Hi Lauszus,
      I got the kit and am using it with another board, not an Arduino (an MCU from STMicro). I have the motor power and direction working as expected, and am getting good encoder signals on three of the four input pins. However, the other encoder signal is stuck high, specifically motor 2 tach1, connected to header pin 3 on the NXT shield. Encoder signals on pins 2, 5, and 6 are all good in my logic analyzer. I’ve been looking for cold solders and such but have not found any yet. I am a software guy so maybe I am missing something simple. I am hoping you could give me some suggestions for where to look for problems. I am sharing ground with the other board and taking 5V from it (for the encoder power), with another external 9V battery connected for the motors. Could my lack of an Arduino connection be a problem?
      Thanks very much for any insights you can suggest!

    11. February 2nd, 2016 at 00:28 | #11

      @Pat Rogers
      Do you got access to an oscilloscope? Can you try to probe the output from the motor directly, so we can make sure that it is not a hardware issue with the motors itself?

    12. February 2nd, 2016 at 00:28 | #12

      @Pat Rogers
      Also maybe you can test it with an Arduino and see if that works?

    1. No trackbacks yet.