Hauptpost – Klick!

 

Changelog:

  • Es liegen jetzt Treiber für sowohl den NXT, als auch den RFID Reader bei.
  • Die Programme wurden überarbeitet, um den NXT responsiver zu machen.
  • Bugfixes

Download v5.0

 

Die neuen Codes:

Java PC-Programm:

//Written by Peter Por
//Last edited: 30.07.13
 
package nxtrfid;
 
import lejos.pc.comm.*;
import java.io.*;
 
 
public class NXTRFID {	
 
  public static void main(String[] args) throws IOException, InterruptedException 
  {
	  String nxtName = "NXT";   //Name of the specific NXT brick; "NXT" is default
	  int COMPort = 8;      //The COM-Port of the RFID Reader	
	  String RFIDScanLocation = "RRFIDScan_v.2.0.1.exe";    //The Location of the ".exe" file for the RFID Reader
	  String Music = "vlc/vlc.exe --play-and-exit --novideo Music.mp3";     //Commandline promt opening VLC and the sound file
	  String InputLocation = "NXTRFID.conf";    //Location of the config file
	  int keypressOld = 9999;   //the last read RFID tag's ID will be saved here
 
	  //You may change the location of the conf file by sending a command line argument
	if(args.length!=0)
	{
		InputLocation = args[0];
	}
 
	//Read the config file
	try 
	{
		BufferedReader in = new BufferedReader(new FileReader(InputLocation));
		String line1 = in.readLine();
		String line2 = in.readLine();
		String line3 = in.readLine();
		String line4 = in.readLine();
 
		nxtName = line1;
		COMPort = Integer.parseInt(line2);
		RFIDScanLocation = line3;
		Music = line4;
 
		in.close();
	} 
	catch (IOException err) 
	{
		err.printStackTrace();
	}
 
    //Necessary declarations for establishing the connection
    NXTInfo[] nxts;
    NXTConnector connect = new NXTConnector();
 
    nxts = connect.search(nxtName,null,NXTCommFactory.BLUETOOTH);    //Searches for nearby NXTs
 
    if(nxts.length == 0)
    { //The NXT was not in range
      System.out.print(nxtName + " not found!");
    }
    else{
      if(!connect.connectTo(nxts[0].name,nxts[0].deviceAddress,NXTCommFactory.BLUETOOTH))
      { //Connection failed
        System.out.println("Connecting to " + nxtName + " failed!");
      }
      else
      { //now there is a connection
        System.out.println("Successfully connected to " + nxtName + " !");
        DataOutputStream dos = new DataOutputStream(connect.getOutputStream());
 
        while(true){
         try
         {
          Process p = Runtime.getRuntime().exec(RFIDScanLocation + " " + COMPort);   //This declaration starts the ".exe" file for the RFID Reader; The number following specifies the COM port
          p.waitFor();    //Waits until the ".exe" has finished
          dos.writeInt(p.exitValue());    //Writes the exitValue of the RFIDScan program to the NXT
          dos.flush();
 
          //Starts VLC and opens the sound file - 3 is the Code for "Dance"
          if(p.exitValue()==3 && p.exitValue() != keypressOld)
          {
        	  Thread.sleep(10);
        	  try
        	  {
        		 Runtime.getRuntime().exec(Music);
        	  }
        	  catch(Exception ex)
        	  {
  		        System.out.println("Error with playing sound.");
  		        ex.printStackTrace();
  		      }
          }
 
          if(p.exitValue()==-1)   // -1 is the code for "Terminate"
          {
        	  System.out.println("The Program will now shut down.");
        	  break;
          }
          if(p.exitValue()==-2)   // -2 is the Error-Code
          {
        	  System.out.println("Error reading the RFID Tag.");
        	  break;
          }
 
          keypressOld=p.exitValue();
         }
         catch(Exception err)
         {
        	 System.out.println("An unknown Error occured.");
        	 break;
         }
        }// end of loop       
 
    	dos.close();    //Closes the DataOutputStream
        connect.close();    //Closes the Connection to the NXT
        System.out.println("Program was terminated successfully.");
      }
     }
 
    }// end of main
   } // end of class Main

C++ PC-Programm (RFID):

// RFIDScan.cpp : Defines the entry point for the console application.
// Written by Andreas Mieke
// Date: 30.07.13
 
#define VERSION "3"
//#define DEBUG		//Uncomment this to see what is scanned from RFIDScan.conf and what is the TagID on the scanner
#define MAX_TAGS (20)	//Defines the maximum number of RFID tags to be scanned
 
#include "std_inc.h"
#include "comm.h"
#include "protocol.h"
#include "std_readwrite.h"
 
//General purpose buffer
char buffer[1000];
char code[17];
int tagCounter = 0;
int tagCounterMax = 0;
char tagIDs[17][MAX_TAGS];
int tagReturns[MAX_TAGS];
 
//This function closes the reader and communication handle
//If not connected the two variables are set to zero
void CloseComm() {
    //If the reader handle is set, close the reader
    if(reader_handle) {
        RDR_CloseReader(reader_handle);
        reader_handle = NULL;
    }
 
    //If the COM handle is set, close the COM port
    if(comm_handle) {
        RDR_CloseComm(comm_handle);
        comm_handle = NULL;
    }
}
 
bool OpenComm() {
    char input_buffer[50], detect_buffer[256];
 
     //Close any possible open connection
    CloseComm();
 
    comm_handle = RDR_OpenComm(com_port, 1, NULL);
 
    if(comm_handle == 0) { //zero indicates error while opening the com port
        printf("\n\nError opening reader(com).\n");
 
        return false;
    }
 
    //After sucessfully opening the com port, try to open the reader
 
    //First detect the station ID of the reader
    RDR_DetectReader(comm_handle, detect_buffer);
 
    //Open the reader with the first detected station ID
    reader_handle = RDR_OpenReader(comm_handle, detect_buffer[0], 0);
 
    if(reader_handle == 0) { //zero indicates error while opening reader
        //Since the com port is allready open, close it on error contition
        CloseComm();
 
        printf("\n\nError opening reader.\nPress any key to continue...");
        getch();
 
        return false;
    }
 
    //Stop the maybe activated continous read (should only be done after opening the reader)
    //RDR_EmptyCommRcvBuffer is not needed because this is implicit done with RDR_AbortContinuousRead
    RDR_AbortContinuousRead(comm_handle);
    return true;
}
 
//This function expalains the standard read/write sequence for a standard MIFARE card [ASCII]
//If the default key is not valid you have to change the line in the source code below
void DoASCIIReadWrite() {
    //The first action is to select the card
    //The select command has no data
    RDR_SendCommandGetData(reader_handle, "select", "", buffer);
	sprintf(code, "%s", buffer);
	strcpy(buffer,"");
}
 
