Remote Control NXT with bluetooth

Post your NXJ projects, project ideas, etc here!

Moderators: roger, 99jonathan, imaqine

Remote Control NXT with bluetooth

Postby Doug Fane » Mon Jan 30, 2012 1:47 am

I made something that allows you to use one NXT as a remote to control another using buetooth. All the controls and directions are comments in the code. I broke my phone, so I cannot upload pictures or video at the moment, but I will do so as soon as possible. This program works on my NXTs and the setup directions are simply the steps I took to get the devices set up. Please let me know if you have any issues.

The files can be downloaded here: http://www.tiarbi.com/lejos/RCNXT.zip

RCNXT.java
Code: Select all
/*
 ************RCNXT***************
 * FUNCTION:
 *  This class allows an nxt rig to act
 *  as a radio controlled car when used
 *  with the compatable controller class
 *
 * SETUP:
 *  Designed for a four wheeled/tracked setup
 *  with differential steering ability. Motor A
 *  powers the left wheel/track and Motor B powers
 *  the right wheel/track.
 *
 * USE:
 *  Run the RCNXT program on the cart vehicle
 *  before running the controller program on
 *  the controlling NXT
 *
 * PACKET INTERPRETATION:
 *  example packet: 897612
 *  -Because the packet is positive, the emergency brake is NOT engaged
 *  -The first two digits (89) control the left motor power
 *  -The thrid and fourth digits (76) control the right motor power
 *  -The fifth digit (1) controls the left motor direction
 *    -A value of 1 indicates backwards spinning
 *  -The final digit (2) controls the right motor direction
 *    -A value of 2 indicates forward spinning
 *  =In this example, the packet tells the cart to spin with the
 *   left motor spinning backwards at a speed of 89 and the right
 *   motor spinning forward at a speed of 76
 *
 *  example packet: -348222
 *  -Because the packet is negative, the emergency brake IS engaged
 *  -The first two digits (34) control the left motor power
 *  -The thrid and fourth digits (82) control the right motor power
 *  -The fifth digit (2) controls the left motor direction
 *    -A value of 2 indicates forward spinning
 *  -The final digit (2) controls the right motor direction
 *    -A value of 2 indicates forward spinning
 *  =In this example, the packet tells the cart to disengage both
 *   motors becuase the emergency brake was engaged.
*/

import lejos.nxt.Motor;
import lejos.nxt.Button;
import lejos.nxt.LCD;
import lejos.nxt.comm.BTConnection;
import lejos.nxt.comm.Bluetooth;
import java.io.*;
import java.lang.Math;

public class RCNXT {

   public static void main(String[] args) throws Exception{
      //BEGIN VARIABLE DEFINITIONS
      int right = 0;                     //right motor direction
      int left = 0;                     //left motor direction
      int rpower = 0;                     //right motor power
      int lpower = 0;                     //left motor power
      int p = 0;                        //packet received from controller
      //END VARIABLE DEFINITIONS


      LCD.clear();
      LCD.drawString("Connecting...", 2, 1);
      LCD.refresh();

      BTConnection btc = Bluetooth.waitForConnection();

      LCD.clear();
      LCD.drawString("Connected", 2, 1);
      DataInputStream dis = btc.openDataInputStream();

      Motor.B.flt();
      Motor.A.flt();
      while(!Button.ESCAPE.isPressed()){
         p = dis.readInt();               //gets packet from controller
         if (p > 0){
            LCD.drawInt(p, 4, 3);
            right = p % 10;               //right motor direction is the sixth digit
            p = p / 10;
            left = p % 10;               //left motor direction is the fith digit
            p = p / 10;
            rpower = p % 100;            //right motor power is always the third and fourth digit
            p = p / 100;
            lpower = p;                  //left motor power is always the first two digits
            rpower *= 8;
            lpower *= 8;               //raw input from throttles is multiplied to match full range of power
            LCD.drawInt(right, 1, 4);
            LCD.drawInt(left, 3, 4);
            LCD.drawInt(rpower, 0, 5);
            LCD.drawInt(lpower, 6, 5);
            Motor.B.setSpeed((float)rpower);
            Motor.A.setSpeed((float)lpower);

            if (right == 2){            //(numeral 2) corresponds to forward power
               Motor.B.forward();
            }
            else{
               Motor.B.backward();         //(numeral 1) corresponds to backward power
            }
            if (left == 2){
               Motor.A.forward();
            }
            else{
               Motor.A.backward();
            }
         }
         if (p < 0){
            Motor.B.flt();               //if the packet is negative, then the emergency brake is in place
            Motor.A.flt();               //flt is used in place of stop becuase it responds faster
         }
      }
      Thread.sleep(2000);
      LCD.clear();
      LCD.drawString("Close Connection", 0, 1);
      dis.close();
      btc.close();
      Thread.sleep(2000);
   }

}



