Sie sind auf Seite 1von 44

Programando Robs Lego com NQC

(Verso 3.03, 2 de Outubro de 1999)

por Mark Overmars

Department of Computer Science Utrecht University P.O. Box 80.089, 3508 TB Utrecht the Netherlands

Traduzido para a lngua portuguesa por Anderson Grandi Pires em 23 de maro de 2008 Professor do Centro Federal de Educao Tecnolgica de Minas Gerais (CEFET-MG) Campus III Leopoldina Minas Gerais Brasil

Prefcio
Os kits de robs Lego Mindstorms e CyberMaster so novos maravilhosos brinquedos em que uma ampla variedade de robs podem ser construdos e programados para fazer todo tipo de tarefa complicada. Infelizmente, o software distribudo juntamente com tais kits , apesar de visualmente atrativo, bastante limitado no que diz respeito funcionalidade. Desse modo, tal software pode ser utilizado somente para tarefas simples. Para explorar todo o potencial dos robs, faz-se necessrio um ambiente de programao diferente. NQC uma linguagem de programao, escrita por Dave Baum, projetada especialmente para os robs Lego. Caso voc nunca tenha escrito um programa antes, no se preocupe. NQC realmente muito fcil de usar e este tutorial o ensinar tudo a este respeito. Atualmente, programar robs com NQC muito mais fcil do que programar um computador normal, sendo essa uma maneira fcil de se tornar um programador. Para tornar a tarefa de programar realmente fcil, existe o RCX Command Center. Este utilitrio o ajuda a escrever seus programas, envi-los aos robs, iniciar e parar os robs. RCX Command Center funciona quase como um processador de textos, porm com algumas funcionalidades extras. Este tutorial usar o RCX Command Center (verso 3.0 ou superior) como ambiente de programao. Voc pode efetuar o download desse utilitrio, livremente, a partir do seguinte endereo eletrnico: http://www.cs.uu.nl/people/markov/lego/ RCX Command Center roda sobre a plataforma Windows (verso 95, 98 e NT). (Voc deve executar o software que vem com o kit Lego Mindstorms pelo menos uma vez, antes de executar o RCX Command Center. O software que acompanha o kit instala certos componentes que o RCX Command Center utiliza.) A linguagem NQC pode tambm ser usada sobre outras plataformas. Voc pode baix-lo na internet no endereo: http://www.enteract.com/~dbaum/lego/nqc/ A maior parte deste tutorial tambm se aplica a outras plataformas (assumindo que se esteja usando o NQC verso 2.0 ou superior), exceto pelo fato de que algumas ferramentas so perdidas, alm da perda da funcionalidade de realce de cor no cdigo-fonte. Neste tutorial eu assumo que voc tenha o kit de robs Lego Mindstorms. A maior parte dos contedos tambm se aplica ao kit de robs CyberMaster, contudo algumas funcionalidades no se encontram disponveis para este ltimo. Alm disso, para o kit de robs CyberMaster, os nomes dos motores (por exemplo) so diferentes, o que torna necessrio modificar os exemplos um pouco para faz-los funcionar.

Agradecimentos
Eu gostaria de agradecer a Dave Braum por ter desenvolvido o NQC. Gostaria de agradecer tambm a Kevin Saddi por ter escrito a primeira verso da primeira parte deste tutorial.

-2-

Sumrio
Prefcio ___________________________________________________________________ 2
Agradecimentos ______________________________________________________________________ 2

Sumrio___________________________________________________________________ 3 I. Escrevendo o seu primeiro programa _________________________________________ 5


Construindo um rob __________________________________________________________________ Iniciando o RCX Command Center _______________________________________________________ Escrevendo o programa _________________________________________________________________ Executando o programa_________________________________________________________________ Erros no programa _____________________________________________________________________ Modificando a velocidade _______________________________________________________________ Resumo _____________________________________________________________________________ 5 5 6 7 7 8 8

II. Um programa mais interessante _____________________________________________ 9


Fazendo curvas _______________________________________________________________________ 9 Repetindo comandos ___________________________________________________________________ 9 Incluindo comentrios _________________________________________________________________ 10 Resumo ____________________________________________________________________________ 11

III. Usando variveis _______________________________________________________ 12


Movendo em forma de uma espiral _______________________________________________________ 12 Nmeros randmicos _________________________________________________________________ 13 Resumo ____________________________________________________________________________ 13

IV. Estruturas de controle ___________________________________________________ 14


A instruo if________________________________________________________________________ 14 A instruo do _______________________________________________________________________ 15 Resumo ____________________________________________________________________________ 15

V. Sensores _______________________________________________________________ 16
Esperando por um sensor ______________________________________________________________ Respondendo a um sensor de toque ______________________________________________________ Sensores de luz ______________________________________________________________________ Resumo ____________________________________________________________________________ Tarefas_____________________________________________________________________________ Sub-rotinas _________________________________________________________________________ Funes inline _______________________________________________________________________ Definindo macros ____________________________________________________________________ Resumo ____________________________________________________________________________ 16 16 17 18 19 20 20 21 22

VI. Tarefas e sub-rotinas ____________________________________________________ 19

VII. Criando msicas _______________________________________________________ 23


Sons pr-programados _________________________________________________________________ 23 Tocando msica _____________________________________________________________________ 23 Resumo ____________________________________________________________________________ 24

VIII. Mais a respeito de motores ______________________________________________ 25


Parando suavemente __________________________________________________________________ Comandos avanados _________________________________________________________________ Variando a velocidade de rotao do motor ________________________________________________ Resumo ____________________________________________________________________________ Modo e tipo de sensores _______________________________________________________________ O sensor de rotao ___________________________________________________________________ Colocando vrios sensores em uma nica entrada ___________________________________________ Fazendo um sensor de proximidade ______________________________________________________ Resumo ____________________________________________________________________________ 25 25 26 26 27 28 28 30 30

IX. Mais a respeito de sensores _______________________________________________ 27

-3-

X. Tarefas paralelas ________________________________________________________ 32


Um programa errado __________________________________________________________________ Parando e reiniciando tarefas ___________________________________________________________ Usando semforos ____________________________________________________________________ Resumo ____________________________________________________________________________ Dando ordens _______________________________________________________________________ Elegendo um lder ____________________________________________________________________ Precaues__________________________________________________________________________ Resumo ____________________________________________________________________________ 32 32 33 34 35 36 36 37

XI. Comunicao entre robs ________________________________________________ 35

XII. Mais comandos ________________________________________________________ 38


Temporizadores______________________________________________________________________ 38 O display ___________________________________________________________________________ 38 Datalogging _________________________________________________________________________ 39

XIII. NQC: guia de referncia rpido __________________________________________ 40


Instrues __________________________________________________________________________ Condies __________________________________________________________________________ Expresses__________________________________________________________________________ Funes do RCX _____________________________________________________________________ Constantes do RCX ___________________________________________________________________ Palavras-chave ______________________________________________________________________ 40 40 40 41 42 43

XIV. Consideraes finais ___________________________________________________ 44

-4-

I. Escrevendo o seu primeiro programa


Neste captulo voc ver como escrever um programa extremamente simples. Iremos programar um rob para executar as seguintes tarefas: mover para frente durante 4 segundos; mover para trs outros 4 segundos; e ento parar. Nada muito espetacular, mas isso o familiarizar com idias bsicas da programao. Alm disso, mostrarlhe- o quando fcil isto . Mas, antes de escrevermos um programa, precisaremos de um rob.

Construindo um rob
O rob que utilizaremos por todo este tutorial uma verso simplificada do rob top-secret que descrito nas pginas 39 a 46 do material contructopedia que acompanha o kit. Utilizaremos somente a base (chassi). Remova toda a frente, incluindo os dois braos e os sensores de toque. Alm disso, conecte os motores ligeiramente diferentes, de modo que os cabos conectados no RCX fiquem dispostos lateralmente. Isto importante para que o rob mova na direo correta. O rob parecer tal como a figura abaixo:

Tenha certeza de que a torre de transmisso de dados (Infrared Tower) esteja conectada corretamente ao computador e que esteja configurada para longo alcance (long range). (Voc pode querer checar com o software Robotics Invention System RIS se o rob est funcionando adequadamente)

Iniciando o RCX Command Center


Escreveremos nossos programas utilizando o RCX Command Center. Inicie-o por intermdio de um clique duplo no cone RcxCC. (Eu presumo que voc j tenha instalado o RCX Command Center. Caso no, faa o download da internet veja o endereo eletrnico no prefcio e o descompacte-o em qualquer diretrio que voc queira.) O programa tentar localizar o rob. Ligue o rob e pressione OK. O programa encontrar o rob automaticamente ( esperado que isso ocorra). A interface do usurio se apresenta conforme abaixo (sem a janela central).

-5-

A interface parecida com aquelas existentes em editores de texto, com os menus usuais e botes para abrir, salvar, imprimir, editar arquivos, etc. Alm disso, existem menus especiais para compilar e descarregar os programas nos robs, alm daqueles disponveis para se obter informaes a respeito do rob. Voc pode ignorar os ltimos menus por enquanto. Iremos escrever um novo programa. Pressione o boto New File para criar uma nova janela vazia.

Escrevendo o programa
Digite as instrues abaixo no novo programa:
task main() { OnFwd(OUT_A); OnFwd(OUT_C); Wait(400); OnRev(OUT_A+OUT_C); Wait(400); Off(OUT_A+OUT_C); }

Pode parecer um pouco complicado a princpio, ento vamos analis-lo. Programas em NQC consistem de tarefas (task). Nosso programa tem somente uma tarefa de nome main (tarefa principal). Cada programa necessita de uma tarefa nomeada main, que ser automaticamente executada pelo rob. Voc aprender mais a respeito de tarefas no Captulo VI. Uma tarefa consiste de um conjunto de comandos, tambm referenciados como instrues (statements). Existem chaves em torno das instrues, o que deixa claro que aquelas instrues pertencem a uma determinada tarefa (Um par de chaves define um bloco de comandos). Cada instruo finaliza com um ponto-e-vrgula. Desse modo, torna-se claro onde uma instruo finaliza e onde a prxima comea. De maneira geral, uma tarefa se parece com a seguinte estrutura:

-6-

task main() { statement1; statement2; }

//tarefa principal //primeira instruo //segunda instruo

Nosso programa (pgina anterior) tem seis comandos. Daremos uma olhada em cada um destes:
OnFwd(OUT_A);

Este comando diz ao rob para habilitar (energizar) a sada A, isto , o motor conectado sada A do RCX girar para frente. Ele mover com a velocidade mxima, a menos que a velocidade seja configurada antes da execuo deste comando. Posteriormente veremos como fazer isso.
OnFwd(OUT_C);

Semelhante instruo anterior, porm agora girar o motor C. Aps a execuo desses dois comandos, ambos os motores estaro girando e o rob se move para frente.
Wait(400);

Agora hora de esperar por um perodo de tempo. Esta instruo nos diz para aguardar pelo perodo de 4 segundos. O argumento, isto , o nmero entre parnteses, define o nmero de ticks. Cada tick corresponde a 1/100 segundos. Ento voc pode, de maneira bastante precisa, dizer ao programa quanto tempo aguardar. Assim sendo, pelo perodo de 4 segundos o programa no faz nada, embora o rob continue se movendo para frente.
OnRev(OUT_A+OUT_C);

Tendo o rob se movimentado o suficiente para frente, diremos a ele para se mover no sentido reverso, ou seja, para trs. Observe que ns podemos configurar ambos os motores de uma nica vez, utilizando OUT_A+OUT_C como argumento. Ns poderamos ter combinado as duas primeiras instrues desta maneira.
Wait(400);

Novamente, esperamos por 4 segundos.


Off(OUT_A+OUT_C);

E, finalmente, desligamos ambos os motores. Este todo o programa. Ele move os motores para frente por 4 segundos, move os motores para trs outros 4 segundos e finalmente os desliga. Voc provavelmente observou as cores quando estava digitando o programa. Elas aparecem automaticamente. Tudo que est em azul so comandos para o rob, ou uma indicao de um motor ou outra coisa que o rob conhece. A palavra task est em negrito por ser uma importante palavra-chave (reservada) em NQC. Outras importantes palavras aparecem em negrito, conforme veremos a seguir. As cores so teis para mostrar que voc no cometeu algum erro enquanto estava digitando o programa.

Executando o programa
Uma vez que um programa tenha sido escrito, ele precisa ser compilado (isto , transformado em um cdigo que o rob possa entender e executar) e enviado para o rob usando a torre de transmisso de dados (comumente denominado de processo de descarregar o programa). Existe um boto que efetua as duas tarefas (veja a figura acima). Pressione este boto e, assumindo que no foram inseridos erros na digitao, o programa ir compilar corretamente e ser descarregado no rob. (Caso existam erros no programa, tais erros sero notificados; veja abaixo.) Agora voc pode executar o programa. Para isso, pressione o boto verde (run) do RCX ou, de maneira mais fcil, pressione o boto run da janela do RCX Command Center (ver figura acima). O rob faz aquilo que esperado? Caso no, provavelmente os cabos foram conectados de maneira errada.

