Программирование LEGO NXT роботов на языке NXC - Дополнительные возможности — различия между версиями

Материал из roboforum.ru Wiki
Перейти к: навигация, поиск
(Дисплей)
(Файловая система)
Строка 101: Строка 101:
 
our simple case. It creates our file by CreateFile("Danny.txt", 512, fileHandle), specifying name,
 
our simple case. It creates our file by CreateFile("Danny.txt", 512, fileHandle), specifying name,
 
size and a handle to the file, where NXT firmware will write a number for its own uses.
 
size and a handle to the file, where NXT firmware will write a number for its own uses.
 +
 
Then it builds strings and write to file with carriage return with WriteLnString(fileHandle,string,
 
Then it builds strings and write to file with carriage return with WriteLnString(fileHandle,string,
 
bytesWritten), where all the parameters must be variables. Finally, the file is closed and renamed.
 
bytesWritten), where all the parameters must be variables. Finally, the file is closed and renamed.
Строка 106: Строка 107:
 
if you want to read from it, you must close it and open it with OpenFileRead(); to delete/rename it, you
 
if you want to read from it, you must close it and open it with OpenFileRead(); to delete/rename it, you
 
must close it.
 
must close it.
#define OK LDR_SUCCESS
+
 
task main(){
+
#define OK LDR_SUCCESS
byte fileHandle;
+
short fileSize;
+
task main(){
short bytesWritten;
+
  byte fileHandle;
string read;
+
  short fileSize;
string write;
+
  short bytesWritten;
DeleteFile("Danny.txt");
+
  string read;
DeleteFile("DannySays.txt");
+
  string write;
CreateFile("Danny.txt", 512, fileHandle);
+
  DeleteFile("Danny.txt");
for(int i=2; i<=10; i++ ){
+
  DeleteFile("DannySays.txt");
write = "NXT is cool ";
+
  CreateFile("Danny.txt", 512, fileHandle);
string tmp = NumToStr(i);
+
  for(int i=2; i<=10; i++ ){
write = StrCat(write,tmp," times!");
+
    write = "NXT is cool ";
WriteLnString(fileHandle,write, bytesWritten);
+
    string tmp = NumToStr(i);
}
+
    write = StrCat(write,tmp," times!");
CloseFile(fileHandle);
+
    WriteLnString(fileHandle,write, bytesWritten);
RenameFile("Danny.txt","DannySays.txt");
+
  }
}
+
  CloseFile(fileHandle);
 +
  RenameFile("Danny.txt","DannySays.txt");
 +
}
 +
 
 
To see the result, go to BricxCCToolsNXT Explorer, upload DannySays.txt to pc and take a look.
 
To see the result, go to BricxCCToolsNXT Explorer, upload DannySays.txt to pc and take a look.
 
Ready for the next example! We will create a table with ASCII characters.
 
Ready for the next example! We will create a table with ASCII characters.
task main(){
+
 
byte handle;
+
task main(){
if (CreateFile("ASCII.txt", 2048, handle) == NO_ERR) {
+
  byte handle;
for (int i=0; i < 256; i++) {
+
  if (CreateFile("ASCII.txt", 2048, handle) == NO_ERR) {
string s = NumToStr(i);
+
    for (int i=0; i < 256; i++) {
int slen = StrLen(s);
+
      string s = NumToStr(i);
WriteBytes(handle, s, slen);
+
      int slen = StrLen(s);
WriteLn(handle, i);
+
      WriteBytes(handle, s, slen);
}
+
      WriteLn(handle, i);
CloseFile(handle);
+
    }
}
+
    CloseFile(handle);
}
+
  }
 +
}
 +
 
 
Really simple, this program creates the file and if no error occurred, it writes a number from 0 to 255 (converting
 
Really simple, this program creates the file and if no error occurred, it writes a number from 0 to 255 (converting
 
it to string before) with WriteBytes(handle, s, slen), that is another way to write strings without
 
it to string before) with WriteBytes(handle, s, slen), that is another way to write strings without
Строка 145: Строка 151:
 
explainable: the number written as string is shown in a human-readable way, while the number written as hex
 
explainable: the number written as string is shown in a human-readable way, while the number written as hex
 
value is interpreted and shown as an ASCII code.
 
value is interpreted and shown as an ASCII code.
 +
 
Two important functions remain to be showed: ReadLnString to read strings from files and ReadLn to read
 
Two important functions remain to be showed: ReadLnString to read strings from files and ReadLn to read
 
numbers.
 
numbers.
Строка 151: Строка 158:
 
with random numbers in it (written as strings); you can comment this line and use another hand-created text file
 
