Part 1:
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" (http://mindstorms.lego.com/en-us/support/files/default.aspx).
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 http://focus.ti.com/lit/ds/symlink/sn74hc14.pdf and http://mindstorms.lego.com/en-us/support/files/default.aspx "LEGO MINDSTORMS NXT Hardware Developer Kit" under "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: LEGO NXT Motor Wiring | BrickEngineer: LEGO Design and Rotary encoder - Wikipedia.
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 Arduino Reference - Arduino Reference and Arduino Playground - 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 (http://www.st.com/internet/com/TECHNICAL_RESOURCES/TECHNICAL_LITERATURE/DATASHEET/CD00000059.pdf) 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:
I have uploaded the schematic and the PCB made in eagle, together with the gerber files ready for shipping at PCB Order - just look in the bottom of this page.
NB: The shield is licensed under a Creative Commons Attribution Noncommercial Share-Alike license, see this link for details: Creative Commons — Attribution-NonCommercial-ShareAlike 3.0 Unported — CC 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.
NXT Motor Shield.zip (662 KB)