Erros no programa
Quando estamos digitando um cdigo de um programa existe a possibilidade de cometermos erros de digitao. O compilador verifica os erros e os relata na parte inferior da janela do RCX Command Center, conforme apresentado abaixo:

-7-

Ele automaticamente seleciona o erro (cometemos um equvoco ao digitar o nome do motor). Quando existem mais erros, voc pode clicar nas mensagens de erros para localiz-los. Observe que erros existentes no incio de um programa podem acarretar em erros em outros locais do cdigo. Ento, o melhor a fazer corrigir alguns erros e compilar o programa novamente. Observe, tambm, que a cor associada s instrues de cdigo ajuda bastante a evitar erros. Por exemplo, na ltima linha foi digitado Of ao invs de Off. Devido ao fato deste comando ser desconhecido, o mesmo no se apresenta na cor azul. Existem alguns erros que no so identificados pelo compilador. Caso tenhamos digitado OUT_B isso teria passado despercebido devido ao fato de que tal sada existe (mesmo sabendo que ns no a usamos no rob). Ento, caso o rob exiba um comportamento inesperado, existe ainda algum erro no seu programa.

Modificando a velocidade
Como observado, o rob se move de maneira bastante rpida. Por padro, o rob se move to rpido quanto ele pode. Para modificar esta velocidade voc pode utilizar o comando SetPower(). A potncia um nmero entre 0 e 7. O nmero 7 representa a velocidade mais rpida, enquanto que 0 representa a mais devagar (mas o rob ainda se move). Aqui est uma nova verso do nosso programa nos quais o rob se move lentamente:
task main() { SetPower(OUT_A+OUT_C,2); OnFwd(OUT_A+OUT_C); Wait(400); OnRev(OUT_A+OUT_C); Wait(400); Off(OUT_A+OUT_C); }

Resumo
Neste captulo voc escreveu seu primeiro programa em NQC, usando o RCX Command Center. At este ponto, voc aprendeu a escrever um programa, descarreg-lo no rob e coloc-lo em execuo. O software RCX Command Center pode fazer outras coisas mais. Para descobrir, leia a documentao que acompanha o software. Este tutorial referente, principalmente, linguagem NQC e somente menciona caractersticas do RCX Command Center quando realmente forem necessrias. Voc tambm aprendeu alguns importantes aspectos da linguagem NQC. Inicialmente, voc aprendeu que cada programa tem uma tarefa denominada main, que sempre executada pelo rob. Depois voc aprendeu os quatro comandos referentes a motores mais importantes: OnFwd(), OnRev(), SetPower() e Off(). Por fim, voc aprendeu a respeito do comando Wait().

-8-

II. Um programa mais interessante


Nosso primeiro programa no era to espetacular. Ento, deixe-nos tentar fazer algo mais interessante. Faremos isso em vrios passos, introduzindo algumas caractersticas importantes da linguagem de programao NQC.

Fazendo curvas
Voc pode instruir o rob a fazer curvas por meio da paralisao ou da rotao reversa de um dos dois motores. Abaixo temos um exemplo. Digite e compile o cdigo, transfira-o para o rob e ento execute. Ele deve se mover para frente um pouco e ento girar em um ngulo de 90 graus.
task main() { OnFwd(OUT_A+OUT_C); Wait(100); OnRev(OUT_C); Wait(85); Off(OUT_A+OUT_C); }

Pode acontecer de voc ter que tentar alguns nmeros prximos de 85 na segunda chamada ao comando Wait() para fazer com que o rob gire precisamente em 90 graus. Isto depende do tipo de superfcie nos quais o rob est sendo utilizado. Ao invs de modificar isto no corpo da tarefa main, mais fcil atribuir um nome para este nmero. Em NQC voc pode definir valores constantes como mostrado no seguinte programa:
#define TEMPO_DE_MOVIMENTACAO #define TEMPO_DE_CURVATURA task main() { OnFwd(OUT_A+OUT_C); Wait(TEMPO_DE_MOVIMENTACAO); OnRev(OUT_C); Wait(TEMPO_DE_CURVATURA); Off(OUT_A+OUT_C); } 100 85

As duas primeiras linhas definem duas constantes. A partir da definio, as constantes podero ser utilizadas por todo o programa. Definir constantes bom por duas razes: torna o programa mais legvel e facilita as mudanas de valores. Observe que o RCX Command Center estipula uma cor prpria para as instrues define. Como ser visto no Captulo VI, voc poder definir outras coisas alm de constantes.

Repetindo comandos
Vamos agora escrever um programa que faz o rob se mover em um caminho em forma de um quadrado. Mover-se em forma de um quadrado significa: mover para frente, girar 90 graus, mover para frente de novo, girar 90 graus, etc. Ns poderamos repetir o pedao de cdigo acima quatro vezes, mas isto pode ser feito de maneira mais fcil com a estrutura de repetio repeat.

-9-

#define TEMPO_DE_MOVIMENTACAO #define TEMPO_DE_CURVATURA task main() { repeat(4) { OnFwd(OUT_A+OUT_C); Wait(TEMPO_DE_MOVIMENTACAO); OnRev(OUT_C); Wait(TEMPO_DE_CURVATURA); } Off(OUT_A+OUT_C); }

100 85

O nmero entre parnteses na instruo repeat indica com que freqncia as coisas devero ser repetidas. As instrues que devem ser repetidas so colocadas entre chaves (definindo o bloco de comandos associado instruo repeat), semelhantemente ao que se faz em uma tarefa. Observe no programa acima que tambm endentamos as instrues (insero de espaos na margem esquerda). Isso no necessrio, mas torna o programa mais legvel. Como um exemplo final, faremos o rob se movimentar 10 vezes em um caminho em forma de um quadrado. Aqui est o programa:
#define TEMPO_DE_MOVIMENTACAO #define TEMPO_DE_CURVATURA task main() { repeat(10) { repeat(4) { OnFwd(OUT_A+OUT_C); Wait(TEMPO_DE_MOVIMENTACAO); OnRev(OUT_C); Wait(TEMPO_DE_CURVATURA); } } Off(OUT_A+OUT_C); } 100 85

Existem agora duas instrues repeat, uma dentro da outra. Ns chamamos isso de instrues repeat aninhadas. Voc pode aninhar quantas instrues repeat voc desejar. D uma olhada criteriosa nas chaves e na endentao utilizada no programa. A tarefa principal inicia na primeira abertura de chaves e finaliza na ltima chave. A primeira instruo repeat inicia na segunda abertura de chaves e finalize na quinta chave. A segunda instruo repeat inicia na terceira chave e finalize na quarta. Como se pode ver, as chaves sempre aparecem em pares e as instrues existentes entre as chaves so endentadas.

Incluindo comentrios
Uma boa maneira para tornar seu programa mais legvel por meio da incluso de comentrios. Caso voc coloque // (duas barras) em uma linha, todo cdigo inserido aps estes smbolos (na mesma linha) sero ignorados e podero ser utilizados como comentrios. Um comentrio mais longo poder ser includo entre os smbolos /* e */ (comentrio de mltiplas linhas). No RCX Command Center os comentrios se apresentam na cor verde. O programa completo se parece conforme apresentado a seguir:

- 10 -

/*

10 QUADRAS por Mark Overmars

Este programa faz o rob se movimentar por 10 quadras */ #define TEMPO_DE_MOVIMENTACAO #define TEMPO_DE_CURVATURA 100 //Tempo de movimentao para frente 85 //Tempo de curvatura em 90 graus

