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/.
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:
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:
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 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 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:
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:
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:
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:
#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:
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
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
can I buy it ?
Yes sure.
You can buy it directly from our online shop -> shop.tkjelectronics.dk
Hi there,
Are you still selling the shield?
Thanks in advance.
@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
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
@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.
Very nice project! Congrats!!
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!
@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?
@Pat Rogers
Also maybe you can test it with an Arduino and see if that works?