with random numbers in it (written as strings); you can comment this line and use another hand-created text file
 
for this example.
 
for this example.
 +
 
Then the main task opens this file for reading, reads it a line at once until the end of file, calling ReadLnString
 
Then the main task opens this file for reading, reads it a line at once until the end of file, calling ReadLnString
 
function and displays text.
 
function and displays text.
 +
 
In the CreateRandomFile subroutine we generate a predefined quantity of random numbers, convert them to
 
In the CreateRandomFile subroutine we generate a predefined quantity of random numbers, convert them to
 
string and write them to the file.
 
string and write them to the file.
 +
 
The ReadLnString accepts a file handle and a string variable as arguments: after the call, the string will
 
The ReadLnString accepts a file handle and a string variable as arguments: after the call, the string will
 
contain a text line and the function will return an error code, that we can use to know if the end of file has been
 
contain a text line and the function will return an error code, that we can use to know if the end of file has been
 
reached.
 
reached.
#define FILE_LINES 10
+
 
sub CreateRandomFile(string fname, int lines){
+
#define FILE_LINES 10
byte handle;
+
string s;
+
sub CreateRandomFile(string fname, int lines){
int bytesWritten;
+
  byte handle;
DeleteFile(fname);
+
  string s;
int fsize = lines*5;
+
  int bytesWritten;
//create file with random data
+
  DeleteFile(fname);
if(CreateFile(fname, fsize, handle) == NO_ERR) {
+
  int fsize = lines*5;
int n;
+
  //create file with random data
repeat(FILE_LINES) {
+
  if(CreateFile(fname, fsize, handle) == NO_ERR) {
int n = Random(0xFF);
+
    int n;
s = NumToStr(n);
+
    repeat(FILE_LINES) {
WriteLnString(handle,s,bytesWritten);
+
      int n = Random(0xFF);
}
+
      s = NumToStr(n);
CloseFile(handle);
+
      WriteLnString(handle,s,bytesWritten);
}
+
    }
}
+
    CloseFile(handle);
task main(){
+
  }
byte handle;
+
}
int fsize;
+
string buf;
+
task main(){
bool eof = false;
+
  byte handle;
CreateRandomFile("rand.txt",FILE_LINES);
+
  int fsize;
if(OpenFileRead("rand.txt", fsize, handle) == NO_ERR) {
+
  string buf;
TextOut(10,LCD_LINE2,"Filesize:");
+
  bool eof = false;
NumOut(65,LCD_LINE2,fsize);
+
  CreateRandomFile("rand.txt",FILE_LINES);
Wait(600);
+
  if(OpenFileRead("rand.txt", fsize, handle) == NO_ERR) {
until (eof == true){ // read the text file till the end
+
    TextOut(10,LCD_LINE2,"Filesize:");
if(ReadLnString(handle,buf) != NO_ERR) eof = true;
+
    NumOut(65,LCD_LINE2,fsize);
ClearScreen();
+
    Wait(600);
TextOut(20,LCD_LINE3,buf);
+
    until (eof == true){ // read the text file till the end
Wait(500);
+
      if(ReadLnString(handle,buf) != NO_ERR) eof = true;
}
+
      ClearScreen();
}
+
      TextOut(20,LCD_LINE3,buf);
CloseFile(handle);
+
      Wait(500);
}
+
    }
 +
  }
 +
  CloseFile(handle);
 +
}
 +
 
 
In the last program, I'll show you how to read numbers from a file.
 
In the last program, I'll show you how to read numbers from a file.
 
I take the occasion to give you a little sample of conditional compilation. At the beginning of the code, there is a
 
I take the occasion to give you a little sample of conditional compilation. At the beginning of the code, there is a
 
definition that is not used for a macro neither for an alias: we simply define INT.
 
definition that is not used for a macro neither for an alias: we simply define INT.
 +
 
Then there is a preprocessor statement
 
Then there is a preprocessor statement
#ifdef INT
+
 
…Code…
+
#ifdef INT
#endif
+
…Code…
 +
#endif
  
 
that simply tells the compiler to compile the code between the two statements if INT as been previously defined.
 
that simply tells the compiler to compile the code between the two statements if INT as been previously defined.
 
So, if we define INT, the task main inside the first couplet will be compiled and if LONG is defined instead of
 
So, if we define INT, the task main inside the first couplet will be compiled and if LONG is defined instead of
 
INT, the second version of main will be compiled.
 
INT, the second version of main will be compiled.
 +
 
This method allows me to show in a single program how both int (16 bit) and long (32 bit) types can be read
 