task main() { repeat(10) // Percorre as 10 quadras { repeat(4) { OnFwd(OUT_A+OUT_C); Wait(TEMPO_DE_MOVIMENTACAO); OnRev(OUT_C); Wait(TEMPO_DE_CURVATURA); } } Off(OUT_A+OUT_C); // Agora, desliga os motores }

Resumo
Neste captulo voc aprendeu a usar a instruo repeat e inserir comentrios. Alm disso, voc viu o propsito de se utilizar chaves aninhadas e o uso de endentao. Com tudo o que foi aprendido, voc pode fazer o rob se mover por todo tipo de caminho. Um bom exerccio seria tentar escrever algumas variaes dos programas deste captulo antes de avanar para o prximo.

- 11 -

III. Usando variveis


Variveis compreendem um importante aspecto de toda linguagem de programao. Variveis consistem de localizaes na memria onde podemos armazenar valores. Podemos usar o valor armazenado em diferentes lugares, alm de podermos modificar tal valor. Deixe-me descrever o uso de variveis por intermdio de um exemplo.

Movendo em forma de uma espiral


Vamos assumir que queremos adaptar o programa acima de tal maneira que o rob percorra um caminho em forma de espiral. Isso pode ser feito por meio de um aumento no tempo em que esperamos (Wait) em cada movimento posterior. Isto , ns queremos aumentar o valor de do TEMPO_DE_MOVIMENTACAO cada vez que as instrues associadas repeat forem executadas. Mas como fazer isso? TEMPO_DE_MOVIMENTACAO uma constante e constantes no podem ser modificadas. Necessitamos, ento, de uma varivel. Variveis podem ser facilmente definidas em NQC. Voc pode ter 32 variveis e dar a cada uma delas um nome diferente. A seguir apresentado o programa espiral.
#define TEMPO_DE_CURVATURA 85 int tempo_de_movimentacao; task main() { tempo_de_movimentacao = 20; repeat(50) { OnFwd(OUT_A+OUT_C); Wait(tempo_de_movimentacao); OnRev(OUT_C); Wait(TEMPO_DE_CURVATURA); tempo_de_movimentacao += 5; } Off(OUT_A+OUT_C); } // declara uma varivel

// inicializa a varivel

// utiliza a varivel para esperar

// incrementa a varivel

As linhas interessantes esto indicadas com comentrios. Primeiro definimos uma varivel por intermdio da utilizao da palavra-chave int, seguida por um nome que ns mesmos escolhemos. (Normalmente usamos letras minsculas para nomes de variveis e letras maisculas para nomes de constantes, mas no necessrio.) O nome deve iniciar com uma letra, mas pode conter nmeros e o caractere especial sublinhado ( _ ). Nenhum outro smbolo permitido. (O mesmo se aplica a constantes, nomes de tarefas, etc.) A palavra-chave em negrito int significa inteiro. Somente nmeros inteiros podem ser armazenados nesse tipo de varivel. Na segunda linha interessante ns inicializamos a varivel com o valor 20 (atribumos o valor 20 varivel). A partir deste ponto, caso voc use a varivel ela valer 20. Agora, no corpo de repeat, observe que usamos a varivel tempo_de_movimentacao para indicar o tempo de espera e no final do loop incrementamos o valor da varivel em 5 unidades. Assim sendo, na primeira vez o rob espera por 20 ticks, na segunda vez 25, na terceira 30, etc. Alm de adicionar valores para uma varivel, podemos multiplicar uma varivel por um nmero utilizando *=, subtrair utilizando -= e dividir usando /=. (Observe que para a diviso o resultado arredondado para o nmero inteiro mais prximo.) Voc pode tambm adicionar uma varivel a outra e desenvolver expresses mais complicadas. Temos aqui alguns exemplos:

- 12 -

int aaa; int bbb, ccc; task main() { aaa = 10; bbb = 20 * 5; ccc = bbb; ccc /= aaa; ccc -= 5; aaa = 10 * (ccc + 3); }

// aaa agora igual a 80

Observe nas duas primeiras linhas que podemos definir vrias variveis em uma nica instruo. Poderamos, tambm, ter combinado as trs variveis em uma nica linha.

Nmeros randmicos
Em todos os programas acima definimos exatamente o que seria suposto que o rob fizesse. Mas as coisas se tornam mais interessantes quando o rob est apto a fazer coisas que ns no sabemos, ou seja, de maneira imprevisvel. Queremos alguma aleatoriedade nas movimentaes do rob. Em NQC voc pode criar nmeros randmicos, ou seja, aleatrios. O seguinte programa usa isso para deixar o rob se movimentar de maneira aleatria. O rob constantemente se movimenta para frente uma quantidade de tempo aleatria e ento efetua um giro tambm aleatrio.
int tempo_de_movimentacao, tempo_de_curvatura; task main() { while(true) { tempo_de_movimentacao = Random(60); tempo_de_curvatura = Random(40); OnFwd(OUT_A+OUT_C); Wait(tempo_de_movimentacao); OnRev(OUT_A); Wait(tempo_de_curvatura); } }

O programa define duas variveis e ento atribui a elas valores aleatrios. Random(60) significa que um nmero entre 0 e 60 (inclusives) ser gerado (0 ou 60 so valores possveis). A cada chamada a Random() os nmeros sero diferentes. (Observe que poderamos evitar o uso de variveis ao escrever, por exemplo, Wait(Random(60)).) Voc pode observar um novo tipo de loop aqui. Ao invs de utilizar a instruo repeat, escrevemos while(true). A estrutura de repetio while repete as instrues associadas a ela (seu bloco de comandos) enquanto o resultado da condio entre parnteses for verdadeiro. A palavra especial true sempre verdadeiro, assim as instrues entre chaves executaro indefinidamente, tanto quanto queiramos. Voc aprender mais a respeito da instruo while no Captulo IV.

Resumo
Neste captulo voc aprendeu a respeito de variveis. Variveis so muito teis, mas, devido s restries do rob, elas so um pouco limitadas. Voc pode definir somente 32 variveis e elas podem armazenar somente inteiros. Mas para muitas tarefas realizadas por robs isso bom o suficiente. Voc tambm aprendeu a criar nmeros randmicos, tais que se pode dar ao rob um comportamento imprevisvel. Finalmente, vimos o uso da estrutura de repetio while para criar um loop infinito que executa indefinidamente.

- 13 -

IV. Estruturas de controle


No captulo anterior vimos as instrues repeat e while. Essas instrues controlam a maneira com que outras instrues so executadas em um programa. Elas so chamadas estruturas de controle. Neste captulo veremos algumas outras estruturas de controle.

A instruo if
s vezes voc deseja que uma parte especfica do seu programa seja executada somente em certas situaes. Em casos semelhantes a esse que a instruo if utilizada. Deixe-me mostrar um exemplo. Iremos modificar novamente o programa que temos utilizado, mas com uma abordagem diferente. Ns queremos que o rob se mova ao longo de uma linha reta e ento efetue um giro para a esquerda ou para a direita. Para fazer isso, ns utilizaremos novamente os nmeros randmicos. Ns pegaremos um nmero randmico entre 0 e 1 (inclusives), isto , o nmero 0 ou o nmero 1. Se o nmero for 0 efetuaremos um giro para a direita; caso contrrio, efetuaremos um giro para a esquerda. Veja o programa:
#define #define TEMPO_DE_MOVIMENTACAO TEMPO_DE_CURVATURA 100 85

task main() { while(true) { OnFwd(OUT_A+OUT_C); Wait(TEMPO_DE_MOVIMENTACAO); if (Random(1) == 0) { OnRev(OUT_C); } else { OnRev(OUT_A); } Wait(TEMPO_DE_CURVATURA); } }

A instruo if se parece um pouco com a instruo while. Caso a condio entre parnteses seja verdadeira, a parte entre chaves ser executada. Caso falso, a parte entre as chaves aps a palavra-chave else ser executada. Vamos olhar um pouco melhor a condio que utilizamos: Random(1) == 0. Isso significa que Random(1) deve ser igual a 0 para fazer a condio verdadeira. Voc poderia pensar por que utilizamos = = ao invs de =. A razo para diferenci-lo daquelas instrues que atribuem valores a uma varivel. Voc pode comparar valores de diferentes maneiras. A seguir so apresentadas as mais importantes: == < <= > >= != igual a menor do que menor ou igual a maior do que maior ou igual a diferente (no igual a)

Voc pode combinar condies usando &&, que significa e ou ||, que significa ou. Aqui temos alguns exemplos de condies:
true sempre verdadeiro false nunca verdadeiro (falso) ttt != 3 verdadeiro quanto ttt for diferente de 3 (ttt >= 5) && (ttt <= 10) verdadeiro quando ttt estiver entre 5 e 10 (inclusives) (aaa == 10) || (bbb == 10) verdadeiro tanto se aaa ou bbb (ou ambos) forem iguais a 10

- 14 -

Observe que a instruo if tem duas partes. A parte imediatamente aps a condio, que executada quando a condio verdadeira, e a parte aps else, que executada quando a condio falsa. A palavra-chave else e a parte aps a mesma so opcionais. Ento, pode-se fazer nada caso a condio seja falsa.

A instruo do
Existe outra estrutura de controle, a instruo do. Ela tem a seguinte forma geral:
do { instrues; } while (condio);

As instrues entre as chaves aps o do so executadas enquanto a condio for verdadeira. A condio tem a mesma forma daquela utilizada nas instrues if, conforme descrito acima. Aqui temos um exemplo de um programa. O rob se movimenta de maneira aleatria por 20 segundos e ento pra.
int tempo_de_movimentacao, tempo_de_curvatura, tempo_total; task main() { tempo_total = 0; do { tempo_de_movimentacao = Random(100); tempo_de_curvatura = Random(100); OnFwd(OUT_A+OUT_C); Wait(tempo_de_movimentacao); OnRev(OUT_C); Wait(tempo_de_curvatura); tempo_total += tempo_de_movimentacao; tempo_total += tempo_de_curvatura; } while (tempo_total < 2000); Off(OUT_A+OUT_C); }

Podemos notar que neste exemplo existem duas instrues em uma nica linha. Isto permitido. Voc pode colocar tantas instrues em uma nica linha quantas voc quiser (desde que separe cada instruo por um ponto-e-vrgula). Mas por questes de legibilidade do programa, isso freqentemente no uma boa idia. Observe, tambm, que a instruo do se comporta de maneira semelhante instruo while. A diferena que na estrutura while a condio testada antes de executar suas instrues, enquanto que na estrutura do a condio testada no fim. Em uma instruo while, pode acontecer do bloco de comandos nunca ser executado, mas na instruo do o bloco de comandos executado pelo menos uma vez.

Resumo
Neste captulo vimos duas estruturas de controle novas: a instruo if e a instruo do. Juntamente com as instrues repeat e while, elas so as instrues que controlam a maneira com que o programa executado. muito importante que voc entenda o que elas fazem. Sendo assim, seria bom que voc tentasse mais alguns exemplos desenvolvidos por voc mesmo antes de continuar. Vimos, tambm, que podemos colocar vrias instrues em uma mesma linha.

- 15 -

V. Sensores
Um dos aspectos interessantes dos robs Lego que voc pode conectar a eles sensores e fazer o rob reagir a esses sensores. Antes de mostrar como fazer isto, devemos modificar o rob que temos utilizado um pouco, por intermdio da instalao de um sensor. Para isso, monte o sensor conforme apresentado na figura 4 da pgina 28 do construpedia. Voc deve fazer isto de maneira ligeiramente diferente, de tal modo que o rob se parea com a figura abaixo:

Conecte o sensor na entrada 1 do RCX.

Esperando por um sensor


Iniciaremos com um programa simples em que o rob se move para frente at que ele bata em algo. Aqui est:
task main() { SetSensor(SENSOR_1,SENSOR_TOUCH); OnFwd(OUT_A+OUT_C); until (SENSOR_1 == 1); Off(OUT_A+OUT_C); }

//entrada 1 um sensor de toque //espera SENSOR_1 se tornar 1

Existem duas linhas importantes aqui. A primeira delas nos diz o tipo de sensor que ns estamos usando. SENSOR_1 o nmero da entrada em que o sensor est conectado. As outras duas entradas so denominadas SENSOR_2 e SENSOR_3. SENSOR_TOUCH indica que se trata de um sensor de toque. Para o sensor de luz ns utilizaramos SENSOR_LIGHT. Aps termos especificado o tipo de sensor, o programa liga os dois motores e o rob se movimenta para frente. A prxima instruo (until) uma construo muito til. Ela aguarda at que a condio definida entre parnteses seja verdadeira. Essa condio diz que o valor do SENSOR_1 deve ser 1, o que significa que o sensor est pressionado. To logo o sensor seja liberado (deixe de estar pressionado), o valor se torna 0. Ento, esta instruo aguarda at que o sensor seja pressionado (a tarefa fica parada neste ponto aguardando a condio ser satisfeita). Quando isso ocorre os motores so desligados e a tarefa finalizada.

Respondendo a um sensor de toque


Deixe-nos tentar fazer um rob desviar de obstculos. Caso o rob bata em um objeto, ns o instruiremos a se mover para traz, efetuar um giro e ento continuar. Um programa para essas tarefas se parece com:

- 16 -

task main() { SetSensor(SENSOR_1,SENSOR_TOUCH); OnFwd(OUT_A+OUT_C); while (true) { if (SENSOR_1 == 1) { OnRev(OUT_A+OUT_C); Wait(30); OnFwd(OUT_A); Wait(30); OnFwd(OUT_A+OUT_C); } } }

Tal como apresentado no exemplo anterior, primeiro indicaremos o tipo de sensor. Em seguida o rob inicia seu movimento para frente. No loop infinito while, verificaremos continuamente se o sensor foi acionado e, em caso verdadeiro, o rob se mover para trs por um tempo de 1/3 de segundo, mover para a direita pelo mesmo perodo de tempo (1/3 de segundo) e ento continuar se movimentando para frente.

Sensores de luz
Alm dos sensores de toque, o kit Lego Mindstorms possui sensores de luz. O sensor de luz mede a quantidade de luz em uma determinada direo. Alm disso, esse sensor emite luz. Sendo assim, possvel apontar o sensor para uma determinada direo e fazer a distino entre a intensidade de luz refletida por um objeto existente naquela direo. Em particular, isso til quando se tenta fazer um rob seguir uma linha existente no cho. Isso o que faremos no prximo exemplo. Primeiramente precisamos encaixar o sensor de luz no rob de tal modo que o sensor fique posicionado no meio do rob, apontando para baixo. Conecte-o na entrada 2. Por exemplo, faa uma construo conforme ilustrado abaixo:

Precisaremos tambm da pista que vem com o kit. (Aquele pedao grande de papel com uma trilha preta nele.) A idia agora que o rob mantenha o sensor de luz sobre a trilha. Caso a intensidade do sensor de luz aumentar, significa que o sensor saiu da trilha e precisaremos ajustar a direo. A seguir apresentado um exemplo simples de como fazer isso, porm somente funciona se o rob seguir a trilha no sentido horrio.

- 17 -

#define VALOR_LIMITE 40 task main() { SetSensor(SENSOR_2,SENSOR_LIGHT); OnFwd(OUT_A+OUT_C); while (true) { if (SENSOR_2 > VALOR_LIMITE) { OnRev(OUT_C); until (SENSOR_2 <= VALOR_LIMITE); OnFwd(OUT_A+OUT_C); } } }

O programa indica, inicialmente, que o sensor 2 um sensor de luz. Em seguida, ele configura o rob para se mover para frente e entra em um loop infinito. Caso o valor lido pelo sensor seja maior do que 40 (utilizamos uma constante aqui de modo que seja fcil modificar o programa no caso de exposio do rob a ambientes com grande variedade de luminosidade) revertemos o sentido de rotao de um dos motores (OUT_C) e aguardamos at que o rob retorne trilha. Como poder ser observado quando o programa for executado, a movimentao no muito regular. Tente adicionar um comando Wait(10) antes da instruo until de modo a fazer o rob se mover de maneira melhor. Observe que o programa no funciona para a movimentao no sentido anti-horrio. Para permitir uma movimentao em caminhos arbitrrios, faz-se necessrio um programa mais complicado.

Resumo
Neste captulo foi visto como trabalhar com sensores de toque e de luz. Tambm vimos o comando until que til quando se usa sensores. Eu sugiro que voc escreva uma variedade de programas com os conceitos vistos at este momento. Voc tem agora todos os ingredientes necessrios para dar ao rob comportamentos bastante complexos. Por exemplo, tente colocar dois sensores de toque no rob, um na parte frontal esquerda e o outro na parte frontal direita, e o faa se afastar dos obstculos que porventura ele se choque. Alm disso, tente manter o rob em uma rea delimitada por uma linha preta no cho.

- 18 -

VI. Tarefas e sub-rotinas


At agora todos os nossos programas consistiam de uma nica tarefa. Entretanto, os programas em NQC podem ter mltiplas tarefas. tambm possvel colocar pedaos de cdigo em sub-rotinas que podero ser utilizadas em diferentes lugares em um programa. Usar tarefas e sub-rotinas torna os programas mais fceis de entender e mais compactos. Neste captulo veremos as vrias possibilidades.

Tarefas
Um programa NQC pode possuir no mximo 10 tarefas. Cada tarefa tem um nome. Uma das tarefas deve ter o nome main (tarefa principal), e ser automaticamente executada. As outras tarefas sero executes somente quando uma tarefa em execuo pedir para elas executem, por intermdio do comando start. A partir deste ponto, as duas tarefas estaro sendo executadas simultaneamente (devido ao fato da primeira tarefa continuar em execuo). Uma tarefa em execuo pode finalizar a execuo de outra tarefa por meio do comando stop. Posteriormente, essa tarefa poder ser reiniciada novamente, mas iniciar a execuo do incio e no a partir do ponto em que foi finalizada. Deixe-me demonstrar o uso de tarefas. Coloque novamente o sensor de toque no rob. Desejamos fazer um programa em que o rob se movimenta em um caminho com a forma de um quadrado, como anteriormente. No entanto, quando o rob chocar com um obstculo ele dever reagir ao obstculo. difcil fazer isto em uma nica tarefa, devido ao fato do rob necessitar fazer duas coisas ao mesmo tempo: movimentar-se (isto , ligar e desligar os motores na hora certa) e responder aos sensores. Ento, o melhor a fazer utilizar duas estratgias para isso, onde uma delas controla o movimento em forma de quadrado e a outra reage aos sensores. Segue um exemplo.
task main() { SetSensor(SENSOR_1,SENSOR_TOUCH); start verificarSensores; start movimentarEmQuadrados; } task movimentarEmQuadrados() { while (true) { OnFwd(OUT_A+OUT_C); Wait(100); OnRev(OUT_C); Wait(85); } } task verificarSensores() { while (true) { if (SENSOR_1 == 1) { stop movimentarEmQuadrados; OnRev(OUT_A+OUT_C); Wait(50); OnFwd(OUT_A); Wait(85); start movimentarEmQuadrados; } } }

A tarefa main simplesmente define o tipo de sensor e ento inicializa as outras tarefas. Aps isso, a tarefa main finalizada. A tarefa movimentarEmQuadrados move o rob continuamente em um circuito com a forma de um quadrado. A tarefa verificarSensores verifica se o sensor de toque pressionado. Caso tenha sido, ele responde com as seguintes aes: antes de tudo ele pra a tarefa movimentarEmQuadrados. Isso muito importante. verificarSensores agora possui o controle sobre as movimentaes do rob. Em seguida, ela move o rob um pouco para trs e o faz girar. Agora ela pode iniciar novamente a tarefa

- 19 -

movimentarEmQuadrados para possibilitar que o rob se movimente em um caminho com a forma de um

quadrado. muito importante lembrar que todas as tarefas que voc inicia esto sendo executadas ao mesmo tempo. Isso pode levar a resultados inesperados. O Captulo X explica esses problemas em detalhes e oferece solues para eles.

Sub-rotinas
s vezes voc precisa que um mesmo pedao de cdigo seja utilizado em vrios lugares em um programa. Nesse caso, voc pode colocar o pedao de cdigo em uma sub-rotina e lhe dar um nome. Agora voc pode executar esse pedao de cdigo simplesmente efetuando uma chamada ao seu nome dentro de uma tarefa. NQC (ou melhor, o RCX) permite at 8 sub-rotinas. Vamos ver um exemplo.
sub darVoltas() { OnRev(OUT_C); Wait(340); OnFwd(OUT_A+OUT_C); } task main() { OnFwd(OUT_A+OUT_C); Wait(100); darVoltas(); Wait(200); darVoltas(); Wait(100); darVoltas(); Off(OUT_A+OUT_C); }

Neste programa definimos uma sub-rotina que faz o rob dar voltar em torno de si mesmo. A tarefa main efetua uma chamada a essa rotina trs vezes. Observe que efetuamos uma chamada sub-rotina por meio da escrita de seu nome seguido de um par de parnteses. Isso se parece bastante com os demais comandos que temos visto. A diferena uma sub-rotina no pode definir parmetros, o que implica em nunca termos algo entre os parnteses de uma sub-rotina. So necessrios alguns esclarecimentos antes de continuarmos. Sub-rotinas so um pouco estranhas. Por exemplo, sub-rotinas no podem ser chamadas a partir de outras sub-rotinas. Por outro lado, sub-rotinas podem ser chamadas a partir de diferentes tarefas, entretanto isto no indicado. muito fcil ocorrerem problemas devido a duas tarefas distintas tentarem, ao mesmo tempo, executar uma mesma sub-rotina. Isso leva a efeitos indesejveis. Alm disso, quando se efetua chamadas a uma mesma sub-rotina a partir de tarefas distintas, devido a uma limitao do firmware do RCX, voc fica impedido de utilizar expresses complicadas (nesse caso, no se pode ter variveis locais ou efetuar clculos que requerem variveis temporrias). Ento, a menos que voc tenha certeza do que est fazendo, no efetue chamadas a uma sub-rotina a partir de diferentes tarefas!

Funes inline
Conforme citado acima, sub-rotinas causam certos problemas. A parte boa que elas so armazenadas somente uma vez no RCX. Isso gasta menos memria e, pelo fato do RCX ter pouca memria livre, isso til. Mas quando as sub-rotinas so pequenas, o melhor a fazer utilizar funes inline. Elas no so armazenadas separadamente, mas copiadas para cada lugar em que so utilizadas. Isso gasta mais memria, mas os problemas citados anteriormente relacionados a expresses complicadas deixam de existir. Alm disso, no existe um limite para a quantidade de funes inline. Definir e chamar funes inline ocorre exatamente da mesma maneira que sub-rotinas. A nica diferena a utilizao da palavra-chave void ao invs de sub. (A palavra void utilizada devido ao fato dessa mesma palavra ser usada em outras linguagens, tal como C, quando uma funo no retorna um valor. As funes em NQC no retornam valor.) Desse modo, o programa acima, com o uso de funes inline, seria assim:

- 20 -

void darVoltas() { OnRev(OUT_C); Wait(340); OnFwd(OUT_A+OUT_C); } task main() { OnFwd(OUT_A+OUT_C); Wait(100); darVoltas(); Wait(200); darVoltas(); Wait(100); darVoltas(); Off(OUT_A+OUT_C); }

Funes inline tm outra vantagem sobre sub-rotinas. Elas podem ter parmetros. Argumentos podem ser usados para passar um valor para certas variveis definidas na funo inline. Por exemplo, assuma, no exemplo acima, que podemos tornar o tempo de giro um parmetro para a funo, conforme apresentado abaixo:
void darVoltas(int tempoDeGiro) { OnRev(OUT_C); Wait(tempoDeGiro); OnFwd(OUT_A+OUT_C); } task main() { OnFwd(OUT_A+OUT_C); Wait(100); darVoltas(200); Wait(200); darVoltas(50); Wait(100); darVoltas(300); Off(OUT_A+OUT_C); }

Observe que foi especificado entre os parnteses associados funo inline o parmetro da funo. Neste caso ns indicamos que o argumento dever ser um inteiro (existem outras opes) e o nome do parmetro tempoDeGiro. Quando existem mais parmetros, os mesmos devem vir separados por vrgulas.

Definindo macros
Existe ainda outra maneira de associar um nome a pequenos pedaos de cdigo. Voc pode definir macros em NQC (no confunda com os macros do RCX Command Center). Foi visto que podemos definir constantes usando a instruo #define, dando-as um nome. Mas na verdade ns podemos definir qualquer pedao de cdigo. A seguir apresentado o mesmo programa anterior com a definio de uma macro para executar as aes existentes em darVoltas.

- 21 -

#define darVoltas OnRev(OUT_C);Wait(340);OnFwd(OUT_A+OUT_C); task main() { OnFwd(OUT_A+OUT_C); Wait(100); darVoltas; Wait(200); darVoltas; Wait(100); darVoltas; Off(OUT_A+OUT_C); }

Aps a instruo #define a palavra darVoltas representa o texto que a segue. Agora caso voc digite darVoltas, essa palavra ser substituda por este texto. Observe que o texto deve estar em uma nica linha. (Na verdade existem maneiras de colocar uma instruo #define em mltiplas linhas, mas no recomendado.) Instrues #define so realmente muito mais poderosas. Elas tambm podem ter parmetros. Por exemplo, podemos colocar o tempo de giro como um parmetro na instruo. Aqui ser apresentado um exemplo em que definimos quatro macros: uma para mover o rob para frente, uma para mover para trs, uma para virar esquerda e outra para virar direita.
#define #define #define #define virarDireita(s,t) SetPower(OUT_A+OUT_C,s);OnFwd(OUT_A);OnRev(OUT_C);Wait(t); virarEsquerda(s,t) SetPower(OUT_A+OUT_C,s);OnRev(OUT_A);OnFwd(OUT_C);Wait(t); frente(s,t) SetPower(OUT_A+OUT_C,s);OnFwd(OUT_A+OUT_C);Wait(t); tras(s,t) SetPower(OUT_A+OUT_C,s);OnRev(OUT_A+OUT_C);Wait(t);

task main() { frente(3,200); virarEsquerda(7,85); frente(7,100); tras(7,200); frente(7,100); virarDireita(7,85); frente(3,200); Off(OUT_A+OUT_C); }

muito til definir macros. Isso faz o seu cdigo mais compacto e legvel. Alm do mais, voc pode modificar seu cdigo facilmente quando, por exemplo, voc modificar as conexes dos motores.

Resumo
Neste captulo vimos o uso de tarefas, sub-rotinas, funes inline e macros. Elas tm utilidades distintas. As tarefas executam simultaneamente e tratam coisas distintas que tm que ser feitas ao mesmo tempo. Sub-rotinas so teis quando grandes pedaos de cdigo devem estar em diferentes lugares em uma mesma tarefa. Funes inline so teis quando pedaos de cdigo devem ser usados em vrios locais em diferentes tarefas, porm com um consumo adicional de memria. Finalmente, macros so muito teis para pequenos pedaos de cdigo que devem ser usados em diferentes locais. Eles tambm podem conter parmetros, o que os torna mais teis. Agora que voc chegou at aqui, voc possui todo tipo de conhecimento para fazer seu rob executar tarefas complexas. Os demais captulos deste tutorial o ensinaro a respeito de outras coisas que so importantes somente em certas aplicaes.

- 22 -

VII. Criando msicas


O RCX tem um alto-falante embutido que pode produzir sons e assim tocar pedaos de msicas simples. Isto , em particular, til quando voc quiser fazer o RCX dizer o que est acontecendo. Mas pode ser divertido ter um rob que toca msica enquanto se movimenta

Sons pr-programados
Existem seis sons pr-programados no RCX, numerados de 0 a 5, conforme apresentado a seguir: 0 1 2 3 4 5 Pressionamento de tecla Beep beep Mudana de freqncia decrescente Mudana de freqncia crescente Som de erro (Buhhh) Mudana crescente rpida

Voc pode tocar estes sons por meio do comando PlaySound(). Aqui temos um pequeno programa que toca todos eles.
task main() { PlaySound(0); PlaySound(1); PlaySound(2); PlaySound(3); PlaySound(4); PlaySound(5); }

Wait(100); Wait(100); Wait(100); Wait(100); Wait(100); Wait(100);

Voc pode se perguntar por que existem estes comandos Wait. A razo que o comando que toca o som no espera pelo seu trmino. Ele imediatamente executa o prximo comando. O RCX tem um pequeno buffer em que ele armazena sons, mas aps um tempo este buffer enche e os sons so perdidos. Isso no faz muita diferena para sons, mas muito importante para msicas, como veremos a seguir. Observe que o argumento para PlaySound() deve ser uma constante. Voc no pode utilizar uma varivel aqui!

Tocando msica
Para msicas mais interessantes, o NQC tem o comando PlayTone(). Ele tem dois parmetros. O primeiro deles a freqncia e o segundo a durao (em ticks de 1/100 segundos, tal como no comando Wait). Abaixo temos uma tabela de freqncias teis: Sound G# G F# F E D# D C# C B A# A 1 52 49 46 44 41 39 37 35 33 31 29 28 2 104 98 92 87 82 78 73 69 65 62 58 55 3 208 196 185 175 165 156 147 139 131 123 117 110 4 415 392 370 349 330 311 294 277 262 247 233 220 5 831 784 740 698 659 622 587 554 523 494 466 440 6 1661 1568 1480 1397 1319 1245 1175 1109 1047 988 932 880 7 3322 3136 2960 2794 2637 2489 2349 2217 2093 1976 1865 1760 8

4186 3951 3729 3520

Conforme citado anteriormente com relao aos sons, aqui tambm o RCX no espera uma nota terminar. Assim sendo, caso voc use vrias notas, o melhor a fazer adicionar comandos Wait entre elas (fica um pouco maior). Eis um exemplo:

- 23 -

task main() { PlayTone(262,40); PlayTone(294,40); PlayTone(330,40); PlayTone(294,40); PlayTone(262,160); }

Wait(50); Wait(50); Wait(50); Wait(50); Wait(200);

Voc pode criar pedaos de msicas muito facilmente utilizando o RCX Piano que parte do RCX Command Center. Caso voc queira que o RCX toque uma msica enquanto se movimenta, o melhor a fazer separar uma tarefa para isso. A seguir apresentado um exemplo de um programa bastante simples onde o rob se move constantemente para frente e para trs, tocando uma msica.
task tocarMusica() { while (true) { PlayTone(262,40); PlayTone(294,40); PlayTone(330,40); PlayTone(294,40); } }

Wait(50); Wait(50); Wait(50); Wait(50);

task main() { start tocarMusica; while(true) { OnFwd(OUT_A+OUT_C); Wait(300); OnRev(OUT_A+OUT_C); Wait(300); } }

Resumo
Neste captulo voc aprendeu como fazer o RCX produzir sons e msicas. Alm disso, foi mostrado como usar uma tarefa especfica para tocar msica.

- 24 -

VIII. Mais a respeito de motores


Existem inmeros comandos adicionais que voc pode utilizar para controlar os motores de maneira mais precisa. Neste captulo ns discutiremos isso.

Parando suavemente
Quando voc utiliza o comando Off(), o motor para imediatamente, usando freios. Em NQC tambm possvel para os motores de maneira suave, sem utilizar freios. Para esse propsito utilizamos o comando Float(). s vezes isso melhor para a tarefa que o rob est executando. Utilizemos o seguinte exemplo. Primeiramente o rob pra usando freios; depois faz o mesmo sem usar os freios. Observe a diferena. (Provavelmente a diferena seja bastante sutil para o rob que estamos usando. Entretanto pode fazer uma grande diferena para outros tipos de robs.)
task main() { OnFwd(OUT_A+OUT_C); Wait(200); Off(OUT_A+OUT_C); Wait(100); OnFwd(OUT_A+OUT_C); Wait(200); Float(OUT_A+OUT_C); }

Comandos avanados
Na verdade, o comando OnFwd() faz duas coisas: ele liga o motor e configura sua direo para frente. O comando OnRev() tambm faz duas coisas: ele liga o motor e configure a direo no sentido reverso. O NQC tambm tem comandos para fazer essas coisas separadamente. Se voc quiser mudar somente uma de duas coisas, mais eficiente utilizar esses comandos em separado; isso faz uso de menos memria no RCX, mais rpido e pode resultar em movimentos mais suaves. Os dois comandos separados so SetDirection() que configura a direo (OUT_FWD, OUT_REV ou OUT_TOGGLE nos quais troca a direo atual) e SetOutput() que define o modo (OUT_ON, OUT_OFF ou OUT_FLOAT). A seguir apresentado um programa simples que faz o rob se mover para frente, para trs e para frente de novo.
task main() { SetPower(OUT_A+OUT_C,7); SetDirection(OUT_A+OUT_C,OUT_FWD); SetOutput(OUT_A+OUT_C,OUT_ON); Wait(200); SetDirection(OUT_A+OUT_C,OUT_REV); Wait(200); SetDirection(OUT_A+OUT_C,OUT_TOGGLE); Wait(200); SetOutput(OUT_A+OUT_C,OUT_FLOAT); }

Cabe observar que no incio de todos os programas, todos os motores so configurados automaticamente para se moverem para frente e a velocidade definida em 7. Sendo assim, no exemplo acima os dois primeiros comandos so desnecessrios. Existem vrios outros comandos para controlar os motores, nos quais consistem de uma abreviao da combinao dos comandos apresentados anteriormente. A seguir apresentada uma lista completa:
On(motores) Off(motores) Float(motores) Fwd(motores) Rev(motores) Toggle(motores)

Liga o motor Desliga o motor Desliga os motores sem frenagem Configura o motor na direo frente (no o coloca em movimento) Configura o motor na direo trs (no o coloca em movimento) Muda a direo do motor (frente para trs e vice-versa)

- 25 -

OnFwd(motores) OnRev(motores) OnFor(motores,ticks) SetOutput(motores,modo) SetDirection(motores,dir) SetPower(motores,potencia)

Configura o motor na direo frente e o coloca em movimento Configura o motor na direo trs e o coloca em movimento Liga os motores por um perodo de tempo em ticks (100 ticks = 1s) Configura a sada (OUT_ON, OUT_OFF ou OUT_FLOAT) Configura a direo da sada (OUT_FWD, OUT_REV ou OUT_TOGGLE) Configura a potncia da sada (0-7)

Variando a velocidade de rotao do motor


Como voc provavelmente observou, mudar a velocidade dos motores no tem muito efeito. A razo que voc est variando o torque e no a velocidade de rotao. Voc somente perceber algum efeito quando o motor tiver uma grande carga. E, mesmo assim, a diferena entre 2 e 7 bem pequena. Caso voc queira alcanar efeitos melhores a dica ligar e desligar os motores sucessivamente de maneira bem rpida. Abaixo temos um exemplo de como fazer isso. Existe uma tarefa chamada moverMotor que responsvel por colocar o motor em movimentao. Ela constantemente verifica a varivel velocidade para ver qual o seu valor. Valores positivos indicam frente e valores negativos indicam trs. Ela configura o motor na direo correta e aguarda por algum tempo, dependendo da velocidade, antes que o motor seja desligado novamente. A tarefa main simplesmente configura a velocidade e aguarda.
int velocidade, __velocidade; task moverMotor() { while (true) { __velocidade = velocidade; if (__velocidade > 0) {OnFwd(OUT_A+OUT_C);} if (__velocidade < 0) {OnRev(OUT_A+OUT_C); __velocidade = -__velocidade;} Wait(__velocidade); Off(OUT_A+OUT_C); } } task main() { velocidade = 0; start moverMotor; velocidade = 1; velocidade = -10; velocidade = 5; velocidade = -2; stop moverMotor; Off(OUT_A+OUT_C); }

Wait(200); Wait(200); Wait(200); Wait(200);

Este programa pode se tornar muito mais poderoso, permitindo rotaes, e tambm possivelmente incorporando um tempo de espera antes do comando Off(). Experimente voc mesmo.

Resumo
Neste captulo voc aprendeu a respeito de comandos extras disponveis relacionados a motores: Float() que para o motor de maneira suave, SetDirection() que define a direo (OUT_FWD, OUT_REV ou OUT_TOGGLE nos quais inverte a direo atual) e SetOutput() que define o modo (OUT_ON, OUT_OFF ou OUT_FLOAT). Voc viu a lista completa dos comandos relacionados a motores disponveis. Voc tambm aprendeu um truque para controlar a velocidade dos motores de uma maneira melhor.

- 26 -

IX. Mais a respeito de sensores


No Captulo V ns discutimos os aspectos bsicos relacionados a sensores. Entretanto, existe muito mais que voc pode fazer com sensores. Neste captulo discutiremos as diferenas entre modo e tipo de sensores, veremos como usar o sensor de rotao (um tipo de sensor que no vem com o RIS, mas pode ser comprado separadamente e muito til), veremos alguns truques para usar mais do que trs sensores e faremos um sensor de proximidade.

Modo e tipo de sensores


O comando SetSensor() que ns vimos anteriormente faz duas coisas: define o tipo e o modo de operao do sensor. Configurar o modo e o tipo de um sensor de maneira separada possibilita uma maior preciso no controle do comportamento do sensor, o que til para algumas aplicaes. O tipo do sensor definido com o comando SetSensorType(). Existem quatro tipos diferentes: SENSOR_TYPE_TOUCH, para sensor de toque, SENSOR_TYPE_LIGHT, para sensor de luz, SENSOR_TYPE_TEMPERATURE, para sensor de temperatura (este tipo de sensor no faz parte do kit, mas pode ser comprado separadamente) e SENSOR_TYPE_ROTATION, para o sensor de rotao (tambm no faz parte do kit disponvel separadamente). Configurar o tipo de um sensor em particular importante para indicar se o sensor necessita de energia (tal como, por exemplo, para a luz do sensor de luz). Eu desconheo alguma utilidade em se colocar um sensor em um tipo diferente daquele que ele . O modo do sensor definido com o comando SetSensorMode(). Existem oito modos diferentes. O mais importante deles o SENSOR_MODE_RAW. Nesse modo, o valor que se obtm quando se faz a leitura do sensor um nmero compreendido entre 0 e 1023. o valor bruto produzido pelo sensor. O que ele representa depende do sensor em uso. Por exemplo, para um sensor de toque, quando o sensor est em repouso (no pressionado) o valor prximo de 1023. Quando ele estiver totalmente pressionado, o valor prximo de 50. Quando estiver parcialmente pressionado o valor se encontra na faixa entre 50 e 1000. Ento, caso voc configure um sensor de toque no modo bruto, voc pode realmente verificar se ele est parcialmente pressionado. Quando o sensor um sensor de luz, a faixa de valores vai de 300 (muita luz) at 800 (muito escuro). Isso nos d um valor muito mais preciso do que quando utilizamos o comando SetSensor(). O prximo modo SENSOR_MODE_BOOL. Nesse modo o valor 0 ou 1. Quando o valor bruto lido for menor do que 550 o valor 0; maior 1. SENSOR_MODE_BOOL o modo padro do sensor de toque. Os modos SENSOR_MODE_CELSIUS e SENSOR_MODE_FAHRENHEIT so teis somente para os sensores de temperatura e apresentam a temperatura na maneira indicada (Celsius ou Fahrenheit). SENSOR_MODE_PERCENT apresenta um valor bruto entre 0 e 100. Todo valor menor ou igual a 400 mapeado para 100 por cento. Caso o valor seja maior do que 400, a porcentagem vagarosamente se torna 0. SENSOR_MODE_PERCENT o modo padro para o sensor de luz. SENSOR_MODE_ROTATION parece ser til somente para o sensor de rotao (ver abaixo). Existem dois outros modos interessantes: SENSOR_MODE_EDGE e SENSOR_MODE_PULSE. Eles contam transies, isto , mudanas de valores altos para valores baixos ou vice-versa. Por exemplo, quando voc pressiona um sensor de toque, isso causa uma transio de um valor bruto alto para um valor baixo. Quando voc libera o sensor, voc gera uma transio na outra direo (valor baixo para alto). Quando voc define o modo do sensor para SENSOR_MODE_PULSE, somente transies de um valor baixo para um valor alto sero contadas. Ento, cada toque e liberao em um sensor de toque contam como uma nica transio. Quando voc configura o modo do sensor para SENSOR_MODE_EDGE, ambas as transies so contadas. Ento, cada toque e liberao em um sensor de toque contam como duas transies. Voc pode utilizar isso para contar a freqncia com que um sensor de toque foi pressionado. Ou voc pode us-lo em combinao com um sensor de luz para contar a freqncia com que uma lmpada acessa e apagada. Normalmente, quando se est contando coisas desejvel zerar o contador. O comando ClearSensor() utilizado para esse propsito. Ele zera o contador para os sensores indicados. Vamos analisar um exemplo. O seguinte programa usa um sensor de toque para guiar o rob. Conecte o sensor de toque com um cabo longo na entrada 1. Caso o sensor de toque seja tocado rapidamente duas vezes o rob se movimente para frente. Caso seja tocado somente uma vez ele pra.

- 27 -

task main() { SetSensorType(SENSOR_1,SENSOR_TYPE_TOUCH); SetSensorMode(SENSOR_1,SENSOR_MODE_PULSE); while(true) { ClearSensor(SENSOR_1); until (SENSOR_1 > 0); Wait(100); if (SENSOR_1 == 1) {Off(OUT_A+OUT_C);} if (SENSOR_1 == 2) {OnFwd(OUT_A+OUT_C);} } }

Observe que primeiramente configuramos o tipo e o modo do sensor. Parece que isso essencial, pois ao mudar o tipo tambm afetamos o modo de operao.

O sensor de rotao
O sensor de rotao um tipo de sensor muito til, porm infelizmente no faz parte do kit padro. Ele pode ser comprado separadamente diretamente na Lego. O sensor de rotao tem um orifcio onde se pode colocar um eixo. O sensor de rotao mede a quantidade de vezes que aquele eixo gira. Uma rotao complete do eixo contm 16 passos (ou -16 caso voc rode no sentido contrrio). Sensores de rotao so mais teis para controlar os movimentos do rob de maneira mais precisa. Voc pode fazer um eixo girar a quantia exata que voc quiser. Se voc quiser um controle com preciso maior do que 16 passos, voc pode utilizar engrenagens, conect-las a um eixo que se mova mais rpido e us-la para contar os passos. Uma aplicao bsica utiliza dois sensores de rotao conectados a duas rodas de um rob que voc controla por intermdio de dois motores. Para um movimento em linha reta voc deseja que ambas as rodas girem na mesma velocidade. Infelizmente, os motores no giram exatamente na mesma velocidade. Usando sensores de rotao voc pode constatar isso. Voc pode, temporariamente, parar o motor que gira mais rpido (melhor se usar Float()) at que ambos os sensores possuam o mesmo valor. O programa abaixo faz isso. Ele simplesmente faz o rob se movimentar em linha reta. Para utiliz-lo, modifique seu rob, conectando dois sensores de rotao s duas rodas. Conecte os sensores nas entras 1 e 3.
task main() { SetSensor(SENSOR_1,SENSOR_ROTATION); ClearSensor(SENSOR_1); SetSensor(SENSOR_3,SENSOR_ROTATION); ClearSensor(SENSOR_3); while (true) { if (SENSOR_1 < SENSOR_3) {OnFwd(OUT_A); Float(OUT_C);} else if (SENSOR_1 > SENSOR_3) {OnFwd(OUT_C); Float(OUT_A);} else {OnFwd(OUT_A+OUT_C);} } }

O programa inicialmente indica que ambos os sensores so de rotao e estabelece 0 como seus valores de inicializao (por meio do comando ClearSensor). Posteriormente, inicia um loop infinito. No loop verificamos se as leituras dos sensores so iguais. Caso sejam, ele simplesmente move o rob em linha reta. Caso alguma leitura apresente um valor maior, o motor adequado parado at que as leituras apresentem valores iguais. Pode-se observar que o programa bastante simples. Voc pode estend-lo para fazer o rob se movimentar em distncias precisas, ou possibilit-los fazer curvas com preciso.

Colocando vrios sensores em uma nica entrada


O RCX tem somente trs entradas, o que implica que voc s pode conectar trs sensores. Quando voc quer construir robs mais complexos (e voc compra sensores extras) isso pode no ser o suficiente. Felizmente, com alguns truques, voc pode conectar dois sensores (ou at mais) em uma nica entrada.

- 28 -

O mais fcil conectar dois sensores de toque em uma nica entrada. Se um deles (ou ambos) pressionado, o valor ser 1, caso contrrio ser 0. Voc no tem como distinguir qual foi pressionado, mas s vezes isso no necessrio. Por exemplo, quando voc coloca um sensor de toque na frente do rob e outro atrs, voc sabe qual foi tocado com base na direo que o rob est se movendo. Mas voc pode configurar o modo para entrada bruta (veja anteriormente). Agora, voc pode obter muito mais informaes. Se voc estiver com sorte, o valor de leitura do sensor quando pressionado no ser o mesmo para ambos os sensores. Sendo este o caso, voc pode realmente distinguir entre os dois sensores. E, quando ambos so pressionados, voc obtm um valor de leitura bem pequeno (em torno de 30), o que o possibilita detectar essa situao. Voc pode conectar um sensor de toque e um sensor de luz a uma mesma entrada. Defina o tipo para luz (de outro modo o sensor de luz no funcionar). Defina o modo de operao para bruto. Nesse caso, quando o sensor de toque for pressionado voc obter um valor bruto menor que 100. Caso no seja pressionado o valor de leitura do sensor nunca ser menor do que 100. O programa abaixo ilustra essa idia. O rob deve ser equipado com um sensor de luz apontado para baixo, e um anteparo na frente (para identificar quando o rob bateu em algo) conectado ao sensor de toque. Conecte ambos na entrada 1. O rob se mover de maneira aleatria dentro de uma rea de cor clara. Quando o sensor identificar uma linha preta (valor bruto > 750) ele recuar um pouco. Quando o sensor de toque bater em algo (valor bruto menor do que 100) ele far o mesmo. Veja um programa exemplo:
int ttt,tt2; task moverAleatoriamente() { while (true) { ttt = Random(50) + 40; tt2 = Random(1); if (tt2 > 0) { OnRev(OUT_A); OnFwd(OUT_C); Wait(ttt); } else { OnRev(OUT_C); OnFwd(OUT_A);Wait(ttt); } ttt = Random(150) + 50; OnFwd(OUT_A+OUT_C);Wait(ttt); } } task main() { start moverAleatoriamente; SetSensorType(SENSOR_1,SENSOR_TYPE_LIGHT); SetSensorMode(SENSOR_1,SENSOR_MODE_RAW); while (true) { if ((SENSOR_1 < 100) || (SENSOR_1 > 750)) { stop moverAleatoriamente; OnRev(OUT_A+OUT_C);Wait(30); start moverAleatoriamente; } } }

Eu espero que o programa esteja simples. Existem duas tarefas. A tarefa moverAleatoriamente faz o rob se mover de maneira aleatria. A tarefa principal inicialmente inicia moverAleatoriamente, define o sensor e aguarda algo acontecer. Caso a leitura do sensor se torne muito pequeno (sendo tocado) ou muito grande (fora da rea clara), ele pra de se mover aleatoriamente, recua um pouco e inicia a movimentao aleatria novamente. Tambm possvel conectar dois sensores de luz na mesma entrada. O valor bruto estar, de alguma maneira, relacionado com a combinao da quantidade de luz recebida pelos sensores. Mas isso bastante confuso e pode parecer difcil de usar. Conectar outros sensores, tal como rotao e temperatura, parece no ser til.

- 29 -

Fazendo um sensor de proximidade


Usando sensores de toque seu rob pode reagir quando ele bater em algo. Mas seria bastante mais interessante se o rob reagisse antes de bater em algo. Ele saberia que est prximo de um obstculo. Infelizmente, no existem sensores para esse propsito. Existe um truque que podemos usar para fazer isso. O rob tem uma porta de luz infra-vermelha com os quais ele se comunica com o computador, ou com outros robs. (Veremos mais a respeito de comunicao entre robs no Captulo XI.) Acontece que o sensor de luz que vem com o kit muito sensvel luz infra-vermelha. Poderamos, ento, construir um sensor baseado nisso. A idia a seguinte: uma tarefa envia mensagem em infra-vermelho e uma outra tarefa mede as flutuaes na intensidade de luz que so refletidas pelos objetos; quanto maior a flutuao mais perto o rob estar de um objeto. Para usar essa idia, posicione o sensor de luz sobre a porta de luz infra-vermelha do rob, apontando-o para frente. Desse modo ele somente medir a reflexo da luz infra-vermelha. Conecte o sensor na entrada 2. Definiremos o modo do sensor de luz para bruto, de modo a identificarmos as flutuaes da melhor maneira possvel. A seguir apresentado um programa simples que faz o rob se movimentar para frente at que ele se aproxima de um objeto e, devido a isso, o programa o faz girar 90 graus para a direita.
int nivelAnterior; // Para armazenar o nvel anterior

task enviarSinal() { while(true) {SendMessage(0); Wait(10);} } task verificarSinal() { while(true) { nivelAnterior = SENSOR_2; if(SENSOR_2 > nivelAnterior + 200) {OnRev(OUT_C); Wait(85); OnFwd(OUT_A+OUT_C);} } } task main() { SetSensorType(SENSOR_2, SENSOR_TYPE_LIGHT); SetSensorMode(SENSOR_2, SENSOR_MODE_RAW); OnFwd(OUT_A+OUT_C); start enviarSinal; start verificarSinal; }

A tarefa enviarSinal envia 10 sinais de infra-vermelho a cada segundo, usando o comando SendMessage(0). A tarefa verificarSinal armazena o valor lido pelo sensor de luz, repetidamente. Ento, ela verifica se um desses valores maior do que o valor anterior em pelo menos 200 unidades, o que indicaria uma grande flutuao. Caso isso tenha ocorrido, ela faz o rob efetuar um giro de 90 graus para a direita. O valor 200 arbitrrio. Se voc o fizer menor, o rob se desviar mais rapidamente do obstculo, ou seja, notar o objeto a uma distncia maior. Caso seja um valor maior, o rob chegar mais perto antes de notar o objeto. Mas isso tambm depende do tipo de material e da quantidade de luminosidade disponvel no ambiente. Voc deveria experimentar ou utilizar algum mecanismo mais fcil e adequado para aprender a determinar o valor correto. Uma desvantagem da tcnica o fato da mesma funcionar somente quando o rob est se movimentando em uma direo. Voc provavelmente precisar de sensores de toque localizados nas laterais para evitar colises nesses locais. Mas a tcnica muito til para robs que necessitam se locomover em labirintos. Outra desvantagem o fato de no ser possvel estabelecer uma comunicao do computador com o rob porque a mesma ir interferir nas mensagens de infra-vermelho enviadas pelo rob. (O controle remoto da sua televiso provavelmente tambm no funcionar.)

Resumo
Neste captulo foram vistas algumas questes adicionais relacionadas a sensores. Vimos como configurar o tipo e o modo de um sensor de maneira separada, alm de como utilizar para se obter informaes adicionais.

- 30 -

Aprendemos como utilizar um sensor de rotao. Vimos, tambm, como fazer para conectar vrios sensores em uma mesma entrada do RCX. Finalmente, vimos um truque para utilizar a conexo de infra-vermelho e o sensor de luz do rob para criar um sensor de proximidade. Todos esses truques so extremamente teis quando se est construindo robs complexos. Sensores tm sempre um papel crucial nessas construes.

- 31 -

X. Tarefas paralelas
Como citado anteriormente, no NQC as tarefas so executadas simultaneamente, ou em paralelo como as pessoas normalmente dizem. Isso extremamente til, possibilitando-o efetuar a leitura de sensores, enquanto outra tarefa controla a movimentao do rob e, ainda, uma outra tarefa toca alguma msica. Mas tarefas paralelas tambm podem causar problemas. Uma tarefa pode interferir em outra.

Um programa errado
Considere o seguinte programa. Nesse programa uma tarefa controla a movimentao do rob em caminhos com a forma de um quadrado (semelhante ao que foi feito em programas anteriores) e uma segunda tarefa verifica um sensor de toque. Quando o sensor for pressionado, ele mover o rob um pouco para trs e far um giro de 90 graus.
task main() { SetSensor(SENSOR_1,SENSOR_TOUCH); start verificarSensores; while (true) { OnFwd(OUT_A+OUT_C); Wait(100); OnRev(OUT_C); Wait(85); } } task verificarSensores() { while (true) { if (SENSOR_1 == 1) { OnRev(OUT_A+OUT_C); Wait(50); OnFwd(OUT_A); Wait(85); OnFwd(OUT_C); } } }

Provavelmente esse programa se parea perfeito. Mas se voc execut-lo, voc provavelmente observar um comportamento inesperado. Tente o seguinte: faa o rob tocar em algo enquanto ele est girando. Ele comear a se mover para trs, mas imediatamente ele se mover para frente novamente, batendo no obstculo. A razo disso que as tarefas esto interferindo umas nas outras. Olha o que acontece. O rob est girando direita, isto , a primeira tarefa est na sua segunda instruo Wait. Agora, o rob bate com o sensor em algo. Ele comea a se movimentar para trs, mas, ao mesmo tempo, a tarefa main finaliza a espera e move o rob para frente novamente; batendo no obstculo. A segunda tarefa est em espera (instruo Wait) neste momento e, devido a isso, no percebe a coliso. Claramente, isto no o comportamento que gostaramos de ver. O problema que enquanto a segunda tarefa est em espera, no percebemos que a primeira tarefa ainda estava em execuo e que suas aes interferem com as aes da segunda tarefa.

Parando e reiniciando tarefas


Uma maneira de solucionar este problema garantir que a qualquer momento somente uma tarefa estar controlando a movimentao do rob. Esta abordagem foi apresentada no Captulo VI. Deixe repetir o programa aqui.

- 32 -

task main() { SetSensor(SENSOR_1,SENSOR_TOUCH); start verificarSensores; start movimentarEmQuadrados; } task movimentarEmQuadrados () { while (true) { OnFwd(OUT_A+OUT_C); Wait(100); OnRev(OUT_C); Wait(85); } } task verificarSensores() { while (true) { if (SENSOR_1 == 1) { stop movimentarEmQuadrados; OnRev(OUT_A+OUT_C); Wait(50); OnFwd(OUT_A); Wait(85); start movimentarEmQuadrados; } } }

A questo aqui que a tarefa verificarSensores somente move o rob aps ter parado a tarefa movimentarEmQuadrados. Ento, esta tarefa no pode interferir na movimentao de desvio de obstculo. Uma vez que o procedimento de se afastar do objeto termina, ela inicia a tarefa movimentarEmQuadrados de novo. Mesmo acreditando que esta seja uma boa soluo para o problema descrito anteriormente, ainda existe um problema. Quando ns reiniciamos a tarefa movimentarEmQuadrados, ela inicia novamente executando a sua primeira instruo. Isso no traz problemas para o problema em questo, mas freqentemente no o comportamento desejado. Ns preferiramos parar a tarefa em algum ponto e, posteriormente, continuar a sua execuo daquele ponto. Infelizmente isso no pode ser feito de maneira muito fcil.

Usando semforos
Uma tcnica padro utilizada para solucionar este problema utilizar uma varivel para indicar qual tarefa est controlando os motores em um determinado momento. As demais tarefas no conseguem obter o controle dos motores at que a primeira tarefa indique, por intermdio da varivel, que est liberada. Tal varivel freqentemente denominada semforo. Abaixo, sem um semforo. Assumimos que o valor 0 em sem indica que nenhuma tarefa est controlando os motores. Agora, caso alguma tarefa queira fazer algo com os motores ela executa os seguintes comandos:
until (sem == 0); sem = 1; // Faa algo com os motores sem = 0;

Ento, inicialmente, esperamos at que ningum precise dos motores. Quando isso ocorre, obtemos o controle por meio da definio da varivel sem como 1. Agora, podemos controlar os motores. Quando tivermos terminado, definimos sem para 0. Neste ponto, chegamos ao programa acima, implementado com o uso de um semforo. Quando o sensor de toque se choca em algo, o semforo definido em 1 e o procedimento de afastamento do obstculo executado. Durante esse procedimento a tarefa movimentarEmQuadrados deve esperar. No momento que o procedimento termina, o semforo definido em 0 e a tarefa movimentarEmQuadrados pode continuar.

- 33 -

int sem; task main() { sem = 0; start movimentarEmQuadrados; SetSensor(SENSOR_1,SENSOR_TOUCH); while (true) { if (SENSOR_1 == 1) { until (sem == 0); sem = 1; OnRev(OUT_A+OUT_C); Wait(50); OnFwd(OUT_A); Wait(85); sem = 0; } } } task movimentarEmQuadrados () { while (true) { until (sem == 0); sem = 1; OnFwd(OUT_A+OUT_C); sem = 0; Wait(100); until (sem == 0); sem = 1; OnRev(OUT_C); sem = 0; Wait(85); } }

Voc poderia dizer que no necessrio definir o semforo para 1 e de volta para 0 na movimentarEmQuadrados. Todavia, isso til. A razo que o comando OnFwd() de fato dois comandos (veja o Captulo VIII). Voc no quer que esta seqncia de comandos seja interrompida por outra tarefa. Semforos so muito teis e quando se est escrevendo programas complicados com tarefas paralelas eles so quase sempre necessrios. (Existe ainda uma chance mnima de eles falharem. Tente descobrir por que.)

Resumo
Neste captulo estudamos alguns dos problemas que podem ocorrer quando utilizamos vrias tarefas. Esteja sempre atento aos efeitos colaterais. Muitos dos comportamentos inesperados so provenientes disso. Vimos duas maneiras diferentes de solucionar tais problemas. A primeira soluo pra e reinicia tarefas para garantir que somente uma tarefa crtica esteja sendo executada a cada momento. A segunda abordagem utiliza semforos para controlar a execuo das tarefas. Isso garante que a cada momento somente a parte crtica de uma tarefa est em execuo.

- 34 -

XI. Comunicao entre robs


Se voc possui mais de um RCX, este captulo foi feito para voc. Os robs podem se comunicar por meio das portas de infra-vermelho. Usando-as, voc pode ter vrios robs colaborando entre si (ou disputando entre si). Alm disso, voc pode construir um rob maior usando dois RCX, de modo a ter seis motores e seis sensores (ou at mais caso utilize as dicas do Captulo IX). Comunicao entre robs funciona, de modo geral, da seguinte forma. Um rob pode usar o comando SendMessage() para enviar um valor (0-255) atravs de sua porta de infra-vermelho. Todos os demais robs recebem aquela mensagem e a armazenam. O programa em um rob pode verificar a ltima mensagem recebida por intermdio do comando Message(). Com base no valor, o programa pode fazer o rob executar certas aes.

Dando ordens
Freqentemente, quando voc tem dois ou mais robs, um deles o lder. Ns o chamamos de mestre (master). Os demais robs so os escravos (slaves). O rob mestre envia ordens para os robs escravos e esses as executam. s vezes, os robs escravos podem enviar de volta informaes para o mestre como, por exemplo, o valor lido em um sensor. Deste modo, voc precisa escrever dois programas, um para o rob mestre e outro para o(s) escravo(s). Aqui, iremos assumir que temos somente um escravo. Deixe-nos iniciar com um exemplo bastante simples. Nesse exemplo o rob escravo pode executar trs diferentes ordens: mover para a frente, mover para trs e parar. Seu programa consiste de um loop simples. Neste loop o valor da mensagem atual defina em 0, por meio do comando ClearMessage(). Depois ele aguarda at que a mensagem se torne diferente de 0. Baseado no valor da mensagem, o rob escravo executa uma de trs diferentes ordens. Eis o programa:
task main() { while (true) { ClearMessage(); until (Message() if (Message() == if (Message() == if (Message() == } } // ESCRAVO

!= 1) 2) 3)

0); {OnFwd(OUT_A+OUT_C);} {OnRev(OUT_A+OUT_C);} {Off(OUT_A+OUT_C);}

O rob mestre tem tambm um programa bastante simples. Ele simplesmente envia mensagens referentes s ordens e aguarda por um tempo. No programa abaixo, ele ordena aos escravos se moverem para frente. Ento, aps dois segundos, ele os ordena a se moverem para trs. Aps novos dois segundos, ele os ordena a parar.
task main() // MESTRE { SendMessage(1); Wait(200); SendMessage(2); Wait(200); SendMessage(3); }

Aps ter escrito esses dois programas, voc precisa efetuar o download dos mesmos para os robs. Cada programa de um dos robs. Esteja certo de que voc tenha desligado o outro rob no momento em que estiver efetuando o download (veja tambm as precaues apresentadas abaixo). Agora, ligue ambos os robs e execute os programas: execute primeiro aquele que est no rob escravo e depois o mestre. Caso voc tenha vrios escravos, voc dever efetuar o download para cada um deles em separado (no o faa simultaneamente; veja abaixo). Assim, todos os robs escravos executaro as mesmas aes. Para propiciar a comunicao dos robs entre si, ns definimos o que chamado de um protocolo: decidimos que um 1 significa mover para a frente, um 2 mover para trs e um 3 parar. muito importante definir tais protocolos de maneira cuidadosa, em particular quando se est lidando com um volume grande de troca de informaes. Por exemplo, quando existem muitos escravos, voc poderia definir um protocolo em que dois

- 35 -

nmeros so enviados (com um pequeno tempo de atraso entre eles): o primeiro o nmero do rob escravo e o segundo a ordem a ser executada. Os robs escravos primeiramente verificam o nmero e somente executam a ao caso aquele seja o seu nmero. (Isso requer que cada rob escravo tenha seu prprio nmero, o que pode ser feito fazendo com que cada escravo tenha um programa ligeiramente diferente em que, por exemplo, uma constante seja diferente.)

Elegendo um lder
Conforme visto acima, quando lidamos com vrios robs, cada um deve ter seu prprio programa. Seria muito mais fcil se pudssemos efetuar o download do mesmo programa para todos os robs. Mas a questo que se apresenta : quem o lder? A resposta fcil: deixe os robs decidirem por si mesmos. Deixe que eles elejam um lder e os demais o seguiro. Mas como fazer isso? A idia bastante simples. Deixaremos cada rob aguardar por um perodo de tempo aleatrio e ento enviar uma mensagem. O primeiro a enviar a mensagem ser o lder. Esse esquema pode falhar caso dois robs esperem por exatamente a mesma quantidade de tempo, mas isso bastante improvvel. (Voc pode construir esquemas mais complicados que detectam isso e tentam uma segunda eleio.) Segue um programa que faz o que foi descrito:
task main() { ClearMessage(); Wait(200); Wait(Random(400)); if (Message() > 0) { start escravo; } else { SendMessage(1); Wait(400); start mestre; } }

// garante que todos os robs estejam ligados // aguarda um tempo entre 0 e 4 segundos // algum outro rob foi o primeiro

// eu sou o mestre agora // garante que todos os demais saibam disso

task mestre() { SendMessage(1); Wait(200); SendMessage(2); Wait(200); SendMessage(3); } task escravo() { while (true) { ClearMessage(); until (Message() if (Message() == if (Message() == if (Message() == } }

!= 1) 2) 3)

0); {OnFwd(OUT_A+OUT_C);} {OnRev(OUT_A+OUT_C);} {Off(OUT_A+OUT_C);}

Efetue o download deste programa para todos os robs (um por um, no o faa simultaneamente; veja abaixo). Inicie os robs ao mesmo tempo e veja o que acontece. Um deles dever tomar o comando e os outros seguiro as ordens. Em situaes bastante raras, nenhum deles se tornar o lder. Como indicado anteriormente, isso requer um protocolo mais elaborado para solucionar tais situaes.

Precaues
Voc deve ser bastante cuidadoso quando estiver lidando com vrios robs. Existem dois problemas: se dois robs (ou um rob e um computador) enviarem informao ao mesmo tempo, as mesmas podero ser perdidas; o segundo problema que, quando o computador envia um programa para vrios robs ao mesmo tempo, isso causa problemas.

- 36 -

Vamos iniciar com o segundo problema. Quando voc efetua o download de um programa para um rob, o rob diz ao computador se ele est recebendo corretamente (as partes do) o programa. O computador reage a isso enviando novos pedaos ou reenviando partes do programa. Quando dois robs esto ligados, ambos iro iniciar dizendo ao computador se ele receberam corretamente o programa. O computador no entende isso (o computador no sabe que existem dois robs!). Como resultado, coisas podem dar errado e o programa corrompido. Os robs no faro as coisas certas. Sempre garanta que quando voc estiver fazendo o download de programas, somente um rob esteja ligado! O outro problema que somente um rob pode enviar uma mensagem em um determinado momento. Caso duas mensagens sejam enviadas exatamente ao mesmo tempo, elas sero perdidas. Alm disso, um rob no pode enviar e receber mensagens no mesmo instante. Isso no um problema quando somente um rob envia mensagens (existe somente um mestre) mas, por outro lado, pode se tornar um problema srio. Por exemplo, voc pode imaginar a escrita de um programa em que o rob escravo envia uma mensagem quando ele bate em algo, de modo que o rob mestre tome uma deciso. Mas, caso o mestre envie uma ordem ao mesmo tempo, a mensagem ser perdida. Para resolver isso, importante definir seu protocolo de comunicao de tal modo que, no caso de uma comunicao falhar, ela seja corrigida. Por exemplo, quando o mestre envia um comando, ele deve receber de volta uma resposta do escravo. Caso ele no receba uma resposta em um intervalo de tempo esperado, ele reenvia o comando. Isso poderia resultar em um pedao de cdigo que se parece com isso:
do { SendMessage(1); ClearMessage(); Wait(10); } while (Message() != 255);

Aqui, 255 usado para informar que o comando foi recebido pelo escravo. s vezes, quando voc est lidando com vrios robs, voc deseja que somente aquele rob que est mais perto receba o sinal. Isso pode ser feito por meio da insero do comando SetTxPower(TX_POWER_LO) ao programa do rob mestre. Neste caso, o sinal de infra-vermelho enviado muito baixo e somente um rob prximo e de frente para o mestre poder escut-lo. Isso em particular til quando estiver construindo um rob maior que utiliza mais de dois RCX. Use SetTxPower(TX_POWER_HI) para configurar o rob novamente com uma taxa de transmisso longa.

Resumo
Neste captulo estudamos alguns aspectos bsicos da comunicao entre robs. A comunicao utiliza comandos para enviar, limpar e verificar mensagens. Vimos que importante definir um protocolo referente maneira que a comunicao acontecer. Tais protocolos desempenham um papel crucial em toda forma de comunicao entre computadores. Vimos, tambm, que existem restries na comunicao entre robs, nos quais evidencia a importncia de se definir bons protocolos.

- 37 -

XII. Mais comandos


A linguagem NQC tem alguns comandos adicionais. Neste captulo discutiremos trs tipos: o uso de temporizadores (timers), comandos para controlar o display e o uso de caractersticas do datalog do RCX.

Temporizadores
O RCX possui quarto temporizadores internos. Esses temporizadores avanam em incrementos de 1/10 segundos. Os temporizadores so numerados de 0 a 3. Voc pode tornar zero o valor de um temporizador (zerar o temporizador) com o comando ClearTimer()e obter o valor corrente com Timer(). Abaixo, tem-se um exemplo do uso de temporizadores. O programa deixa o rob se movimentar de forma meio aleatria por 20 segundos.
task main() { ClearTimer(0); do { OnFwd(OUT_A+OUT_C); Wait(Random(100)); OnRev(OUT_C); Wait(Random(100)); } while (Timer(0)<200); Off(OUT_A+OUT_C); }

Voc pode querer comparar este programa com aquele apresentado no Captulo IV que fazia exatamente a mesma coisa. Entretanto, este programa com o uso de temporizadores se torna definitivamente mais simples. Temporizadores so muito teis em substituio ao comando Wait(). Voc pode aguardar (sleep) por uma determinada quantidade de tempo zerando o temporizador e esperando at que seu valor alcance um valor determinado. Mas voc tambm pode reagir a outros eventos (como por exemplo, gerados por sensores) enquanto o temporizador estiver executando. O seguinte programa um exemplo disso. Ele deixa o rob se movimentar at que uma de duas coisas acontea: 10 segundos sejam passados; ou o sensor de toque perceba algo.
task main() { SetSensor(SENSOR_1,SENSOR_TOUCH); ClearTimer(3); OnFwd(OUT_A+OUT_C); until ((SENSOR_1 == 1) || (Timer(3) >100)); Off(OUT_A+OUT_C); }

No se esquea que os temporizadores trabalham em intervalos de 1/10 segundos, enquanto que o comando Wait utiliza intervalos de 1/100 segundos.

O display
possvel controlar o display do RCX de duas maneiras diferentes. Na primeira delas voc pode indicar o que ser mostrado no display: o clock do sistema, um dos sensores ou um dos motores. Isso equivalente a utilizar o boto view do RCX. Para definir o tipo de informao a ser apresentada, utilize o comando SelectDisplay(). A seguir so mostradas todas as sete possibilidades, uma aps a outra.

- 38 -

task main() { SelectDisplay(DISPLAY_SENSOR_1); SelectDisplay(DISPLAY_SENSOR_2); SelectDisplay(DISPLAY_SENSOR_3); SelectDisplay(DISPLAY_OUT_A); SelectDisplay(DISPLAY_OUT_B); SelectDisplay(DISPLAY_OUT_C); SelectDisplay(DISPLAY_WATCH); }

Wait(100); Wait(100); Wait(100); Wait(100); Wait(100); Wait(100); Wait(100);

// // // // // // //

Entrada 1 Entrada 2 Entrada 3 Sada A Sada B Sada C Clock do sistema

Observe que voc no deve utilizar SelectDisplay(SENSOR_1). A segunda maneira de controlar o display por intermdio do valor do clock do sistema (relgio do sistema). Voc pode us-lo, por exemplo, para apresentar informaes de diagnstico. Para isso, use o comando SetWatch(), conforme mostrado abaixo.
task main() { SetWatch(1,1); Wait(100); SetWatch(2,4); Wait(100); SetWatch(3,9); Wait(100); SetWatch(4,16); Wait(100); SetWatch(5,25); Wait(100); }

Observe que os argumentos para SetWatch() devem ser constantes.

Datalogging
O RCX pode armazenar valores de variveis, leituras de sensores e o valor de temporizadores em uma pequena rea da memria denominada datalog. Os valores do datalog no podem ser utilizados pelo RCX, mas podem ser lidos pelo seu computador. Isso til, por exemplo, para verificar o que est acontecendo com o seu rob. O RCX Command Center tem uma janela especial em que voc pode ver o contedo atual do datalog. Usar o datalog consiste de trs passos. Primeiro, o programa em NQC define o tamanho do datalog por meio do comando CreateDatalog(). Isso tambm limpa o valor corrente do datalog. Depois, os valores podem ser escritos no datalog usando o comando AddToDatalog(). Os comandos sero escritos um aps o outro. (Se voc observar o display do RCX ver que aparecem quatro partes de um disco, uma aps a outra. Quando o disco estiver completo o datalog estar cheio.) Caso o final do datalog estiver sido alcanado, nada acontece. Novos valores no sero armazenados. O terceiro passo transferir o contedo do datalog para o computador. Para isso, escolha no RCX Command Center o comando Datalog no menu Tools. Depois, pressione o boto Upload Datalog, e todos os valores aparecero. Voc pode v-los ou salv-los em um arquivo para fazer algo a mais com eles. Essa caracterstica tem sido freqentemente utilizada, por exemplo, para fazer uma varredura com o RCX. No prximo exemplo temos um rob com um sensor de luz. O rob se move por 10 segundos e a cada segundo so feitas 5 escritas no datalog do valor lido no sensor.
task main() { SetSensor(SENSOR_2,SENSOR_LIGHT); OnFwd(OUT_A+OUT_C); CreateDatalog(50); repeat (50) { AddToDatalog(SENSOR_2); Wait(20); } Off(OUT_A+OUT_C); }

- 39 -

XIII. NQC: guia de referncia rpido


Abaixo voc encontrar uma lista com todas as estruturas, comandos, constantes, etc. do NQC. A maioria deles foi tratada nos captulos anteriores, de modo que ser dada somente uma breve descrio.

Instrues
Instrues
while (cond) body do body while (cond) until (cond) body break continue repeat (expression) body if (cond) stmt1 if (cond) stmt1 else stmt2 start task_name stop task_name function(args) var = expression var += expression var -= expression var *= expression var /= expression var |= expression var &= expression return expression

Descrio Executa o corpo zero ou mais vezes enquanto a condio for verdadeira Executa o corpo uma ou mais vezes enquanto a condio for verdadeira Executa o corpo zero ou mais vezes at que a condio se torne verdadeira Sai de uma estrutura do tipo while/do/until Pula a prxima iterao de uma estrutura do tipo while/do/until Repete o corpo um nmero de vezes especfico Executa stmt1 se a condio for verdadeira. Executa stmt2 (caso exista) se a condio for falsa Inicia a tarefa especificada Pra a tarefa especificada Chama uma funo utilizando os argumentos passados Calcula a expresso e atribui o valor resultante para a varivel Calcula a expresso e adiciona o valor resultante ao valor da varivel Calcula a expresso e subtrai o valor resultante do valor da varivel Calcula a expresso e multiplica o valor resultante pelo valor da varivel Calcula a expresso e divide o valor resultante pelo valor da varivel Calcula a expresso e executa a operao OR sobre a varivel Calcula a expresso e executa a operao AND sobre a varivel Retorna de uma funo para o ponto que a chamou Calcula a expresso

Condies
Condies so usadas dentro de estruturas de controle para a tomada de decises. Na maioria dos casos, a condio envolver uma comparao entre as expresses. Condio Significado true sempre verdadeiro false sempre falso expr1 == expr2 Testa se as expresses so iguais expr1 != expr2 Testa se as expresses so diferentes expr1 < expr2 Testa se uma expreso menor do que a outra expr1 <= expr2 Testa se uma expreso menor ou igual do que a outra expr1 > expr2 Testa se uma expreso maior do que a outra expr1 >= expr2 Testa se uma expreso maior ou igual do que a outra ! condition Negao lgica de uma expresso cond1 && cond2 Lgica AND de duas condies (verdadeiro se, e somente se, ambas as condies forem verdadeiras) cond1 || cond2 Lgica OR de duas condies (verdadeiro se, e somente se, pelo menos uma das condies for verdadeira)

Expresses
Existem diferentes valores que podem ser usados dentro de expresses, incluindo constantes, variveis e valores de sensores. Observe que SENSOR_1, SENSOR_2 e SENSOR_3 so macros que se expandem para SensorValue(0), SensorValue(1) e SensorValue(2), respectivamente. Valor nmero varivel Timer(n) Descrio Um valor constante (por exemplo "123") Uma varivel nomeada (por exemplo "x") Valor do temporizador n, onde n pode ser 0, 1, 2 ou 3

- 40 -

Random(n) SensorValue(n) Watch() Message()

Nmero randmico definido entre 0 e n (inclusives) Valor corrente do sensor n, onde n pode ser 0, 1 ou 2 Valor do relgio do sistema Valor da ltima mensagem de infra-vermelho recebida

Valores podem ser combinados utilizando operadores. Muitos dos operadores somente podem ser utilizados no clculo de expresses constantes, o que significa que seus operandos devem ser constantes ou expresses envolvendo nada mais do que constantes. Os operadores so listados abaixo em ordem de precedncia (da maior para a menor). Operador
abs() sign() ++ -~ * / % + << >> & ^ | && ||

Descrio Valor absoluto Sinal do operando Incremento Decremento Menos unrio Negao Bitwise (unria) Multiplicao Diviso Mdulo Adio Subtrao Deslocamento para a esquerda Deslocamento para a direita Bitwise AND Bitwise XOR Bitwise OR Operador lgico AND Operador lgico OR

Associatividade Restrio n/a n/a esquerda Somente variveis esquerda Somente variveis direita Somente constantes direita esquerda esquerda esquerda Somente constantes esquerda esquerda esquerda Somente constantes esquerda Somente constantes esquerda esquerda Somente constantes esquerda esquerda Somente constantes esquerda Somente constantes

Exemplo
abs(x) sign(x) x++ ou ++x x-- ou --x -x ~123 x * y x / y 123 % 4 x + y x - y 123 << 4 123 >> 4 x & 123 x | 123 123 y ^ 4 y && 4 || 4

Funes do RCX
A maioria das funes requer que todos os argumentos sejam expresses constantes (nmeros ou operaes envolvendo outras expresses constantes). As excees so as funes que usam um sensor como argumento e aquelas que no usam qualquer expresso. No caso de sensores, o argumento deve ser um nome de um sensor: SENSOR_1, SENSOR_2 ou SENSOR_3. Em alguns casos existem nomes predefinidos (por exemplo, SENSOR_TOUCH) para constantes apropriadas. Funo
SetSensor(sensor, config) SetSensorMode(sensor, mode) SetSensorType(sensor, type) ClearSensor(sensor) On(outputs) Off(outputs) Float(outputs) Fwd(outputs) Rev(outputs) Toggle(outputs) OnFwd(outputs) OnRev(outputs) OnFor(outputs, time)

Descrio Configura um sensor. Define o modo do sensor. Define o tipo do sensor.

Exemplo
SetSensor(SENSOR_1, SENSOR_TOUCH) SetSensor(SENSOR_2, SENSOR_MODE_PERCENT) SetSensor(SENSOR_2, SENSOR_TYPE_LIGHT)

ClearSensor(SENSOR_3) Limpa o valor do sensor. On(OUT_A + OUT_B) Liga uma ou mais sadas. Desliga uma ou mais sadas. Off(OUT_C) Float(OUT_B) Deixa que a sada flutue. Fwd(OUT_A) Define a direo da sada para frente. Rev(OUT_B) Define a direo da sada para trs. Toggle(OUT_C) Troca a direo da sada (Frente para trs e vice-versa) Liga em movimentao para OnFwd(OUT_A) frente. OnRev(OUT_B) Liga no sentido reverso. OnFor(OUT_A, 200) Liga por um perodo de tempo especificado por um nmero igual a 1/100 de

- 41 -

segundo. O tempo (time) pode ser uma expresso. SetOutput(outputs, mode) Define o modo de sada. SetOutput(OUT_A, OUT_ON) SetDirection(outputs, dir) Define a direo da sada. SetDirection(OUT_A, OUT_FWD) SetPower(outputs, power) Define o nvel de potncia da SetPower(OUT_A, 6) sada (0-7). power pode ser uma expresso. Wait(time) Aguarda por uma quantidade Wait(x) de tempo especificada em 1/100 segundos. time pode ser uma expresso. PlaySound(sound) PlaySound(SOUND_CLICK) Toca um som especfico (0-5). PlayTone(freq, duration) Toca uma nota de uma PlayTone(440, 5) freqncia especificada por um determinado perodo de tempo (em 1/10 segundos). ClearTimer(timer) Define o temporizador (0-3) ClearTimer(0) em 0. StopAllTasks() StopAllTasks() Pra todas as tarefas atualmente em execuo. SelectDisplay(mode) Seleciona um de 7 modos do SelectDisplay(1) display: 0: relgio do display, 1-3: valores de sensor, 4-6: configurao de sada. mode pode ser uma expresso. SendMessage(message) SendMessage(x) Envia uma mensagem em infra-vermelho (1-255). message pode ser uma expresso. ClearMessage() Limpa o buffer de mensagens ClearMessage() de infra-vermelho. CreateDatalog(size) Cria um novo datalog de um CreateDatalog(100) tamanho (size) especificado. AddToDatalog(value) AddToDatalog(Timer(0)) Adiciona um valor ao datalog. value pode ser uma exepresso. SetWatch(hours, minutes) Define o valor do relgio do SetWatch(1,30) sistema. SetTxPower(hi_lo) Define o nvel de potncia do SetTxPower(TX_POWER_LO) transmissor de infra-vermelho para um nvel baixo ou alto.

Constantes do RCX
Existem vrias constantes nomeadas (constantes simblicas) que podem ser passadas para as funes de modo a ajudar a tornar o cdigo mais legvel. Quando possvel, utilize uma constante nomeada ao invs de um valor bruto. Configuraes do sensor para SetSensor() Modos para SetSensorMode()
SENSOR_TOUCH, SENSOR_LIGHT, SENSOR_ROTATION, SENSOR_CELSIUS, SENSOR_FAHRENHEIT, SENSOR_PULSE, SENSOR_EDGE SENSOR_MODE_RAW, SENSOR_MODE_BOOL, SENSOR_MODE_EDGE, SENSOR_MODE_PULSE, SENSOR_MODE_PERCENT, SENSOR_MODE_CELSIUS, SENSOR_MODE_FAHRENHEIT, SENSOR_MODE_ROTATION SENSOR_TYPE_TOUCH, SENSOR_TYPE_TEMPERATURE, SENSOR_TYPE_LIGHT, SENSOR_TYPE_ROTATION OUT_A, OUT_B, OUT_C OUT_ON, OUT_OFF, OUT_FLOAT OUT_FWD, OUT_REV, OUT_TOGGLE

Tipos para SetSensorType() Sadas para On(), Off(), etc. Modos para SetOutput() Direes para SetDirection()

- 42 -

Potncia de sada para SetPower() OUT_LOW, OUT_HALF, OUT_FULL SOUND_CLICK, SOUND_DOUBLE_BEEP, SOUND_DOWN, SOUND_UP, Sons para PlaySound() Modos para SelectDisplay() Nvel da potncia da taxa de transmisso para SetTxPower()
SOUND_LOW_BEEP, SOUND_FAST_UP DISPLAY_WATCH, DISPLAY_SENSOR_1, DISPLAY_SENSOR_2, DISPLAY_SENSOR_3, DISPLAY_OUT_A, DISPLAY_OUT_B, DISPLAY_OUT_C TX_POWER_LO, TX_POWER_HI

Palavras-chave
Palavras-chave so aquelas palavras reservadas pelo compilador do NQC. um erro utilizar essas palavras para nomes de funes, tarefas ou variveis. A seguir, tem-se uma lista das palavras-chave usadas: __sensor, abs,
asm, break, const, continue, do, else, false, if, inline, int, repeat, return, sign, start, stop, sub, task, true, void, while.

- 43 -

XIV. Consideraes finais


Caso voc tenha trabalhado sua maneira por todo este tutorial, voc pode se considerar um expert em NQC. Caso voc ainda no tenha feito isso, hora de comear experimentando os exemplos. Com criatividade no projeto e programao, voc pode instruir os robs Lego a fazer coisas maravilhosas. Este tutorial no cobre todos os aspectos do RCX Command Center. recomendvel que voc leia a documentao em algum momento. Alm do mais, o NQC encontra-se em desenvolvimento. Verses futuras devem incorporar funcionalidades adicionais. Muitos conceitos de programao no foram tratados neste tutorial. Em particular, no consideramos a aprendizagem dos robs nem outros aspectos da inteligncia artificial. Tambm possvel controlar um rob Lego diretamente do PC. Isso requer que voc escreva um programa em uma linguagem tal como, Visual Basic, Java ou Delphi. possvel, tambm, deixar um programa desses rodar juntamente com um outro programa em execuo no RCX. Essa combinao muito poderosa. Caso voc esteja interessado nessa maneira de programar os seus robs, o melhor a fazer comear efetuando o download da referncia tcnica no site do Lego Mindstorms no site. http://www.legomindstorms.com/ A internet uma fonte repleta de informaes adicionais. Alguns outros importantes primeiros passos esto disponveis por meio de links na minha prpria home page: http://www.cs.uu.nl/people/markov/lego/ e em LUGNET, a rede de grupos de usurios LEGO (no oficial): http://www.lugnet.com/ Uma gama de informaes podem tambm ser lugnet.robotics.rcx.nqc em lugnet.com. encontradas nos newsgroups lugnet.robotics e

- 44 -

Das könnte Ihnen auch gefallen