//Main programm entry point
int main(int args, char* argv[]) {
	char* filepath;
	if(args < 2)
	{
		printf("[ERROR]\tPlease provide the right COM port <name_of_file.exe {portnumer} [path_to_config]>\n");
		return -2;
	}
	printf("RFIDScan Version: %s; Coded by Andreas Mieke\n\n[JOB]\t\tLoading config file...\n\n",VERSION);
	if(argv[2] != NULL)
		filepath = argv[2];
	else
		filepath = "RFIDScan.conf";
	FILE *configFile = fopen(filepath,"r");
	if(configFile != NULL)
	{
		fgets(buffer, sizeof(buffer), configFile);
		tagCounterMax = atoi(buffer);
		if(tagCounterMax > MAX_TAGS)
		{
			printf("[ERROR]\tYour specification of tags has too much elements! Max: %d",MAX_TAGS);
			return -3;
		}
		if(tagCounterMax < 1)
		{
			printf("[WARNING]\tFailed to read the config file (maybe because encoding is not ANSI?)");
			return -6;
		}
		for(; tagCounter < tagCounterMax; tagCounter++)
		{
			fscanf(configFile,"%s%d", tagIDs[tagCounter], &tagReturns[tagCounter]);
#ifdef DEBUG
			printf("[DEBUG]\t%s : %d\n", tagIDs[tagCounter], tagReturns[tagCounter]);
#endif
		}
		fclose(configFile);
		printf("[SUCCESS]\tConfig file successfully loaded. Program started.\n\n");
	}
	else
	{
		printf("[FATAL ERROR]\tConfig file \"%s\" could not be opened!\n", filepath);
		return -4;
	}
	sprintf(com_port,"COM%d",atoi(argv[1])); //Sets the content of argv[1] as COM port
 
	if(OpenComm() == false) //Opens the connection to the RFID reader (comm.cpp)
	{
		printf("[FATAL ERROR]\tCould not connect to the RFID Reader!\n");
		return -5;
	}
 
	do { //Continues until a valid ID was scanned.
		do { //Tries as long to scan a Tag as it doesn't find one.
			DoASCIIReadWrite(); // (std_readwrite.cpp)
		} while ((strlen(code) == 0) || (strlen(code) == 1)); //Strlen of 0 or 1 indicates error
 
#ifdef DEBUG
		printf("[DEBUG] %s\n",code); //Prints the HEX-Code (TAGID) to the screen
#endif
 
		for(tagCounter = 0; tagCounter < tagCounterMax; tagCounter++)
		{
			if(strcmp(code,tagIDs[tagCounter]) == 0)
			{
#ifdef DEBUG
				printf("%s return %d\n",tagIDs[tagCounter],tagReturns[tagCounter]);
#endif
				CloseComm(); //Closes connection to Reader (comm.cpp)
				return tagReturns[tagCounter];
			}
#ifdef DEBUG
			else
			{
				printf("no match\n");
			}
#endif
		}
		strcpy(code,"");
	} while(true);
}
//EOF

Java NXT-Programm:

//Written by Peter Por
//Last edited: 30.07.13     
 
import java.io.IOException;
import lejos.nxt.*;
import lejos.nxt.comm.*;
import java.io.*;
import javax.bluetooth.*;
import lejos.util.Delay;
import lejos.nxt.UltrasonicSensor;
 
 
 
public class BluetoothNXT_v5 {
 
  //globally accessable variables
  public static int keypress = 0, keypressOld = 9999;
  public static boolean mayDriveForward=true, mayDriveBackward = true, clawsOpen=false;
 
  public static void main(String [] args) throws Exception
  {
    String connected = "Connected";
    String waiting = "Waiting...";
    String closing = "Closing...";
 
    //Starting the Thread which controls the ultrasonic sensors
    Indicators ussf = new Indicators();
    ussf.setDaemon(true);
    ussf.start();
 
    //Waiting for, and establishing, the bluetooth connection
    LCD.drawString(waiting,0,0);
    LCD.refresh();
    BTConnection btc = Bluetooth.waitForConnection();
    LCD.clear();
    LCD.drawString(connected,0,0);
    LCD.refresh();
    Sound.beepSequenceUp();
    DataInputStream dis = btc.openDataInputStream();
    DataOutputStream dos = btc.openDataOutputStream();
    ////////////////////////////////////////////////////////////////////////////  
    mayDriveForward=true;
    mayDriveBackward=true;
 
 
    while(true)
    {//start loop
 
      try{//waiting for the order from the PC program
        keypress=dis.readInt();
      }
      catch(IOException e)
      {
        LCD.drawString("Error:",0,0);
        LCD.drawString("Datastream Invlaid.",0,1);
        LCD.refresh();
        break;
      }
      Thread.sleep(100);
 
 
      //Forward
      if (keypressOld!=8 && keypress ==8 && mayDriveForward) 
      {
        Motor.A.setSpeed(1200);
        Motor.C.setSpeed(1200);
        Motor.A.forward();
        Motor.C.forward();
        mayDriveBackward=true;
      } // end of if
      else
      //Backward
      if (keypressOld!=2 && keypress ==2 && mayDriveBackward) 
      {
        Motor.A.setSpeed(1200);
        Motor.C.setSpeed(1200);
        Motor.A.backward();
        Motor.C.backward();
        mayDriveForward=true;
      } // end of if
      else
      //Turn right
      if (keypressOld!=6 && keypress ==6) 
      {
        Motor.A.setSpeed(150);
        Motor.C.setSpeed(150);
        Motor.A.forward();
        Motor.C.backward();
        mayDriveForward=true;
        mayDriveBackward=true;
      } // end of if
      else
      //Turn left
      if (keypressOld!=4 && keypress ==4) 
      {         
        Motor.A.setSpeed(150);
        Motor.C.setSpeed(150);
        Motor.A.backward();
        Motor.C.forward();
        mayDriveForward=true;
        mayDriveBackward=true;
      } // end of if
      else
      //Stop
      if (keypress ==5) 
      {
        if (keypressOld==8||keypressOld==2)
        SoftStop();
        Motor.A.stop();
        Motor.C.stop();
      } // end of if
      else
      //Close Claws
      if (keypressOld!=keypress && clawsOpen && keypress==9) 
      {
        if (keypressOld==8||keypressOld==2)
        {SoftStop();}
        Motor.A.stop();
        Motor.C.stop();
        Motor.B.setSpeed(100);
        Motor.B.backward();
        Thread.sleep(1000);
        Motor.B.stop();
        clawsOpen=false;
      } // end of if
      else
      //Dance like nobody's watching
      if (keypressOld!=3 && keypress==3) 
      {
        SoftStop();
        Motor.A.stop();
        Motor.C.stop();
        if (!clawsOpen) 
        {                               
          Motor.B.setSpeed(100);
          Motor.B.forward();
          Thread.sleep(1000);
          Motor.B.stop();
          clawsOpen=true;
        }
        Dance.startDance();
      } // end of if  
      //Open claws
      else
      if (true) 
      {
        if (keypressOld!=keypress && !clawsOpen && keypress==7) 
        {
          if (keypressOld==8||keypressOld==2)
          SoftStop();
          Motor.A.stop();
          Motor.C.stop();
          Motor.B.setSpeed(100);
          Motor.B.forward();
          Thread.sleep(1000);
          Motor.B.stop();
          clawsOpen=true;
        } // end of if   
        mayDriveForward=true;
      }      
      keypressOld=keypress;
    }//end loop
 
 
    //Terminating the program
 
    //closes claws in case they were open
    if (clawsOpen) 
    {                               
      SoftStop();
      Motor.A.stop();
      Motor.C.stop();
      Motor.B.setSpeed(100);
      Motor.B.backward();
      Thread.sleep(1000);
      Motor.B.stop();
      clawsOpen=false;
    }
 
    //closes the bluetooth connection
    dis.close();
    dos.close();
    Thread.sleep(90); // wait for data to drain
    LCD.clear();
    LCD.drawString(closing,0,0);
    LCD.refresh();
    btc.close();
    LCD.clear();
  }
 
 
  //Due to a hardware problem regarding the NXT's motors, this method was necessary in order to stop both motors at the same time
  static void SoftStop()
  {
    int i = 1200;
    while(i>0)
    {
      Motor.A.setSpeed(i);
      Motor.C.setSpeed(i);
      Delay.msDelay(10);
      i=i-100;
    }
  }
}
 
 
//Ultrasonic-Thread
class Indicators extends Thread 
{
  //Declaring the sensor-ports
  UltrasonicSensor sonicF = new UltrasonicSensor(SensorPort.S1);
  UltrasonicSensor sonicB = new UltrasonicSensor(SensorPort.S2);
  int safetyDistanceF=30, safetyDistanceB=27;
 
  //Workerthread
  public void run() 
  {
    while (true) 
    {
      //If the claws are open, the safety-distance is smaller
      if (BluetoothNXT_v5.clawsOpen)
      safetyDistanceF=23;
      else
      safetyDistanceF=30;
 
 
      try
      {
        if (sonicF.getDistance()<safetyDistanceF && BluetoothNXT_v5.keypress==8) 
        {//The NXT is currently driving forwards and faces an obstacle
          Motor.B.stop();
          BluetoothNXT_v5.SoftStop();
          Motor.A.stop();
          Motor.C.stop();       
          BluetoothNXT_v5.mayDriveForward = false;                  
        }
      }      
      catch(Exception err)
      { }
 
 
      try
      {
        if (sonicB.getDistance()<safetyDistanceB && BluetoothNXT_v5.keypress==2) 
        {//The NXT is currently driving backwards and faces an obstacle
          Motor.B.stop();
          BluetoothNXT_v5.SoftStop();
          Motor.A.stop();
          Motor.C.stop();     
          BluetoothNXT_v5.mayDriveBackward = false;                  
        }
      }      
      catch(Exception err)
      { }     
    }     
  }
}
 
 
class Dance {
 