Controller.java
Code: Select all
/*
 ************RCNXT***************
 * FUNCTION:
 *  This class allows an nxt rig to act
 *  as a radio controlled car when used
 *  with the compatable controller class
 *
 * SETUP:
 *  Designed for a four wheeled/tracked setup
 *  with differential steering ability. Motor A
 *  powers the left wheel/track and Motor B powers
 *  the right wheel/track.
 *
 * USE:
 *  Run the RCNXT program on the cart vehicle
 *  before running the controller program on
 *  the controlling NXT
 *
 * PACKET INTERPRETATION:
 *  example packet: 897612
 *  -Because the packet is positive, the emergency brake is NOT engaged
 *  -The first two digits (89) control the left motor power
 *  -The thrid and fourth digits (76) control the right motor power
 *  -The fifth digit (1) controls the left motor direction
 *    -A value of 1 indicates backwards spinning
 *  -The final digit (2) controls the right motor direction
 *    -A value of 2 indicates forward spinning
 *  =In this example, the packet tells the cart to spin with the
 *   left motor spinning backwards at a speed of 89 and the right
 *   motor spinning forward at a speed of 76
 *
 *  example packet: -348222
 *  -Because the packet is negative, the emergency brake IS engaged
 *  -The first two digits (34) control the left motor power
 *  -The thrid and fourth digits (82) control the right motor power
 *  -The fifth digit (2) controls the left motor direction
 *    -A value of 2 indicates forward spinning
 *  -The final digit (2) controls the right motor direction
 *    -A value of 2 indicates forward spinning
 *  =In this example, the packet tells the cart to disengage both
 *   motors becuase the emergency brake was engaged.
*/

import lejos.nxt.Motor;
import lejos.nxt.Button;
import lejos.nxt.LCD;
import lejos.nxt.comm.BTConnection;
import lejos.nxt.comm.Bluetooth;
import java.io.*;
import java.lang.Math;

public class RCNXT {