This method allows me to show in a single program how both int (16 bit) and long (32 bit) types can be read
 
from file calling the same function ReadLn(handle,val).
 
from file calling the same function ReadLn(handle,val).
 +
 
As before, it accepts a file handle and a numeric variable as arguments, returning an error code.
 
As before, it accepts a file handle and a numeric variable as arguments, returning an error code.
 
The function will read 2 bytes from file if the passed variable is declared as int, and will read 4 bytes if the
 
The function will read 2 bytes from file if the passed variable is declared as int, and will read 4 bytes if the
 
variable is long. Also bool variables can be written and read the same way.
 
variable is long. Also bool variables can be written and read the same way.
#define INT // INT or LONG
+
 
#ifdef INT
+
#define INT // INT or LONG
task main () {
+
#ifdef INT
byte handle, time = 0;
+
int n, fsize,len, i;
+
task main () {
int in;
+
  byte handle, time = 0;
DeleteFile("int.txt");
+
  int n, fsize,len, i;
CreateFile("int.txt",4096,handle);
+
  int in;
for (int i = 1000; i<=10000; i+=1000){
+
  DeleteFile("int.txt");
WriteLn(handle,i);
+
  CreateFile("int.txt",4096,handle);
}
+
  for (int i = 1000; i<=10000; i+=1000){
CloseFile(handle);
+
    WriteLn(handle,i);
OpenFileRead("int.txt",fsize,handle);
+
  }
until (ReadLn(handle,in)!=NO_ERR){
+
  CloseFile(handle);
ClearScreen();
+
  OpenFileRead("int.txt",fsize,handle);
NumOut(30,LCD_LINE5,in);
+
  until (ReadLn(handle,in)!=NO_ERR){
Wait(500);
+
    ClearScreen();
}
+
    NumOut(30,LCD_LINE5,in);
CloseFile(handle);
+
    Wait(500);
}
+
  }
#endif
+
  CloseFile(handle);
#ifdef LONG
+
}
task main () {
+
byte handle, time = 0;
+
#endif
int n, fsize,len, i;
+
#ifdef LONG
long in;
+
DeleteFile("long.txt");
+
task main () {
CreateFile("long.txt",4096,handle);
+
  byte handle, time = 0;
for (long i = 100000; i<=1000000; i+=50000){
+
  int n, fsize,len, i;
WriteLn(handle,i);
+
  long in;
}
+
  DeleteFile("long.txt");
CloseFile(handle);
+
  CreateFile("long.txt",4096,handle);
OpenFileRead("long.txt",fsize,handle);
+
  for (long i = 100000; i<=1000000; i+=50000){
until (ReadLn(handle,in)!=NO_ERR){
+
    WriteLn(handle,i);
ClearScreen();
+
  }
NumOut(30,LCD_LINE5,in);
+
  CloseFile(handle);
Wait(500);
+
  OpenFileRead("long.txt",fsize,handle);
}
+
  until (ReadLn(handle,in)!=NO_ERR){
CloseFile(handle);
+
    ClearScreen();
}
+
    NumOut(30,LCD_LINE5,in);
 +
    Wait(500);
 +
  }
 +
  CloseFile(handle);
 +
}
 +
 
#endif
 
#endif
 +
 
==Подводим итоги==
 
==Подводим итоги==
 
In this last chapter you met the advanced features offered by NXT: high resolution timer, dot matrix display and
 
In this last chapter you met the advanced features offered by NXT: high resolution timer, dot matrix display and
 
filesystem.
 
filesystem.

Версия 09:42, 20 мая 2009

Автор: Daniele Benedettelli

Перевод: © Ботов Антон aka =DeaD=, 2009

Эксклюзивно для www.roboforum.ru
копирование на другие ресурсы и публикация перевода
без разрешения его автора запрещены

Дополнительные возможности

NXC имеет несколько сервисных команд. В этой главе мы обсудим три типа таких команд: для работы с таймером, дисплеем и для использования файловой системы NXT.

Таймеры

The NXT has a timer that runs continuously. This timer ticks in increments of 1/1000 of a second. You can get the current value of the timer with CurrentTick(). Here is an example of the use of a timer. The following program lets the robot drive sort of random for 10 seconds.

task main()
{
  long t0, time;
  t0 = CurrentTick();
  do
  {
    time = CurrentTick()-t0;
    OnFwd(OUT_AC, 75);
    Wait(Random(1000));
    OnRev(OUT_C, 75);
    Wait(Random(1000));
  }
  while (time<10000);
  Off(OUT_AC);
}

You might want to compare this program with the one given in Chapter IV that did exactly the same task. The one with timers is definitely simpler.