  public static void startDance()
  {
    try{
      //Declaring the sensor-ports
      UltrasonicSensor sonicF = new UltrasonicSensor(SensorPort.S1);
      UltrasonicSensor sonicB = new UltrasonicSensor(SensorPort.S2);
      //Getting the current time
      long startTime = System.currentTimeMillis();
      Delay.msDelay(20);
      long endTime = System.currentTimeMillis();
 
      //The program may only run for 29seconds (30seconds is the duration of the music we chose, the last second is used to close the claws and beep)
      while (endTime-startTime < 29000) 
      { 
        //Set the motor-speed to a random number between 20 and 400
        Motor.A.setSpeed(myRandom(100,400));
        Motor.C.setSpeed(myRandom(100,400));
 
        //If the NXT is facing an obstacle, the the motors are only allowed to turn backward
        if (sonicF.getDistance()<50)
        { 
          Motor.A.backward();
          Motor.C.backward();   
          Delay.msDelay(100);
        }
        //If the NXT's back is facing an obstacle, the the motors are only allowed to turn forward
        else if (sonicB.getDistance()<40) 
        {
          Motor.A.forward();
          Motor.C.forward();
          Delay.msDelay(100);   
        }
        //If there is no obstacle in the way, the directions are chosen randomly
        else
        {
          if (myRandom(0,1)==0) 
          {                   
            Motor.A.forward();
          } // end of if
          else
          {              
            Motor.A.backward();
          }
 
          if (myRandom(0,1)==0) 
          {                   
            Motor.C.forward();
          } // end of if
          else
          {              
            Motor.C.backward();
          }
        }
        //Perform the action for a duration of 100 to 500 milliseconds
        Delay.msDelay(myRandom(100,400));
 
        //reading the current time
        endTime = System.currentTimeMillis();
      } // end of while
 
      //Stopping, closing the claws and beeping
      BluetoothNXT_v5.SoftStop();
      Motor.A.stop();
      Motor.C.stop();
      Motor.B.setSpeed(100);
      Motor.B.backward();
      Thread.sleep(1000);
      Motor.B.stop();
      BluetoothNXT_v5.clawsOpen=false;
      Sound.twoBeeps();
    }
    catch(Exception err) {}
  }
 
  //Random number generator
  static int myRandom(int low, int high) 
  {
    high++;
    return (int) (Math.random() * (high - low) + low);
  }
}//EOF
Praktikaten: Andreas Mieke, Peter Por
Betreuer: Patrik Grausberg

Am 29.07.2013 fand die Abschlusspräsentation der Ferialpraktika 2013 statt.

Jedes Team bekam seinen eigenen Stand, sowie eine Pinnwand für das jeweilige Plakat. Wir konnten unseren NXT-Roboter vorführen und bekamen fast nur positives Feedback!
Anschließend ging es dann zum Sommerfest, wo uns ein überwältigendes Grillbuffet erwartete.

Unser Poster können Sie hier sehen.

 

Ein paar der Bilder von dem Event:

Hauptpost – Klick!

 