   public static void main(String[] args) throws Exception{
      //BEGIN VARIABLE DEFINITIONS
      int right = 0;                     //right motor direction
      int left = 0;                     //left motor direction
      int rpower = 0;                     //right motor power
      int lpower = 0;                     //left motor power
      int p = 0;                        //packet received from controller
      //END VARIABLE DEFINITIONS


      LCD.clear();
      LCD.drawString("Connecting...", 2, 1);
      LCD.refresh();

      BTConnection btc = Bluetooth.waitForConnection();

      LCD.clear();
      LCD.drawString("Connected", 2, 1);
      DataInputStream dis = btc.openDataInputStream();

      Motor.B.flt();
      Motor.A.flt();
      while(!Button.ESCAPE.isPressed()){
         p = dis.readInt();               //gets packet from controller
         if (p > 0){
            LCD.drawInt(p, 4, 3);
            right = p % 10;               //right motor direction is the sixth digit
            p = p / 10;
            left = p % 10;               //left motor direction is the fith digit
            p = p / 10;
            rpower = p % 100;            //right motor power is always the third and fourth digit
            p = p / 100;
            lpower = p;                  //left motor power is always the first two digits
            rpower *= 8;
            lpower *= 8;               //raw input from throttles is multiplied to match full range of power
            LCD.drawInt(right, 1, 4);
            LCD.drawInt(left, 3, 4);
            LCD.drawInt(rpower, 0, 5);
            LCD.drawInt(lpower, 6, 5);
            Motor.B.setSpeed((float)rpower);
            Motor.A.setSpeed((float)lpower);

            if (right == 2){            //(numeral 2) corresponds to forward power
               Motor.B.forward();
            }
            else{
               Motor.B.backward();         //(numeral 1) corresponds to backward power
            }
            if (left == 2){
               Motor.A.forward();
            }
            else{
               Motor.A.backward();
            }
         }
         if (p < 0){
            Motor.B.flt();               //if the packet is negative, then the emergency brake is in place
            Motor.A.flt();               //flt is used in place of stop becuase it responds faster
         }
      }
      Thread.sleep(2000);
      LCD.clear();
      LCD.drawString("Close Connection", 0, 1);
      dis.close();
      btc.close();
      Thread.sleep(2000);
   }

}
Doug Fane
New User
 
Posts: 9
Joined: Sun Dec 04, 2011 11:20 pm

Re: Remote Control NXT with bluetooth

Postby Doug Fane » Mon Jan 30, 2012 4:20 pm

UPDATE: I will be releasing a new version shortly with support for a ball shooter to be mounted on the front of the RC cart. I will be re-writing the program so as follows:

Controller.java:
-will now send the numeral 3 in the motor direction digits to indicate the brake being applied to the motor
-will send the packet as a negative integer if the fire ball button is derpressed

RCNXT.java:
-will now interpret a numeral 3 in the motor direction digit to cause an application of the brake to the indicated motor
-will now interpret a negative packet as a command to fire a ball (rotate Motor C exactly 360 degrees at maximum speed)


The updated code is being written now and will be posted after testing (some time tomorrow)
Doug Fane
New User
 
Posts: 9
Joined: Sun Dec 04, 2011 11:20 pm

Re: Remote Control NXT with bluetooth

Postby Doug Fane » Wed Feb 15, 2012 2:24 pm

I know it has been a while, but I cleaned everything up and added shooting functionality. The new instructions are part of the source code.

Code: Select all
/*
 ********CONTROLLER*********
 * FUNCTION:
 *  This class allows an NXT to be used
 *  as a remote to control another NXT
 *  via bluetooth
 *
 * SETUP:
 *  Touch sensors are attached to sensor
 *  ports 1 and 2. Motors A and B are
 *  attached in such a way that the user
 *  can freely turn them.
 *
 * USE:
 *  Pair the controller NXT with the desired
 *  cart NXT. Then turn off both NXTs and
 *  restart them. Run the RCNXT program on
 *  the cart NXT, once you see "Connecting..."
 *  on the cart NXT, run this program on the
 *  controller.
 *
 * CONTROLS:
 *   Touch Sensor 1 controls the Throttle Lock. If
 *  activated, the two motors will both spin at the
 *  speed of the left throttle. The right button
 *  controls the ball launcher. The launcher will
 *  fire once for every push of the button. The
 *  center (orange) button acts as the brake.
 *   pressing once will cause the cart to stop,
 *  pressing again will return control of the cart
 *  to the throttles.
 *
*/

import lejos.nxt.*;
import lejos.nxt.comm.*;
import java.io.*;
import javax.bluetooth.*;