Timers are very useful as a replacement for a Wait() command. You can sleep for a particular amount of time by resetting a timer and then waiting till it reaches a particular value. But you can also react on other events (e.g. from sensors) while waiting. The following simple program is an example of this. It lets the robot drive until either 10 seconds are past, or the touch sensor touches something.

task main()
{
  long t3;
  SetSensor(IN_1,SENSOR_TOUCH);
  t3 = CurrentTick();
  OnFwd(OUT_AC, 75);
  until ((SENSOR_1 == 1) || ((CurrentTick()-t3) > 10000));
  Off(OUT_AC);
}

Don't forget that timers work in ticks of 1/1000 of a second just like the wait command.

Дисплей

NXT brick features a black and white dot matrix display with a resolution of 100x64 pixels. There are many API functions to draw text strings, numbers, dots, lines, rectangles, circles, and even bitmap images (.ric files). The next example tries to cover all these cases. Pixel numbered (0,0) is the bottom left one.

#define X_MAX 99
#define Y_MAX 63
#define X_MID (X_MAX+1)/2
#define Y_MID (Y_MAX+1)/2

task main(){
  int i = 1234;
  TextOut(15,LCD_LINE1,"Display", true);
  NumOut(60,LCD_LINE1, i);
  PointOut(1,Y_MAX-1);
  PointOut(X_MAX-1,Y_MAX-1);
  PointOut(1,1);
  PointOut(X_MAX-1,1);
  Wait(200);
  RectOut(5,5,90,50);
  Wait(200);
  LineOut(5,5,95,55);
  Wait(200);
  LineOut(5,55,95,5);
  Wait(200);
  CircleOut(X_MID,Y_MID-2,20);
  Wait(800);
  ClearScreen();
  GraphicOut(30,10,"faceclosed.ric"); Wait(500);
  ClearScreen();
  GraphicOut(30,10,"faceopen.ric");
  Wait(1000);
}

All these functions are quite self-explanatory, but now I'll describe their parameters in detail.

  • ClearScreen() очищает экран;
  • NumOut(x, y, number) выводит число в указанные координаты;
  • TextOut(x, y, string) тоже самое, только выводит строку
  • GraphicOut(x, y, filename) выводит картинку из .ric-файла
  • CircleOut(x, y, radius) выводит окружность определенную коорoutputs a circle specified by the coordinates of the center and radius;
  • LineOut(x1, y1, x2, y2) draws a line that goes from point (x1,x2) to (x2,y2)
  • PointOut(x, y) ставит точку
  • RectOut(x, y, width, height) рисует прямоугольник с нижним левым углом в (x,y) и указанных размеров;
  • ResetScreen() сбрасывает экран.

Файловая система

The NXT can write and read files, stored inside its flash memory. So you could save a datalog from sensor data or read numbers during program execution. The only limit in files number and dimension is the size of the flash memory. NXT API functions let you manage files (create, rename, delete, find) , let you read and write text strings, numbers and single bytes. In the next example, we will see how to create a file, write strings into it and rename it.

First, program deletes files with the names we're going to use: it is not a good habit (we should check for file existence, manually delete it or choose automatically another name for our work file), but there's no problem in our simple case. It creates our file by CreateFile("Danny.txt", 512, fileHandle), specifying name, size and a handle to the file, where NXT firmware will write a number for its own uses.

Then it builds strings and write to file with carriage return with WriteLnString(fileHandle,string, bytesWritten), where all the parameters must be variables. Finally, the file is closed and renamed. Remember: a file must be closed before beginning another operation, so if you created a file you can write to it; if you want to read from it, you must close it and open it with OpenFileRead(); to delete/rename it, you must close it.

#define OK LDR_SUCCESS

task main(){
  byte fileHandle;
  short fileSize;
  short bytesWritten;
  string read;
  string write;
  DeleteFile("Danny.txt");
  DeleteFile("DannySays.txt");
  CreateFile("Danny.txt", 512, fileHandle);
  for(int i=2; i<=10; i++ ){
    write = "NXT is cool ";
    string tmp = NumToStr(i);
    write = StrCat(write,tmp," times!");
    WriteLnString(fileHandle,write, bytesWritten);
  }
  CloseFile(fileHandle);
  RenameFile("Danny.txt","DannySays.txt");
}

To see the result, go to BricxCCToolsNXT Explorer, upload DannySays.txt to pc and take a look. Ready for the next example! We will create a table with ASCII characters.