Changelog:

  • Das Programm sollte jetzt auf jedem Windows-Rechner funktionieren, ohne zusätzliche Programme (außer natürlich dem Java Runtime Environment) zu benötigen. Der Befehl zum Ausführen des Programms lautet: “java -jar NXTRFID_vx.x”.
  • Wenn Einstellungen (NXT-Name, Com-Port, usw.) geändert werden sollen, muss jetzt nicht mehr der Code modifiziert werden. Es liegen 2 Config-Files bei, aus denen die Inputs ausgelesen werden.
  • Minor Bugfixes
  • Wir stellen jetzt ein WinRAR-Verzeichnis mit den ausführbaren Dateien (StandAlone-Version) zur Verfügung: Download v4.4.2
     

    Die neuen Codes:

     

    Java PC-Programm:

    //Written by Peter Por
    //Last edited: 17.07.13
     
    package nxtrfid;
     
    import lejos.pc.comm.*;
    import java.io.*;
     
     
    public class NXTRFID {	
     
      public static void main(String[] args) throws IOException, InterruptedException 
      {
    	  String nxtName = "NXT";   //Name of the specific NXT brick; "NXT" is default
    	  int COMPort = 8;      //The COM-Port of the RFID Reader	
    	  String RFIDScanLocation = "RRFIDScan_v.2.0.1.exe";    //The Location of the ".exe" file for the RFID Reader
    	  String Music = "vlc/vlc.exe --play-and-exit --novideo Music.mp3";     //Commandline promt opening VLC and the sound file
    	  String InputLocation = "NXTRFID.conf";    //Location of the config file
    	  int keypressOld = 9999;   //the last read RFID tag's ID will be saved here
     
    	  //You may change the location of the conf file by sensing a command line argument
    	if(args.length!=0)
    	{
    		InputLocation = args[0];
    	}
     
    	//Read the config file
    	try 
    	{
    		BufferedReader in = new BufferedReader(new FileReader(InputLocation));
    		String zeile1 = in.readLine();
    		String zeile2 = in.readLine();
    		String zeile3 = in.readLine();
    		String zeile4 = in.readLine();
     
    		nxtName = zeile1;
    		COMPort = Integer.parseInt(zeile2);
    		RFIDScanLocation = zeile3;
    		Music = zeile4;
     
    		in.close();
    	} 
    	catch (IOException err) 
    	{
    		err.printStackTrace();
    	}
     
        //Necessary declarations for establishing the connection
        NXTInfo[] nxts;
        NXTConnector connect = new NXTConnector();
     
        nxts = connect.search(nxtName,null,NXTCommFactory.BLUETOOTH);    //Searches for nearby NXTs
     
        if(nxts.length == 0)
        { //The NXT was not in range
          System.out.print(nxtName + " nicht gefunden!");
        }
        else{
          if(!connect.connectTo(nxts[0].name,nxts[0].deviceAddress,NXTCommFactory.BLUETOOTH))
          { //Connection failed
            System.out.println("Verbindungsaufbau zu " + nxtName + " fehlgeschlagen!");
          }
          else
          { //now there is a connection
            System.out.println("Verbindung zu " + nxtName + " aufgebaut!");
            DataOutputStream dos = new DataOutputStream(connect.getOutputStream());
     
            while(true){
             try
             {
              Process p = Runtime.getRuntime().exec(RFIDScanLocation + " " + COMPort);   //This declaration starts the ".exe" file for the RFID Reader; The number following specifies the COM port
              p.waitFor();    //Waits until the ".exe" has finished
              dos.writeInt(p.exitValue());    //Writes the exitValue of the RFIDScan program to the NXT
              dos.flush();
     
              //Starts VLC and opens the sound file - 3 is the Code for "Dance"
              if(p.exitValue()==3 && p.exitValue() != keypressOld)
              {
            	  Thread.sleep(10);
            	  try
            	  {
            		 Runtime.getRuntime().exec(Music);
            	  }
            	  catch(Exception ex)
            	  {
      		        System.out.println("Error with playing sound.");
      		        ex.printStackTrace();
      		      }
              }
     
              if(p.exitValue()==-1)   // -1 is the code for "Terminate"
              {
            	  System.out.println("Das Programm wird nun beendet.");
            	  break;
              }
              if(p.exitValue()==-2)   // -2 is the Error-Code
              {
            	  System.out.println("Fehler beim Einlesen des RFID Tags.");
            	  break;
              }
     
              keypressOld=p.exitValue();
             }
             catch(Exception err)
             {
            	 System.out.println("Error.");
            	 break;
             }
            }// end of loop       
     
        	dos.close();    //Closes the DataOutputStream
            connect.close();    //Closes the Connection to the NXT
            System.out.println("Programm beendet.");
          }
         }
     
        }// end of main
       } // end of class Main

    C++ PC-Programm (RFID):

    // RFIDScan.cpp : Defines the entry point for the console application.
    // Written by Andreas Mieke
    // Date: 17.07.13
     
    #define VERSION "2.0.2"
    //#define DEBUG		//Uncomment this to see what is scanned from RFIDScan.conf and what is the TagID on the scanner
    #define MAX_TAGS (20)	//Defines the maximum number of RFID tags to be scanned
     
    #include "std_inc.h"
    #include "comm.h"
    #include "protocol.h"
    #include "std_readwrite.h"
     
    //General purpose buffer
    char buffer[1000];
    char code[17];
    int tagCounter = 0;
    int tagCounterMax = 0;
    char tagIDs[17][MAX_TAGS];
    int tagReturns[MAX_TAGS];
     
    //This function closes the reader and communication handle
    //If not connected the two variables are set to zero
    void CloseComm() {
        //If the reader handle is set, close the reader
        if(reader_handle) {
            RDR_CloseReader(reader_handle);
            reader_handle = NULL;
        }
     
        //If the COM handle is set, close the COM port
        if(comm_handle) {
            RDR_CloseComm(comm_handle);
            comm_handle = NULL;
        }
    }
     
    bool OpenComm() {
        char input_buffer[50], detect_buffer[256];
     
         //Close any possible open connection
        CloseComm();
     
        comm_handle = RDR_OpenComm(com_port, 1, NULL);
     
        if(comm_handle == 0) { //zero indicates error while opening the com port
            printf("\n\nError opening reader(com).\n");
     
            return false;
        }
     
        //After sucessfully opening the com port, try to open the reader
     
        //First detect the station ID of the reader
        RDR_DetectReader(comm_handle, detect_buffer);
     
        //Open the reader with the first detected station ID
        reader_handle = RDR_OpenReader(comm_handle, detect_buffer[0], 0);
     
        if(reader_handle == 0) { //zero indicates error while opening reader
            //Since the com port is allready open, close it on error contition
            CloseComm();
     
            printf("\n\nError opening reader.\nPress any key to continue...");
            getch();
     
            return false;
        }
     
        //Stop the maybe activated continous read (should only be done after opening the reader)
        //RDR_EmptyCommRcvBuffer is not needed because this is implicit done with RDR_AbortContinuousRead
        RDR_AbortContinuousRead(comm_handle);
        return true;
    }
     
    //This function expalains the standard read/write sequence for a standard MIFARE card [ASCII]
    //If the default key is not valid you have to change the line in the source code below
    void DoASCIIReadWrite() {
        //The first action is to select the card
        //The select command has no data
        RDR_SendCommandGetData(reader_handle, "select", "", buffer);
    	sprintf(code, "%s", buffer);
    	strcpy(buffer,"");
    }
     
    //Main programm entry point
    int main(int args, char* argv[]) {
    	char* filepath;
    	if(args < 2)
    	{
    		printf("[ERROR]\tPlease provide the right COM port <name_of_file.exe {portnumer} [path_to_config]>\n");
    		return -2;
    	}
    	printf("RFIDScan Version: %s; Coded by Andreas Mieke\n\n[JOB]\t\tLoading config file...\n\n",VERSION);
    	if(argv[2] != NULL)
    		filepath = argv[2];
    	else
    		filepath = "RFIDScan.conf";
    	FILE *configFile = fopen(filepath,"r");
    	if(configFile != NULL)
    	{
    		fgets(buffer, sizeof(buffer), configFile);
    		tagCounterMax = atoi(buffer);
    		if(tagCounterMax > MAX_TAGS)
    		{
    			printf("[ERROR]\tYour specification of tags has too much elements! Max: %d",MAX_TAGS);
    			return -3;
    		}
    		for(; tagCounter < tagCounterMax; tagCounter++)
    		{
    			fscanf(configFile,"%s%d", tagIDs[tagCounter], &tagReturns[tagCounter]);
    #ifdef DEBUG
    			printf("[DEBUG]\t%s : %d\n", tagIDs[tagCounter], tagReturns[tagCounter]);
    #endif
    		}
    		fclose(configFile);
    		printf("[SUCCESS]\tConfig file successfully loaded. Program started.\n\n");
    	}
    	else
    	{
    		printf("[FATAL ERROR]\tConfig file \"%s\" could not be opened!\n", filepath);
    		return -4;
    	}
    	sprintf(com_port,"COM%d",atoi(argv[1])); //Sets the content of argv[1] as COM port
     
    	do { //Continues until a valid ID was scanned.
    		if(OpenComm() == false) //Opens the connection to the RFID reader (comm.cpp)
    		{
    			printf("[FATAL ERROR]\tCould not connect to the RFID Reader!\n");
    			return -5;
    		}
     
    		do { //Tries as long to scan a Tag as it doesn't find one.
    			DoASCIIReadWrite(); // (std_readwrite.cpp)
    		} while ((strlen(code) == 0) || (strlen(code) == 1)); //Strlen of 0 or 1 indicates error
     
    #ifdef DEBUG
    		printf("[DEBUG] %s\n",code); //Prints the HEX-Code (TAGID) to the screen
    #endif
    		CloseComm(); //Closes connection to Reader (comm.cpp)
     
    		for(tagCounter = 0; tagCounter < tagCounterMax; tagCounter++)
    		{
    			if(strcmp(code,tagIDs[tagCounter]) == 0)
    			return tagReturns[tagCounter];
    		}
    		strcpy(code,"");
    	} while(true);
    }
    //EOF

    Java NXT-Programm:

    //Written by Peter Por
    //Last edited: 17.07.13     
     
    import java.io.IOException;
    import lejos.nxt.*;
    import lejos.nxt.comm.*;
    import java.io.*;
    import javax.bluetooth.*;
    import lejos.util.Delay;
    import lejos.nxt.UltrasonicSensor;
     
     
     
    public class BluetoothNXT_v4 {
     
      //globally accessable variables
      public static int keypress = 0, keypressOld = 9999;
      public static boolean mayDriveForward=true, mayDriveBackward = true, clawsOpen=false;
     
      public static void main(String [] args) throws Exception
      {
        String connected = "Connected";
        String waiting = "Waiting...";
        String closing = "Closing...";
     
        //Starting the Thread using the ultrasonic sensors
        Indicators ussf = new Indicators();
        ussf.setDaemon(true); 
        ussf.start();
     
        //Waiting for, and establishing, the bluetooth connection
        LCD.drawString(waiting,0,0);
        LCD.refresh();
        BTConnection btc = Bluetooth.waitForConnection();
        LCD.clear();
        LCD.drawString(connected,0,0);
        LCD.refresh();
        Sound.beepSequenceUp();
        DataInputStream dis = btc.openDataInputStream();
        DataOutputStream dos = btc.openDataOutputStream();
        ///////////////////////////////////////////////////////////////////////  
        mayDriveForward=true;
        mayDriveBackward=true;
     
     
        while(true)
        {//start loop
     
          try{//waiting for the order-ID from the PC program
            keypress=dis.readInt();
          }
          catch(IOException e)
          {
            LCD.drawString("Error:",0,0);
            LCD.drawString("Datastream Invlaid.",0,1);
            LCD.refresh();
            break;
          }
          Thread.sleep(100);
     
     
          //Forward
          if (keypressOld!=8 && keypress ==8 && mayDriveForward) 
          {
            Motor.A.setSpeed(1200);
            Motor.C.setSpeed(1200);
            Motor.A.forward();
            Motor.C.forward();
            mayDriveBackward=true;
          } // end of if
          else
          //Backward
          if (keypressOld!=2 && keypress ==2 && mayDriveBackward) 
          {
            Motor.A.setSpeed(1200);
            Motor.C.setSpeed(1200);
            Motor.A.backward();
            Motor.C.backward();
            mayDriveForward=true;
          } // end of if
          else
          //Turn right
          if (keypressOld!=6 && keypress ==6) 
          {
            Motor.A.setSpeed(150);
            Motor.C.setSpeed(150);
            Motor.A.forward();
            Motor.C.backward();
            mayDriveForward=true;
            mayDriveBackward=true;
          } // end of if
          else
          //Turn left
          if (keypressOld!=4 && keypress ==4) 
          {         
            Motor.A.setSpeed(150);
            Motor.C.setSpeed(150);
            Motor.A.backward();
            Motor.C.forward();
            mayDriveForward=true;
            mayDriveBackward=true;
          } // end of if
          else
          //Stop
          if (keypress ==5) 
          {
            if (keypressOld==8||keypressOld==2)
            SoftStop();
            Motor.A.stop();
            Motor.C.stop();
          } // end of if
          else
          //Close Claws
          if (keypressOld!=keypress && clawsOpen && keypress==9) 
          {
            if (keypressOld==8||keypressOld==2)
            {SoftStop();}
            Motor.A.stop();
            Motor.C.stop();
            Motor.B.setSpeed(100);
            Motor.B.backward();
            Thread.sleep(1000);
            Motor.B.stop();
            clawsOpen=false;
          } // end of if
          else
          //Dance like nobody's watching
          if (keypressOld!=keypress && keypress==3)
          {
            SoftStop();
            Motor.A.stop();
            Motor.C.stop();
            if (!clawsOpen) 
            {                               
              Motor.B.setSpeed(100);
              Motor.B.forward();
              Thread.sleep(1000);
              Motor.B.stop();
              clawsOpen=true;
            }
            Dance.startDance();
          } // end of if  
          //Open claws
          else
          if (true) 
          {
            if (keypressOld!=keypress && !clawsOpen && keypress==7) 
            {
              if (keypressOld==8||keypressOld==2)
              SoftStop();
              Motor.A.stop();
              Motor.C.stop();
              Motor.B.setSpeed(100);
              Motor.B.forward();
              Thread.sleep(1000);
              Motor.B.stop();
              clawsOpen=true;
            } // end of if   
            mayDriveForward=true;
          }      
          keypressOld=keypress;
        }//end loop
     
     
        ///Terminating the program
     
        //closes claws in case they were open
        if (clawsOpen) 
        {                               
          SoftStop();
          Motor.A.stop();
          Motor.C.stop();
          Motor.B.setSpeed(100);
          Motor.B.backward();
          Thread.sleep(1000);
          Motor.B.stop();
          clawsOpen=false;
        }
     
        //closes the bluetooth connection
        dis.close();
        dos.close();
        Thread.sleep(90); // wait for data to drain
        LCD.clear();
        LCD.drawString(closing,0,0);
        LCD.refresh();
        btc.close();
        LCD.clear();
      }
     
     
      //Due to a hardware problem regarding the NXT's motors, this method was necessary in order to stop both motors at the same time
      static void SoftStop()
      {
        int i = 1200;
        while(i>0)
        {
          Motor.A.setSpeed(i);
          Motor.C.setSpeed(i);
          Delay.msDelay(10);
          i=i-100;
        }
      }
    }
     
     
    //Ultrasonic-Thread
    class Indicators extends Thread 
    {
      //Declaring the sensor-ports
      UltrasonicSensor sonicF = new UltrasonicSensor(SensorPort.S1);
      UltrasonicSensor sonicB = new UltrasonicSensor(SensorPort.S2);
      int safetyDistanceF=30,safetyDistanceB=27;
     
      //Workerthread
      public void run() 
      {
        while (true) 
        {
          //If the claws are open, the safety-distance is smaller
          if (BluetoothNXT_v4.clawsOpen)
          safetyDistanceF=23;
          else
          safetyDistanceF=30;
     
     
          try
          {
            if (sonicF.getDistance()<safetyDistanceF && BluetoothNXT_v4.keypress==8) 
            {//The NXT is currently driving forwards and faces an obstacle
              Motor.B.stop();
              BluetoothNXT_v4.SoftStop();
              Motor.A.stop();
              Motor.C.stop();       
              BluetoothNXT_v4.mayDriveForward = false;                  
            }
          }      
          catch(Exception err)
          { }
     
     
          try
          {
            if (sonicB.getDistance()<safetyDistanceB && BluetoothNXT_v4.keypress==2) 
            {//The NXT is currently driving backwards and faces an obstacle
              Motor.B.stop();
              BluetoothNXT_v4.SoftStop();
              Motor.A.stop();
              Motor.C.stop();     
              BluetoothNXT_v4.mayDriveBackward = false;                  
            }
          }      
          catch(Exception err)
          { }     
        }     
      }
    }
     
     
    class Dance {
     
      public static void startDance()
      {
        try{
          //Declaring the sensor-ports
          UltrasonicSensor sonicF = new UltrasonicSensor(SensorPort.S1);
          UltrasonicSensor sonicB = new UltrasonicSensor(SensorPort.S2);
          //Getting the current time
          long startTime = System.currentTimeMillis();
          Thread.sleep(50);
          long endTime = System.currentTimeMillis();
     
          //The program may only run for 29seconds (30seconds is the duration of the music we chose, the last second is used to close the claws and beep)
          while (endTime-startTime < 29500)
          { 
            //Set the motor-speed to a random number between 20 and 400
            Motor.A.setSpeed(myRandom(100,400));
            Motor.C.setSpeed(myRandom(100,400));
     
            //If the NXT is facing an obstacle, the the motors are only allowed to turn backward
            if (sonicF.getDistance()<50)
            { 
              Motor.A.backward();
              Motor.C.backward();   
              Delay.msDelay(100);
            }
            //If the NXT's back is facing an obstacle, the the motors are only allowed to turn forward
            else if (sonicB.getDistance()<40) 
            {
              Motor.A.forward();
              Motor.C.forward();
              Delay.msDelay(100);   
            }
            //If there is no obstacle in the way, the directions are chosen randomly
            else
            {
              if (myRandom(0,1)==0) 
              {                   
                Motor.A.forward();
              } // end of if
              else
              {              
                Motor.A.backward();
              }
     
              if (myRandom(0,1)==0) 
              {                   
                Motor.C.forward();
              } // end of if
              else
              {              
                Motor.C.backward();
              }
            }
            //Perform the action for a duration of 100 to 500 milliseconds
            Delay.msDelay(myRandom(100,400));
     
            //reading the current time
            endTime = System.currentTimeMillis();
          } // end of while
     
          //Stopping, closing the claws and beeping
          BluetoothNXT_v4.SoftStop();
          Motor.A.stop();
          Motor.C.stop();
          Motor.B.setSpeed(100);
          Motor.B.backward();
          Thread.sleep(1000);
          Motor.B.stop();
          BluetoothNXT_v4.clawsOpen=false;
          Sound.twoBeeps();
        }
        catch(Exception err) {}
      }
     
      //Random number generator
      static int myRandom(int low, int high) 
      {
        high++;
        return (int) (Math.random() * (high - low) + low);
      }
    }//End of file