public class Controller {

public static void main(String[] args) throws Exception {

   //BEGIN VARIABLE DEFINITIONS
   int lsend = 0;                                  //direction of left motor
   int rsend = 0;                                 //direction of right motor
   int ltsend = 0;                                 //left motor power
   int rtsend = 0;                                 //right motor power
   int toSend = 0;                                 //packet sent to RCNXT
   int p = 0;                                     //packet received from Cart
   int leftThrottleZero = 0;
   int rightThrottleZero = 0;
   int curLeftThrottle = 0;
   int curRightThrottle = 0;
   boolean fire = false;                           //fires a ball
   boolean brake = false;                           //emergency brake
   boolean send = false;                           //checks for change in input
   boolean throttleLock = false;                     //locks the motors at the same speed
   boolean leftLock = true;                        //tells which motor is the master when locked
   boolean centerButton = false;                     //indicates position of center button
   InputThread input;
   Thread inThread;
   TouchSensor leftButton = new TouchSensor(SensorPort.S1);
   TouchSensor rightButton = new TouchSensor(SensorPort.S2);
   //END VARIABLE DEFINITIONS

   LCD.clear();
   LCD.drawString("Connecting...", 2, 1);

   RemoteDevice bt = Bluetooth.getKnownDevice("NXT");      //connects to RCNXT

   if (bt == null){                              //checks for non-existant device
      LCD.clear();
      LCD.drawString("device not found", 0, 1);
      Thread.sleep(2000);
      System.exit(1);
   }

   BTConnection btc = Bluetooth.connect(bt);

   if (btc == null){                              //checks for failedd connection
      LCD.clear();
      LCD.drawString("connection fail", 0, 1);
      Thread.sleep(2000);
      System.exit(1);
   }

   LCD.clear();
   LCD.drawString("CONTROLLER ACTIVE", 0, 0);
   Thread.sleep(500);

   DataOutputStream dos = btc.openDataOutputStream();      //opens stream to RCNXT
   DataInputStream dis = btc.openDataInputStream();      //opens import stream to receive data from cart

   input = new InputThread(dis);
   inThread = new Thread(input);
   inThread.start();

   LCD.clear();
   LCD.drawString("Move throttles to", 0, 0);
   LCD.drawString("zero position and", 0, 1);
   LCD.drawString("press enter", 0, 2);
   LCD.drawString("Tacho count:", 0, 5);

   while (!Button.ENTER.isPressed()){
      curLeftThrottle = Motor.B.getTachoCount();
      curRightThrottle = Motor.C.getTachoCount();         //gets the desired starting position of the throttles
      LCD.drawInt(curLeftThrottle, 1, 6);
      LCD.drawInt(curRightThrottle, 5, 6);
   }
   leftThrottleZero = curLeftThrottle;
   rightThrottleZero = curRightThrottle;

   LCD.clear();
   LCD.drawString("Connected", 2, 1);

   while(!Button.ESCAPE.isPressed()){
      if (Motor.B.getTachoCount() != curLeftThrottle){   //gets the left motor power
         curLeftThrottle = Motor.B.getTachoCount();
         ltsend = curLeftThrottle - leftThrottleZero;
         send = true;
      }
      if (Motor.C.getTachoCount() != curRightThrottle){   //gets the right motor power
         curRightThrottle = Motor.C.getTachoCount();
         rtsend = curRightThrottle - rightThrottleZero;
         send = true;
      }
      if (leftButton.isPressed()){                  //checks the emergency brake
         if (!throttleLock){
            throttleLock = true;
            send = true;
         }
      }
      else{
         if (throttleLock){
            throttleLock = false;
            send = true;
         }
      }
      if (rightButton.isPressed()){                  //checks if the fire button is depressed
         if (!fire){
            fire = true;
            send = true;
         }
      }
      else{
         if (fire){
            fire = false;
            send = true;
         }
      }
      if (Button.RIGHT.isPressed()){
         leftLock = false;
         send = true;
      }
      if (Button.LEFT.isPressed()){
         leftLock = true;
         send = true;
      }
      if (Button.ENTER.isPressed()){
         if (!centerButton){
            centerButton = true;
            if (brake){
               brake = false;
               send = true;
            }
            else{
               brake = true;
               send = true;
            }
         }
      }
      else{
         if (centerButton){
            centerButton = false;
         }
      }

      if (send){                                 //sends packet to the RCNXT
         toSend = makePacket(ltsend, rtsend, brake, fire, throttleLock, leftLock);
         dos.writeInt(toSend);
         dos.flush();
         send = false;
      }
      LCD.drawString("          ", 0, 0);
      LCD.drawInt(toSend, 0, 0);
      LCD.drawString("                ", 0, 2);
      if (leftLock){
         LCD.drawString("LEFT", 0, 2);
      }
      else{
         LCD.drawString("RIGHT", 0, 2);
      }
      if (brake){
         LCD.drawString("BRAKE", 8, 2);
      }
      LCD.drawString("      ", 0, 5);
      if (throttleLock){
         LCD.drawString("LOCK", 0, 5);
      }
      p = input.readInt();
      if (p != 0){
         LCD.drawInt(p, 0, 7);
      }

   }
   dos.writeInt(999999);
   dos.flush();
   LCD.clear();
   LCD.drawString("Finished", 0, 1);
   Thread.sleep(4000);
   dos.close();
   btc.close();
   }