task main(){
  byte handle;
  if (CreateFile("ASCII.txt", 2048, handle) == NO_ERR) {
    for (int i=0; i < 256; i++) {
      string s = NumToStr(i);
      int slen = StrLen(s);
      WriteBytes(handle, s, slen);
      WriteLn(handle, i);
    }
    CloseFile(handle);
  }
}

Really simple, this program creates the file and if no error occurred, it writes a number from 0 to 255 (converting it to string before) with WriteBytes(handle, s, slen), that is another way to write strings without carriage return; then it writes the number as is with WriteLn(handle, value) that appends a carriage return. The result, that you can see as before opening ASCII.txt with a text editor (as Windows Notepad), is so explainable: the number written as string is shown in a human-readable way, while the number written as hex value is interpreted and shown as an ASCII code.

Two important functions remain to be showed: ReadLnString to read strings from files and ReadLn to read numbers.

Now for the example for the first one: the main task calls CreateRandomFile subroutine that creates a file with random numbers in it (written as strings); you can comment this line and use another hand-created text file for this example.

Then the main task opens this file for reading, reads it a line at once until the end of file, calling ReadLnString function and displays text.

In the CreateRandomFile subroutine we generate a predefined quantity of random numbers, convert them to string and write them to the file.

The ReadLnString accepts a file handle and a string variable as arguments: after the call, the string will contain a text line and the function will return an error code, that we can use to know if the end of file has been reached.

#define FILE_LINES 10

sub CreateRandomFile(string fname, int lines){
  byte handle;
  string s;
  int bytesWritten;
  DeleteFile(fname);
  int fsize = lines*5;
  //create file with random data
  if(CreateFile(fname, fsize, handle) == NO_ERR) {
    int n;
    repeat(FILE_LINES) {
      int n = Random(0xFF);
      s = NumToStr(n);
      WriteLnString(handle,s,bytesWritten);
    }
    CloseFile(handle);
  }
}

task main(){
  byte handle;
  int fsize;
  string buf;
  bool eof = false;
  CreateRandomFile("rand.txt",FILE_LINES);
  if(OpenFileRead("rand.txt", fsize, handle) == NO_ERR) {
    TextOut(10,LCD_LINE2,"Filesize:");
    NumOut(65,LCD_LINE2,fsize);
    Wait(600);
    until (eof == true){ // read the text file till the end
      if(ReadLnString(handle,buf) != NO_ERR) eof = true;
      ClearScreen();
      TextOut(20,LCD_LINE3,buf);
      Wait(500);
    }
  }
  CloseFile(handle);
}

In the last program, I'll show you how to read numbers from a file. I take the occasion to give you a little sample of conditional compilation. At the beginning of the code, there is a definition that is not used for a macro neither for an alias: we simply define INT.

Then there is a preprocessor statement

#ifdef INT
…Code…
#endif

that simply tells the compiler to compile the code between the two statements if INT as been previously defined. So, if we define INT, the task main inside the first couplet will be compiled and if LONG is defined instead of INT, the second version of main will be compiled.

This method allows me to show in a single program how both int (16 bit) and long (32 bit) types can be read from file calling the same function ReadLn(handle,val).

As before, it accepts a file handle and a numeric variable as arguments, returning an error code. The function will read 2 bytes from file if the passed variable is declared as int, and will read 4 bytes if the variable is long. Also bool variables can be written and read the same way.

#define INT // INT or LONG
#ifdef INT

task main () {
  byte handle, time = 0;
  int n, fsize,len, i;
  int in;
  DeleteFile("int.txt");
  CreateFile("int.txt",4096,handle);
  for (int i = 1000; i<=10000; i+=1000){
    WriteLn(handle,i);
  }
  CloseFile(handle);
  OpenFileRead("int.txt",fsize,handle);
  until (ReadLn(handle,in)!=NO_ERR){
    ClearScreen();
    NumOut(30,LCD_LINE5,in);
    Wait(500);
  }
  CloseFile(handle);
}

#endif
#ifdef LONG

task main () {
  byte handle, time = 0;
  int n, fsize,len, i;
  long in;
  DeleteFile("long.txt");
  CreateFile("long.txt",4096,handle);
  for (long i = 100000; i<=1000000; i+=50000){
    WriteLn(handle,i);
  }
  CloseFile(handle);
  OpenFileRead("long.txt",fsize,handle);
  until (ReadLn(handle,in)!=NO_ERR){
    ClearScreen();
    NumOut(30,LCD_LINE5,in);
    Wait(500);
  }
  CloseFile(handle);
}

  1. endif

Подводим итоги

In this last chapter you met the advanced features offered by NXT: high resolution timer, dot matrix display and filesystem.