Praktikaten: Andreas Mieke, Peter Por
Betreuer: Patrik Grausberg

Zieldefinition

Der Mindstorms NXT Roboter soll, abhängig davon, welcher RFID Tag an den Scanner gehalten wird, eine andere Operation ausführen. Ist dieser Schritt erst einmal geschafft, darf weiters Kreativität einfließen.
Die Arbeit soll übersichtlich dokumentiert werden.
 

1. Update!

2. Update!

 

Bilder

Videos



 

Dokumentation

Das erste Problem bestand darin, dass wir den NXT (und die Bluetooth Schnittstelle) per Java programmieren wollten, der RFID Sensor allerdings nur über C-Librarys verfügt.
Um dieses Hindernis zu umgehen, hatten wir mehrere Lösungsansätze:

  • Die fertige Java Bluetooth Fernsteuerung nochmals in C schreiben. Hierfür fehlten uns allerdings die Bluetooth Bibliotheken.
  • Die C-Librarys des RFID Sensors mit Hilfe eines Java/C-Wrappers in Java implementieren. Hierfür standen uns das JNI (Java Native Interface) oder JNA (Java Native Access) zur Verfügung. Der Vorteil von JNA ist, dass wir hiermit, bereits existierende DLLs einbinden können, und diese nicht, wie bei JNI, selbst erstellen müssen.
  • Das getrennte Programmieren des Readers in C, und des NXTs in Java.