   public static int makePacket(int a, int b, boolean brake, boolean fire, boolean throttleLock, boolean leftLock){
      int pak = 0;

      int ld = 2;            //by default both motors drive forward (numeral 2)
      int rd = 2;

      if (throttleLock){
         if (leftLock){
            b = a;
         }
         else{
            a = b;
         }
      }

      if (a < 0){            //if either throttle position is below zero
         ld = 1;            //then the direction number is changed to backwards (numeral 1)
         a *= -1;
      }
      if (b < 0){
         rd = 1;
         b *= -1;
      }
      if (brake){
         ld = 3;
         rd = 3;
      }

      if (a > 99){
         a = 99;            //sets maximum throttle to 99 so that data can be sent with 2 digits
      }                  //this is aceptable because the motors cannot go faster than this anyway
      if (b > 99){
         b = 99;
      }

      pak += (a * 10000);      //left motor power is always the first two digits (assume a zero for values < 10)
      pak += (b * 100);      //right motor power is always the third and fourth digits
      pak += (ld * 10);      //left motor direction is the fifth digit
      pak += rd;            //right motor direction is the last (sixth) digit

      if (fire){
         pak *= -1;
         fire = false;
      }
      return pak;

   }
}


Code: Select all
/*
 ************RCNXT***************
 * FUNCTION:
 *  This class allows an nxt rig to act
 *  as a radio controlled car when used
 *  with the compatable controller class
 *
 * SETUP:
 *  Designed for a four wheeled/tracked setup
 *  with differential steering ability. Motor A
 *  powers the left wheel/track and Motor B powers
 *  the right wheel/track.
 *
 * USE:
 *  Run the RCNXT program on the cart vehicle
 *  before running the controller program on
 *  the controlling NXT
 *
 * PACKET INTERPRETATION:
 *  example packet: 897612
 *  -Because the packet is positive, the emergency brake is NOT engaged
 *  -The first two digits (89) control the left motor power
 *  -The thrid and fourth digits (76) control the right motor power
 *  -The fifth digit (1) controls the left motor direction
 *    -A value of 1 indicates backwards spinning
 *  -The final digit (2) controls the right motor direction
 *    -A value of 2 indicates forward spinning
 *  =In this example, the packet tells the cart to spin with the
 *   left motor spinning backwards at a speed of 89 and the right
 *   motor spinning forward at a speed of 76
 *
 *  example packet: -348233
 *  -Because the packet is negative, a ball will fire
 *  -The first two digits (34) control the left motor power
 *  -The thrid and fourth digits (82) control the right motor power
 *  -The fifth digit (3) controls the left motor direction
 *    -A value of 3 indicates an applied emergency brake
 *  -The final digit (3) controls the right motor direction
 *    -A value of 3 indicates an applied emergency brake
 *  =In this example, the packet tells the cart to disengage both
 *   motors becuase the emergency brake is engaged. A single ball will fire
*/