Wir haben uns letzten Endes für die dritte Option entschieden.
Auch bei dieser Herangehensweise konnten wir wieder zwischen zwei Verfahren wählen:
Das C-Programm für den RFID-Scanner könnte das Java-Programm aufrufen, oder umgekehrt.
Problematisch ist bei ersterem Ansatz, dass der Bluetooth-Kommunikationskanal immer geöffnet bleiben muss, dies aber schwer umzusetzen ist, wenn das Java-Programm nach jedem Befehl wieder beendet wird.

Daher haben wir uns dazu entschlossen, die Programme nach folgendem Blockschaltbild zu entwickeln:

Flowchart PC

Den entsprechenden Java-Code (wird am PC ausgeführt) können Sie hier sehen:
//Written by Peter Por and Andreas Mieke
//Last edited: 11.07.13
 
import lejos.pc.comm.*;
import java.io.*;
import java.awt.*;
 
public class NXTRFID {	
 
  public static void main(String[] args) throws IOException, InterruptedException {
	String nxtName = "NXT";    //Name of the specific NXT brick; "NXT" is default
	String RFIDScanLocation = "C:\\Users\\Peter\\Desktop\\RFIDScan_v1.2";    //The Location of the ".exe" file for the RFID Reader
	int COMPort = 8;    //The COM-Port of the RFID Reader
 
    //Necessary declarations for establishing the connection
    NXTInfo[] nxts;
    NXTConnector connect = new NXTConnector();
 
    nxts = connect.search(nxtName,null,NXTCommFactory.BLUETOOTH);    //Searches for nearby NXTs
 
    if(nxts.length == 0)
    { //The NXT was not in range
      System.out.print(nxtName + " nicht gefunden!");
    }
    else{
      if(!connect.connectTo(nxts[0].name,nxts[0].deviceAddress,NXTCommFactory.BLUETOOTH))
      { //Connection failed
        System.out.print("Verbindungsaufbau zu " + nxtName + " fehlgeschlagen!");
      }
      else
      { //now there is a connection
        System.out.println("Verbindung zu " + nxtName + " aufgebaut!");
        DataOutputStream dos = new DataOutputStream(connect.getOutputStream());
 
        while(true){
         try
         {
          Process p = Runtime.getRuntime().exec(RFIDScanLocation + " " + COMPort);   //This declaration starts the ".exe" file for the RFID Reader; The number following specifies the COM port
          p.waitFor();    //Waits until the ".exe" has finished
          dos.writeInt(p.exitValue());    //Writes the exitValue of the RFIDScan program to the NXT
          dos.flush();
 
          if(p.exitValue()==3)  //Start playing music if the NXT is supposed to dance
          {
          	Desktop d = Desktop.getDesktop();
              File f = new File("C:/Users/Peter/Desktop/Musik.mp3");
              d.open(f); 
          }
 
          if(p.exitValue()==-1)   // -1 is the Error Code
          {
        	  System.out.println("Ein nicht bekannter RFID Tag wurde eingelesen.");
        	  break;
          }
         }
         catch(Exception err)
         {
        	 System.out.println("Fehler beim Einlesen des RFID Tags.");
          break;
         }
        }// end of loop       
 
    	dos.close();    //Closes the DataOutputStream
        connect.close();    //Closes the Connection to the NXT
        System.out.println("Programm beendet.");
      }
     }
 
    }// end of main 
   } // end of class Main
Der C-Code für den RFID Reader:
// RFIDScan.cpp : Defines the entry point for the console application.
// Written by Andreas Mieke
// Date: 10.07.13
 
#define VERSION "1.2"
 
#include "std_inc.h"
#include "comm.h"
#include "protocol.h"
#include "std_readwrite.h"
 
//General purpose buffer
char buffer[1000];
char code[17];
void *comm_handle = NULL;
void *reader_handle = NULL;
 
//This function closes the reader and communication handle
//If not connected the two variables are set to zero
void CloseComm() {
    //If the reader handle is set, close the reader
    if(reader_handle) {
        RDR_CloseReader(reader_handle);
        reader_handle = NULL;
    }
 
    //If the COM handle is set, close the COM port
    if(comm_handle) {
        RDR_CloseComm(comm_handle);
        comm_handle = NULL;
    }
}
 
bool OpenComm() {
    char input_buffer[50], detect_buffer[256];
 
     //Close any possible open connection
    CloseComm();
 
    comm_handle = RDR_OpenComm(com_port, 1, NULL);
 
    if(comm_handle == 0) { //zero indicates error while opening the com port
        printf("\n\nError opening reader(com).\n");
 
        return false;
    }
 
    //After sucessfully opening the com port, try to open the reader
 
    //First detect the station ID of the reader
    RDR_DetectReader(comm_handle, detect_buffer);
 
    //Open the reader with the first detected station ID
    reader_handle = RDR_OpenReader(comm_handle, detect_buffer[0], 0);
 
    if(reader_handle == 0) { //zero indicates error while opening reader
        //Since the com port is allready open, close it on error contition
        CloseComm();
 
        printf("\n\nError opening reader.\nPress any key to continue...");
        getch();
 
        return false;
    }
 
    //Stop the maybe activated continous read (should only be done after opening the reader)
    //RDR_EmptyCommRcvBuffer is not needed because this is implicit done with RDR_AbortContinuousRead
    RDR_AbortContinuousRead(comm_handle);
    return true;
}
 
//This function expalains the standard read/write sequence for a standard MIFARE card [ASCII]
//If the default key is not valid you have to change the line in the source code below
void DoASCIIReadWrite() {
    //The first action is to select the card
    //The select command has no data
    RDR_SendCommandGetData(reader_handle, "select", "", buffer);
	sprintf(code, "%s", buffer);
	strcpy(buffer,"");
}
 
//Main programm entry point
int main(int args, char* argv[]) {
	printf("RFIDScan Version: %s; Coded by Andreas Mieke\n\tStarting up...\n\n",VERSION);
	if(args < 2)
	{
		printf("Please provide the right COM port ");
		return -1;
	}
	sprintf(com_port,"COM%d",atoi(argv[1])); //Sets the content of argv[1] as COM port
 
	do { //Continues until a valid ID was scanned.
		if(OpenComm() == false) //Opens the connection to the RFID reader (comm.cpp)
			return -1;
 
		do { //Tries as long to scan a Tag as it doesn't find one.
			DoASCIIReadWrite(); // (std_readwrite.cpp)
		} while ((strlen(code) == 0) || (strlen(code) == 1)); //Strlen of 0 or 1 indicates error
 
		printf("%s\n",code); //Prints the HEX-Code (TAGID) to the screen
		CloseComm(); //Closes connection to Reader (comm.cpp)
 
		if(strcmp(code,"E00401500A95A9FF") == 0)		//Forward code
			return 8;
		else if(strcmp(code,"E00401500A957E17") == 0)	//Backward code
			return 2;
		else if(strcmp(code,"E00401500A95AA39") == 0)	//Turn left code
			return 4;
		else if(strcmp(code,"E00401500A957E55") == 0)	//Turn right code
			return 6;
		else if(strcmp(code,"E00401500A95AA79") == 0)	//Stop code
			return 5;
		else if(strcmp(code,"E00401500A957DDB") == 0)	//Claws open code
			return 7;
		else if(strcmp(code,"E00401500A9572E4") == 0)	//Claws close code
			return 9;
		else if(strcmp(code,"E00401500A954A94") == 0)	//Dance code
			return 3;
		else if(strcmp(code,"E00401500A957E95") == 0)	//Terminate code
			return -1;
		else
			strcpy(code,"");
	} while(true);
}
//EOF
Das Grundgerüst des Programms, das am NXT ausgeführt wird, ist ebenfalls sehr simpel:

Bevor wir Ihnen an dieser Stelle den NXT-Code präsentieren, wollen wir Ihnen noch etwas über die Bonus-Features erzählen, die wir unserem NXT gegeben haben:
Wir haben den Roboter vorne und hinten mit je einem Ultraschall-Sensor ausgestattet. Wenn der NXT nun zu nahe an ein Objekt fährt, bleibt er stehen und man kann den jeweiligen Befehl (vorwärts/rückwärts) erst wieder benutzen, wenn der NXT “freie Sicht” hat. Alle anderen Fahrtrichtungen sind jedoch weiterhin freigegeben.
Des Weiteren haben wir, zusätzlich zu den nun folgenden Funktionalitäten, auch einen Tanz-Befehl einprogrammiert. Außerdem haben wir ihn mit Klauen, die er öffnen und schließen kann, ausgestattet.

Der Roboter kennt folgende Befehle:

  • Vorwärts
  • Rückwärts
  • Links drehen
  • Rechts drehen
  • Stopp
  • Klauen öffnen
  • Klauen schließen
  • Tanzen
Nun können Sie sich hier den betreffenden Java-Code (wird am NXT ausgeführt) zu Gemüte führen:
//Written by Peter Por
//Last edited: 11.07.13     
 
import java.io.IOException;
import lejos.nxt.*;
import lejos.nxt.comm.*;
import java.io.*;
import javax.bluetooth.*;
import lejos.util.Delay;
import lejos.nxt.UltrasonicSensor;
 
 
 
public class BluetoothNXT_v4 {
 
  //globally accessable variables
  public static int keypress = 0, keypressOld = 9999;
  public static boolean mayDriveForward=true, mayDriveBackward = true, clawsOpen=false;
 
  public static void main(String [] args) throws Exception
  {
    String connected = "Connected";
    String waiting = "Waiting...";
    String closing = "Closing...";
 
    //Starting the Thread using the ultrasonic sensors
    Indicators ussf = new Indicators();
    ussf.setDaemon(true); 
    ussf.start();
 
    //Waiting for, and establishing, the bluetooth connection
    LCD.drawString(waiting,0,0);
    LCD.refresh();
    BTConnection btc = Bluetooth.waitForConnection();
    LCD.clear();
    LCD.drawString(connected,0,0);
    LCD.refresh();
    Sound.beepSequenceUp();
    DataInputStream dis = btc.openDataInputStream();
    DataOutputStream dos = btc.openDataOutputStream();
    ///////////////////////////////////////////////////////////////////////  
    mayDriveForward=true;
    mayDriveBackward=true;
 
 
    while(true)
    {//start loop
 
      try{//waiting for the order-ID from the PC program
        keypress=dis.readInt();
      }
      catch(IOException e)
      {
        LCD.drawString("Error:",0,0);
        LCD.drawString("Datastream Invlaid.",0,1);
        LCD.refresh();
        break;
      }
      Thread.sleep(100);
 
 
      //Forward
      if (keypressOld!=8 && keypress ==8 && mayDriveForward) 
      {
        Motor.A.setSpeed(1200);
        Motor.C.setSpeed(1200);
        Motor.A.forward();
        Motor.C.forward();
        mayDriveBackward=true;
      } // end of if
      else
      //Backward
      if (keypressOld!=2 && keypress ==2 && mayDriveBackward) 
      {
        Motor.A.setSpeed(1200);
        Motor.C.setSpeed(1200);
        Motor.A.backward();
        Motor.C.backward();
        mayDriveForward=true;
      } // end of if
      else
      //Turn right
      if (keypressOld!=6 && keypress ==6) 
      {
        Motor.A.setSpeed(150);
        Motor.C.setSpeed(150);
        Motor.A.forward();
        Motor.C.backward();
        mayDriveForward=true;
        mayDriveBackward=true;
      } // end of if
      else
      //Turn left
      if (keypressOld!=4 && keypress ==4) 
      {         
        Motor.A.setSpeed(150);
        Motor.C.setSpeed(150);
        Motor.A.backward();
        Motor.C.forward();
        mayDriveForward=true;
        mayDriveBackward=true;
      } // end of if
      else
      //Stop
      if (keypress ==5) 
      {
        if (keypressOld==8||keypressOld==2)
        SoftStop();
        Motor.A.stop();
        Motor.C.stop();
      } // end of if
      else
      //Close Claws
      if (keypressOld!=keypress && clawsOpen && keypress==9) 
      {
        if (keypressOld==8||keypressOld==2)
        {SoftStop();}
        Motor.A.stop();
        Motor.C.stop();
        Motor.B.setSpeed(100);
        Motor.B.backward();
        Thread.sleep(1000);
        Motor.B.stop();
        clawsOpen=false;
      } // end of if
      else
      //Dance like nobody's watching
      if (keypressOld!=3 && keypress==3) 
      {
        SoftStop();
        Motor.A.stop();
        Motor.C.stop();
        if (!clawsOpen) 
        {                               
          Motor.B.setSpeed(100);
          Motor.B.forward();
          Thread.sleep(1000);
          Motor.B.stop();
          clawsOpen=true;
        }
        Dance.startDance();
      } // end of if  
      //Open claws
      else
      if (true) 
      {
        if (keypressOld!=keypress && !clawsOpen && keypress==7) 
        {
          if (keypressOld==8||keypressOld==2)
          SoftStop();
          Motor.A.stop();
          Motor.C.stop();
          Motor.B.setSpeed(100);
          Motor.B.forward();
          Thread.sleep(1000);
          Motor.B.stop();
          clawsOpen=true;
        } // end of if   
        mayDriveForward=true;
      }      
      keypressOld=keypress;
    }//end loop
 
 
    ///Terminating the program
 
    //closes claws in case they were open
    if (clawsOpen) 
    {                               
      SoftStop();
      Motor.A.stop();
      Motor.C.stop();
      Motor.B.setSpeed(100);
      Motor.B.backward();
      Thread.sleep(1000);
      Motor.B.stop();
      clawsOpen=false;
    }
 
    //closes the bluetooth connection
    dis.close();
    dos.close();
    Thread.sleep(90); // wait for data to drain
    LCD.clear();
    LCD.drawString(closing,0,0);
    LCD.refresh();
    btc.close();
    LCD.clear();
  }
 
 
  //Due to a hardware problem regarding the NXT's motors, this method was necessary in order to stop both motors at the same time
  static void SoftStop()
  {
    int i = 1200;
    while(i>0)
    {
      Motor.A.setSpeed(i);
      Motor.C.setSpeed(i);
      Delay.msDelay(10);
      i=i-100;
    }
  }
}
 
 
//Ultrasonic-Thread
class Indicators extends Thread 
{
  //Declaring the sensor-ports
  UltrasonicSensor sonicF = new UltrasonicSensor(SensorPort.S1);
  UltrasonicSensor sonicB = new UltrasonicSensor(SensorPort.S2);
  int safetyDistanceF=30,safetyDistanceB=27;
 
  //Workerthread
  public void run() 
  {
    while (true) 
    {
      //If the claws are open, the safety-distance is smaller
      if (BluetoothNXT_v4.clawsOpen)
      safetyDistanceF=23;
      else
      safetyDistanceF=30;
 
 
      try
      {
        if (sonicF.getDistance()<safetyDistanceF && BluetoothNXT_v4.keypress==8) 
        {//The NXT is currently driving forwards and faces an obstacle
          Motor.B.stop();
          BluetoothNXT_v4.SoftStop();
          Motor.A.stop();
          Motor.C.stop();       
          BluetoothNXT_v4.mayDriveForward = false;                  
        }
      }      
      catch(Exception err)
      { }
 
 
      try
      {
        if (sonicB.getDistance()<safetyDistanceB && BluetoothNXT_v4.keypress==2) 
        {//The NXT is currently driving backwards and faces an obstacle
          Motor.B.stop();
          BluetoothNXT_v4.SoftStop();
          Motor.A.stop();
          Motor.C.stop();     
          BluetoothNXT_v4.mayDriveBackward = false;                  
        }
      }      
      catch(Exception err)
      { }     
    }     
  }
}
 
 
class Dance {
 