import lejos.nxt.Motor;
import lejos.nxt.Button;
import lejos.nxt.LCD;
import lejos.nxt.comm.BTConnection;
import lejos.nxt.comm.Bluetooth;
import java.io.*;
import java.lang.Math;

public class RCNXT {

   public static void main(String[] args) throws Exception{

      //BEGIN VARIABLE DEFINITIONS
      int right = 0;                     //right motor direction
      int left = 0;                     //left motor direction
      int rpower = 0;                     //right motor power
      int lpower = 0;                     //left motor power
      int p = 0;                        //packet received from controller
      int bul = 0;
      boolean fire = false;               //indicates if Motor C is firing
      InputThread input;
      Thread inThread;
      //END VARIABLE DEFINITIONS

      LCD.clear();
      LCD.drawString("Connecting...", 2, 1);
      LCD.refresh();

      BTConnection btc = Bluetooth.waitForConnection();

      LCD.clear();
      LCD.drawString("Connected", 2, 1);
      DataInputStream dis = btc.openDataInputStream();
      input = new InputThread(dis);
      inThread = new Thread(input);
      inThread.start();

      DataOutputStream dos = btc.openDataOutputStream();

      Motor.B.flt();
      Motor.A.flt();
      Motor.C.setSpeed(720f);
      while(!Button.ESCAPE.isPressed()){
         p = input.readInt();               //gets packet from controller
         if (p != 0){
            if (p == 999999){
            System.exit(0);
            }
            if (p < 0){
               p *= -1;               //a negative packet indicates a command to fire
               fire = true;
            }
            LCD.drawInt(p, 4, 3);
            right = p % 10;               //right motor direction is the sixth digit
            p = p / 10;
            left = p % 10;               //left motor direction is the fith digit
            p = p / 10;
            rpower = p % 100;            //right motor power is always the third and fourth digit
            p = p / 100;
            lpower = p;                  //left motor power is always the first two digits
            rpower *= 8;
            lpower *= 8;               //raw input from throttles is multiplied to match full range of power
            LCD.drawInt(right, 1, 4);
            LCD.drawInt(left, 3, 4);
            LCD.drawInt(rpower, 0, 5);
            LCD.drawInt(lpower, 6, 5);
            LCD.drawInt(bul, 3, 7);
            Motor.B.setSpeed((float)rpower);
            Motor.A.setSpeed((float)lpower);

            if (right == 2){            //(numeral 2) corresponds to forward power
               Motor.B.forward();
            }
            else if (right == 1){
               Motor.B.backward();         //(numeral 1) corresponds to backward power
            }
            else{
               Motor.B.flt();            //(numeral 3) corresponds to a brake on the motor
            }
            if (left == 2){
               Motor.A.forward();
            }
            else if (left == 1){
               Motor.A.backward();
            }
            else{
               Motor.A.flt();
            }
            if (fire){
               Motor.C.rotate(360, true);      //fires the ball and reloads the shooter
               bul ++;
               fire = false;
            }
         }
      }

      LCD.clear();
      LCD.drawString("Close Connection", 0, 1);
      dis.close();
      btc.close();
      Thread.sleep(2000);
   }

}


Code: Select all
/**
 * @(#)InputThread.java
 *
 *
 * @author
 * @version 1.00 2012/2/6
 */
import lejos.nxt.comm.*;
import lejos.nxt.*;
import java.io.*;

public class InputThread implements Runnable{

   DataInputStream dis;
   int input = 0;
   boolean running = true;

    public InputThread(DataInputStream d) {
       dis = d;
    }

    public static void main(String[] args){
       LCD.drawString("no", 0 , 0);
    }

    public void run(){
       while (running){
          try{
             input = dis.readInt();
          }
          catch (IOException e){

          }
       }
    }

    public int readInt(){
       return input;
    }


}
Doug Fane
New User
 
Posts: 9
Joined: Sun Dec 04, 2011 11:20 pm


Return to NXJ Projects

Who is online

Users browsing this forum: Google [Bot] and 1 guest

more stuff