  public static void startDance()
  {
    try{
      //Declaring the sensor-ports
      UltrasonicSensor sonicF = new UltrasonicSensor(SensorPort.S1);
      UltrasonicSensor sonicB = new UltrasonicSensor(SensorPort.S2);
      //Getting the current time
      long startTime = System.currentTimeMillis(), endTime = System.currentTimeMillis();
 
      //The program may only run for 29seconds (30seconds is the duration of the music we chose, the last second is used to close the claws and beep)
      while (endTime-startTime < 29000) 
      { 
        //Set the motor-speed to a random number between 20 and 400
        Motor.A.setSpeed(myRandom(100,400));
        Motor.C.setSpeed(myRandom(100,400));
 
        //If the NXT is facing an obstacle, the the motors are only allowed to turn backward
        if (sonicF.getDistance()<50)
        { 
          Motor.A.backward();
          Motor.C.backward();   
          Delay.msDelay(100);
        }
        //If the NXT's back is facing an obstacle, the the motors are only allowed to turn forward
        else if (sonicB.getDistance()<40) 
        {
          Motor.A.forward();
          Motor.C.forward();
          Delay.msDelay(100);   
        }
        //If there is no obstacle in the way, the directions are chosen randomly
        else
        {
          if (myRandom(0,1)==0) 
          {                   
            Motor.A.forward();
          } // end of if
          else
          {              
            Motor.A.backward();
          }
 
          if (myRandom(0,1)==0) 
          {                   
            Motor.C.forward();
          } // end of if
          else
          {              
            Motor.C.backward();
          }
        }
        //Perform the action for a duration of 100 to 500 milliseconds
        Delay.msDelay(myRandom(100,400));
 
        //reading the current time
        endTime = System.currentTimeMillis();
      } // end of while
 
      //Stopping, closing the claws and beeping
      BluetoothNXT_v4.SoftStop();
      Motor.A.stop();
      Motor.C.stop();
      Motor.B.setSpeed(100);
      Motor.B.backward();
      Thread.sleep(1000);
      Motor.B.stop();
      BluetoothNXT_v4.clawsOpen=false;
      Sound.twoBeeps();
    }
    catch(Exception err) {}
  }
 
  //Random number generator
  static int myRandom(int low, int high) 
  {
    high++;
    return (int) (Math.random() * (high - low) + low);
  }
}//End of file
Praktikaten: Andreas Mieke, Peter Por
Betreuer: Patrik Grausberg

Das Ziel der Aufgabenstellung war, dass der NXT Roboter mittels KINECT (XBox360) gesteuert wird.

Mit Hilfe von C# und eventuell auch Java sollen die Bewegungen kontrolliert und mittels Bluetooth sollen einzelnen Befehle an den NXT Baustein des Roboters übertragen werden.

Einer der ersten Schritte war es, den Roboter aus dem Standrad-Kit zusammen zu bauen und richtig zu verkabeln. Unsere Wahl fiel auf den Fahrzeug-Roboter. Bei deiner Taufe bekam er den Namen Kico (Kinect Controlled).

Der Lego NXT Mindstorms Roboter besteht aus:

  • einem programmierbaren NXT-Stein
  • 3 Servomotoren mit Rotationssensoren
  • dem Ultraschallsensor
  • dem Drucksensor

Um uns mit dem Roboter vertraut zu machen, erstellten wir zuerst einige kleine Programme mit der mitgelieferten Software von LEGO MINDSTORMS.

Um den Roboter richtig zu Programmieren musste die benötigte Software erst auf den Arbeitsrechnern installiert werden:

  • Microsoft Visual C# Express 2010
  • Kinect SDK
  • DirectXàneueste Version
  • Developer Toolkit Kinect for Windows
  • Java Editor mit dem lejos Plugin (wurde später nicht mehr benötigt)
  • Mindsqualls (ersetzt Java)

Die Grundbewegungen für die einzelnen Aktionen die der Roboter ausführen soll, wurden festgelegt:

  • vorwärts à den rechten Arm abgewinkelt nach vorne bewegen
  • rückwärts à den linken Arm abgewinkelt nach hinten bewegen(ACHTUNG: negativer Wert!)
  • rechts drehen à rechten Arm zur Seite drehen
  • links drehen à linken Arm zur Seite drehen
  • klatschen à Hände falten/klatschen

Um eine Anhaltspunkt zu haben wurde das Skeleton Basics WPF Package installiert. Dies war der Grundstock unserer weiteren Programmierung.

Der erste Schritt, den Code zu vervollständigen, war mittels Timern die Werte der einzelnen Joints(also Punkte die die KINECT erkennt) auf den Jeweiligen Achsen auszugeben. Anfangs machte dies einige Probleme da zuerst der Code des vorgefertigten Files verstanden werden musste.

Soweit, so gut. Als Nächstes musste eine Kalibrierung programmiert werden, die, egal wo sie die Person im Koordinatensystem befindet die Durchschnittswerte der einzelnen Joints in Arrays speichert. Diese Werte werden für alle anderen Berechnungen als Standardwert herangezogen. Hierbei war darauf zu achten, dass sich das Koordinatensystem der KINECT auf allen Achsen(x, y und z) von -2 bis 2 erstreckt.

Mit Hilfe von Differenzen wurden als nächstes die Abstände zwischen den verschiedenen benötigten Joints berechnet.

Da das Arbeiten mit Differenzen aber einem Problem mit sich gebracht hat, fiel die Entscheidung schlussendlich darauf, die Differenzen in Vektoren umzuwandeln und mit den Beträgen der Vektoren zu rechnen.

Für die Analyse, ob eine gewisse Bewegung getätigt wurde, mussten die Standradbeträge der Vektoren aus der Kalibrierung mit den aktuellen Vektoren die aus den Joints immer wieder berechnet werden verglichen werden. Die richtigen Verhältnisse wurden durch ein experimentelles Verfahren(ständige Ausgabe der werte) ermittelt. Bei dem richtigen Verhältnis (also der richtigen Bewegung) wird via Bluetooth ein Signal an den NXT Roboter gesendet.

Die Bluetooth Verbindung über C# machte allerdings einige Zicken. Ständig wurde der Fehler „Exception 16 at 71(81)“ und ein Beep-Ton vom NXT Baustein ausgegeben. Aus diesem Grund stellten wir das Programm auf die sehr nützliche Mindsqualls Bibliothek um, die extra für die Kommunikation von C# zum programmierbaren NXT Stein  entwickelt wurde. Somit fällt auch der Teil weg der mit Java hätte programmiert werden sollen. Der Port über den die Connection aufgebaut ist, ist je nach Computer verschieden. Dieser muss im Programm(region Variablen) jeweils ausgebessert werden.

Das Signal wird für eine Bewegung ständig gesendet. Die Bewegung des Roboters dauert dabei aber nur 1 Sekunde. Somit entsteht der Eindruck einer flüssigen Bewegung.

Um die Benutzerfreundlichkeit zu erhöhen, wurden noch verschiedene Buttons zum Connecten oder zum neu Kalibrieren in das Projekt eingebaut. Um das Projekt auf jedem PC lauffähig zu machen, wurde ein Textfeld eingebaut, mit dem der COM Port individuell eingelesen werden kann.

Das Projekt wurde zusätzlich noch als ausführbares Programm veröffentlicht.

Das veröffentlichte Projekt und der Projektordner befinden sich mit folgenden Namen jeweils unter Downloads:

1 Aufgabe:

Lego Mindstorms NXT Roboter

Lego Mindstorms NXT Roboter

Die Aufgabe war es, die Steuerbefehle der Wii Fernbedienung an den Roboter weiterzuleiten und die Befehle vom Roboter richtig ausführen zu lassen. Der Roboter soll auch ans Ziel kommen, wenn keine Verbindung vorhanden ist.

Wir haben uns vorgestellt, dass wir die Signale der Wii Remote, die wir über Bluetooth empfangen, am PC verarbeiten und die Befehle ebenfalls via Bluetooth an den NXT Roboter zu senden.

Damit sich der Roboter aber auch bewegen kann, wenn keine Bluetoothverbindung besteht, verfügt er über ein Programm, das per Hand gestartet werden kann. Um die Wegfindung für den Roboter überhaupt möglich zu machen, haben wir einige der Lego NXT Sensoren verwendet.

Read the rest of this entry »