Controlar tu iRobot Create con un piloto de Palma (11 / 16 paso)

Paso 11: El programa, parte 3

Ahora es el momento para el "núcleo" del programa, el archivo "robot.c".

En la parte superior del archivo "robot.c" necesitamos:

 #include "robot.h" #include "string_arrays.c" #include <PalmTypes.h> #include <PalmCompatibility.h> #include <System/SystemPublic.h> #include <UI/UIPublic.h> void SetField (UInt16 formID, UInt16 fieldID, MemPtr str); Int16 Connect(); Boolean Disconnect(); void DisplaySensors(); Boolean MenuHandler (EventPtr event); Boolean SelectFormHandler (EventPtr event); Int16 SendScript (char length); void Display (char length); Boolean ScriptFormHandler (EventPtr event); Boolean MainFormHandler (EventPtr event); Boolean AppHandleEvent (EventPtr event); void AppEventLoop(); void AppStart(); void AppStop(); UInt32 PilotMain (UInt16 cmd, MemPtr cmdPBP, UInt16 launchFlags); // GlobalsUInt16 port = 0; char prog = 0; unsigned char script[30][2]; 

Parte de esto es la biblioteca genérica de Palm OS. También estoy declarando todas las funciones que he usado en la parte superior, por lo que no necesitará preocuparse por cualquier pedido especial al editar el archivo robot.c. En el fondo también tengo unas variables globales que utilizo en varios puntos en el programa.

La función de "PilotMain" es el punto de entrada al programa. Hay varias razones por qué un programa podría iniciarse en una Palm Pilot, pero sólo queremos que se preocupe de uno; Si el programa fue iniciado por el usuario PilotMain() se iniciará el resto del programa.

 UInt32 PilotMain (UInt16 cmd, MemPtr cmdPBP, UInt16 launchFlags) { if (cmd == sysAppLaunchCmdNormalLaunch) { AppStart(); AppEventLoop(); AppStop(); } return 0; } 

Las funciones AppStart() y AppStop() son bastante básicas, AppStart() Asegúrese de que la aplicación se inicia correctamente, y AppStop() se asegura de que la aplicación se cierra limpiamente.

 void AppStart() { FrmGotoForm(FormMain); } void AppStop() { Disconnect(); FrmCloseAllForms(); } 

AppEventLoop() es el núcleo del programa. Cada vez que pasa algo AppEventLoop() recuperar el "evento" y tratar de manejarlo. Primero envía el evento para algunas funciones integradas para tratar de dejar que el sistema a controlar el evento. Si el sistema no maneja completamente el evento AppEventLoop(), pasa el evento a nuestras propias funciones para tratar de manejarlo. FrmDispatchEvent() es la función de controlador de eventos que hemos asignado para controlar los eventos de forma activa en la actualidad.

 void AppEventLoop() { EventType event; short error; do { EvtGetEvent (&event, 50); // Wait 100 ticks before sending a nilEvent // Allow the system to attemt to handle events before trying ourself if (SysHandleEvent(&event)) continue; if (MenuHandleEvent((void*)0, &event, &error)) continue; if (AppHandleEvent(&event)) continue; if (MenuHandler(&event)) continue; // Send the event to the form event handler FrmDispatchEvent(&event); } while (event.eType != appStopEvent); } 

AppHandleEvent() es la primera función no sea del sistema que envía eventos de AppEventLoop(). Comprueba si el evento significa la carga de una de las formas. Si es así configura el formulario y asigna a un controlador de eventos predeterminado (para FrmDispatchEvent()).

 Boolean AppHandleEvent (EventPtr event) { FormPtr frm; Int frmID; Boolean handled = false; char str[255]; str[0] = '\0'; if (event->eType == frmLoadEvent) { frmID = event->data.frmLoad.formID; frm = FrmInitForm(frmID); FrmSetActiveForm(frm); switch (frmID) { case FormMain: FrmSetEventHandler(frm, MainFormHandler); FrmDrawForm(frm); StrCat(str, PROGRAM[prog]); SetField(frmID, FldProg, str); handled = true; break; case FormSelect: FrmSetEventHandler(frm, SelectFormHandler); FrmDrawForm(frm); StrCat (str, DISCRIPIONS[prog]); SetField (frmID, FldDescription, str); handled = true; break; case FormMacro: FrmSetEventHandler(frm, ScriptFormHandler); FrmDrawForm(frm); handled = true; break; } } return handled; } 

MenuHandler() es la función siguiente en la lista de AppEventLoop (). Si el usuario hace un menú de selección MenuHandler() lo controlará.

 Boolean MenuHandler (EventPtr event) { Boolean handled = false; Err err; // The command that runs the demo program that corosponds to 'prog' char data[] = {128, 136, prog}; // Handle the menu button's if (event->eType == menuEvent) { MenuEraseStatus(NULL); switch (event->data.menu.itemID) { // Go to the verious forms case MnuStatus: FrmGotoForm(FormMain); handled = true; break; case MnuScript: FrmGotoForm(FormSelect); handled = true; break; case MnuMacro: FrmGotoForm(FormMacro); handled = true; break; // Open the serial connection case MnuConnect: Connect(); handled = true; break; // Close the serial connection case MnuDisconnect: Disconnect(); handled = true; break; // Start/Stop the currently selected program or macro case MnuRun: if (!Connect()) break; // Send the command to the iRobot SrmSend(port, data, 3, &err); SrmSendFlush(port); handled = true; break; case MnuStop: // Replace the 'prog' byte with -1 (255) to stop the currently running program data[2] = 255; // Send the command to the iRobot if (!Connect()) break; SrmSend(port, data, 3, &err); SrmSendFlush(port); handled = true; break; case MnuAbout: FrmAlert(AboutAlert); handled = true; break; } } return handled; } 

Connect() y Disconnect() se utilizan para abrir y cerrar el puerto serie de la Palm Pilot. Tiempo o no el robot está conectado a la Palm Pilot y enciende cuando se utilizan estas funciones no es demasiado importante. Resistente, si el robot no recibe el comando "Start" al menos una vez (se envía cuando se llama a la función Connect()) podría tener algunos problemas al ejecutar sus propios scripts.

 Int16 Connect() { Err err; char data = 128; // Open the serial port if (!port) SrmOpen(serPortCradlePort, 57600, &port); // Send the "Start" command to make sure the Create comes out of "Off" mode SrmSend(port, &data, 1, &err); SrmSendFlush(port); return port; } Boolean Disconnect() { // Close the serial port if (port && !SrmClose(port)) { port = 0; return true; } else return false; } 

SetFiled() es utilizado por varias funciones para Mostrar datos en los campos de texto definidos por el archivo "robot.rcp".

 void SetField (UInt16 formID, UInt16 fieldID, MemPtr str){ FormPtr frm; FieldPtr fld; UInt16 obj; CharPtr p; VoidHand h; frm = FrmGetFormPtr(formID); obj = FrmGetObjectIndex(frm, fieldID); fld = (FieldPtr)FrmGetObjectPtr(frm, obj); h = (VoidHand)FldGetTextHandle(fld); if (h == NULL) { h = MemHandleNew (FldGetMaxChars(fld)+1); ErrFatalDisplayIf(!h, "No Memory"); } p = (CharPtr)MemHandleLock(h); StrCopy(p, str); MemHandleUnlock(h); FldSetTextHandle(fld, (Handle)h); FldDrawField(fld); } 

DisplaySensors() es utilizado por el formulario principal (la forma de "Estado") para recuperar información de sensor del robot y luego mostrar al usuario. Primero envía el comando "Query List" del robot con una lista de sensores que nos interesa. DisplaySensors() luego analizar la respuesta del robot y actualizar la pantalla en consecuencia.

 void DisplaySensors() { // The data packet sent to the create that requests the sensor data char data[] = {128, 149, 8, 8, 7, 9, 10, 11, 12, 22, 21}; // The byte array that holds the sensor data retrived by the create char inData[9]; char str[20]; UInt16 tmp, *volt; Err err; VoidHand bitmapHandle; BitmapPtr bitmap; Boolean wheall = false, whealr = false; str[0] = '\0'; if (port) { // Only perform this loop if the serial connection is open FrmDrawForm(FrmGetActiveForm()); // Re-draw the form, to clear the old data // Send the request to the create for the sensor data, and put the reply in 'inData' SrmReceiveFlush(port, 0); SrmSend(port, data, 11, &err); SrmSendFlush(port); SrmReceive(port, inData, 9, 20, &err); // The wall sensor if (inData[0]) { bitmapHandle = DmGetResource('Tbmp', PicWall); bitmap = MemHandleLock(bitmapHandle); WinDrawBitmap(bitmap, 110, 25); MemHandleUnlock(bitmapHandle); } // The bumper's and wheal drop sensors tmp = (int)inData[1]; if (tmp >= 16) tmp=tmp-16; // Caster wheal if (tmp >= 8) { // Left wheal wheall = true; tmp = tmp - 8; } if (tmp >= 4) { // Right wheal whealr = true; tmp = tmp - 4; } if (tmp >= 2) { // Left wheal bitmapHandle = DmGetResource('Tbmp', PicBumpL); bitmap = MemHandleLock(bitmapHandle); WinDrawBitmap(bitmap, 25, 30); MemHandleUnlock(bitmapHandle); tmp = tmp - 2; } if (tmp == 1) { // Right wheal bitmapHandle = DmGetResource('Tbmp', PicBumpR); bitmap = MemHandleLock(bitmapHandle); WinDrawBitmap(bitmap, 60, 30); MemHandleUnlock(bitmapHandle); } // We draw the wheal's after drawing the bumpers, so the // pictures overlap properly if (wheall) { bitmapHandle = DmGetResource('Tbmp', PicWhealL); bitmap = MemHandleLock(bitmapHandle); WinDrawBitmap(bitmap, 37, 52); MemHandleUnlock(bitmapHandle); } if (whealr) { bitmapHandle = DmGetResource('Tbmp', PicWhealR); bitmap = MemHandleLock(bitmapHandle); WinDrawBitmap(bitmap, 71, 52); MemHandleUnlock(bitmapHandle); } // The 4 clif sensors if (inData[2]+inData[3]+inData[4]+inData[5] > 0) { bitmapHandle = DmGetResource('Tbmp', PicCliff); bitmap = MemHandleLock(bitmapHandle); if (inData[2] > 0) WinDrawBitmap(bitmap, 21, 35); // Left if (inData[3] > 0) WinDrawBitmap(bitmap, 31, 25); // Top left if (inData[4] > 0) WinDrawBitmap(bitmap, 80, 25); // Top Right if (inData[5] > 0) WinDrawBitmap(bitmap, 90, 35); // Right MemHandleUnlock(bitmapHandle); } // The raw battery voltage volt = (UInt16*)(inData + 6); StrIToA(str, *volt); StrCat(str, " mV"); if (inData[8] > 0 && inData[8] <= 3) StrCat(str, " (crg)"); SetField(FormMain, FldVoltage, str); } } 

MainFormHandler() es la función asignada al formulario principal (estado). Está diseñado para controlar los eventos específicos a la forma de estado. El controlador de forma individual sobre todo apenas controlar eventos provocados por el usuario, pero el controlador de formulario principal será también responder a nillEvent que son generados por cada 50 "garrapatas" (una marca es una medida de tiempo que utiliza el sistema operativo de Palm) por AppEventLoop().

 Boolean MainFormHandler (EventPtr event) { Boolean handled = false; switch (event->eType) { // Every 50 ticks we check the create's sensors (pending a serial connection) case nilEvent: DisplaySensors(); handled = true; break; case ctlSelectEvent: if (event->data.ctlSelect.controlID == BtnDisconnect) { Disconnect(); handled = true; } break; } return handled; } 

SelectFormHandler() se encarga de eventos para el formulario de selección.

 Boolean SelectFormHandler (EventPtr event) { Boolean handled = false; char str[255]; str[0] = '\0'; switch (event->eType) { case lstSelectEvent: prog = event->data.lstSelect.selection; StrCat (str, DISCRIPIONS[prog]); SetField (FormSelect, FldDescription, str); handled = true; break; } return handled; } 

ScriptFormHandler() maneja eventos para la forma de secuencias de comandos. Una gran parte de ScriptFormHandler() es distinguir entre los diferentes botones de programación. Porque la tecla de programación ID ' s son números consecutivos, en vez de buscar eventos de botón específico para gamas del botón Buscar.

 Boolean ScriptFormHandler (EventPtr event) { const char MAX_SCRIPT = 8; static char length = 0; Boolean handled = false; UInt16 id; Int16 x; FieldPtr fld; FormPtr frm; switch (event->eType) { case frmOpenEvent: Display(length); handled=true; break; // Handle the various buttons case ctlSelectEvent: id = event->data.ctlSelect.controlID; switch (id) { case BtnSend: SendScript(length); handled = true; break; case BtnClear: length = 0; Display(length); handled = true; break; case BtnDel: length--; if (length < 0) length = 0; Display(length); handled = true; break; } // The script action buttons if (id >= BtnUp && id <= BtnPause) { if (length < MAX_SCRIPT) { script[length][0] = id-3100; script[length][1] = 1; length++; } Display(length); handled = true; } // The script time buttons if (id >= BtnP1 && id <= BtnP16) { x = script[length-1][1]; script[length-1][1] = (x+(id-3200) <= 25) ? x+(id-3200) : x; Display(length); handled = true; } break; // The scroll bar case sclRepeatEvent: x = event->data.sclRepeat.newValue - event->data.sclRepeat.value; frm = FrmGetActiveForm(); fld = (FieldPtr)FrmGetObjectPtr (frm, FrmGetObjectIndex(frm, FldScript)); if (x >= 0) FldScrollField (fld, x, winDown); else FldScrollField (fld, x*-1, winUp); break; } return handled; } 

La función Display() traduce los datos en la matriz de secuencia de comandos en una cadena de humanos y lo muestra en un campo de texto que el usuario pueda ver.

 void Display (char length) { char str[1000]; char x; char tmp[10]; str[0] = '\0'; // Turn the script array into a string and display it for (x = 0; x < length; x++) { StrCat (str, COMMANDS[script[x][0]]); StrCat (str, " for \0"); StrIToA (tmp, script[x][1]); StrCat (str, tmp); StrCat (str, " Seconds\n\0"); } SetField (FormMacro, FldScript, str); } 

Finalmente la función de SendScript() tomará la variable de script y traduce en comandos que el iRobot Create puede comprender y luego enviar el resultado a tu robot. Se llama desde la función ScriptFormHandler().

 Int16 SendScript (char length) { char safe[] = {128, 131}; char data[150]; char i; char x = 0; char y; char cmds = 0; Err err; data[x] = 131; data[++x] = 152; y = ++x; for (i = 0; i < length; i++) { switch (script[i][0]) { case 0: data[++x] = 137; data[++x] = 0; data[++x] = 150; data[++x] = 128; data[++x] = 0; data[++x] = 155; data[++x] = script[i][1]*10; data[++x] = 137; data[++x] = 0; data[++x] = 0; data[++x] = 128; data[++x] = 0; cmds += 3; break; case 1: data[++x] = 137; data[++x] = 255; data[++x] = 106; data[++x] = 128; data[++x] = 0; data[++x] = 155; data[++x] = script[i][1]*10; data[++x] = 137; data[++x] = 0; data[++x] = 0; data[++x] = 128; data[++x] = 0; cmds += 3; break; case 2: data[++x] = 137; data[++x] = 0; data[++x] = 150; data[++x] = 1; data[++x] = 44; data[++x] = 155; data[++x] = script[i][1]*10; data[++x] = 137; data[++x] = 0; data[++x] = 0; data[++x] = 128; data[++x] = 0; cmds += 3; break; case 3: data[++x] = 137; data[++x] = 0; data[++x] = 150; data[++x] = 254; data[++x] = 212; data[++x] = 155; data[++x] = script[i][1]*10; data[++x] = 137; data[++x] = 0; data[++x] = 0; data[++x] = 128; data[++x] = 0; cmds += 3; break; case 4: data[++x] = 137; data[++x] = 0; data[++x] = 125; data[++x] = 0; data[++x] = 1; data[++x] = 155; data[++x] = script[i][1]*10; data[++x] = 137; data[++x] = 0; data[++x] = 0; data[++x] = 128; data[++x] = 0; cmds += 3; break; case 5: data[++x] = 137; data[++x] = 0; data[++x] = 125; data[++x] = 255; data[++x] = 255; data[++x] = 155; data[++x] = script[i][1]*10; data[++x] = 137; data[++x] = 0; data[++x] = 0; data[++x] = 128; data[++x] = 0; cmds += 3; break; case 6: data[++x] = 155; data[++x] = script[i][1]*10; cmds += 1; break; } } data[y] = x+1; Connect(); // Send the script SrmSend(port, data, x+1, &err); SrmSendWait(port); SrmSendFlush(port); return err; } 

Artículos Relacionados

Adaptación mapeo y navegación con iRobot Create

Adaptación mapeo y navegación con iRobot Create

este tutorial demostrará cómo hacer el mapeo y navegación con el iRobot Create para menos de $30! Y mejor aún, su diseño para ser un complemento fácil a tu robot ya existentes (robot mayordomo, alguien?).¿Por qué es cartografía útil? ¿Que siempre qui
Cómo hacer un baloncesto autónoma jugar robot utilizando un iRobot Create como base

Cómo hacer un baloncesto autónoma jugar robot utilizando un iRobot Create como base

esta es mi entrada para el iRobot Create desafío. La parte más difícil de todo este proceso para mí fue decidir lo que el robot se iba a hacer. Quería demostrar las características interesantes de la creación, mientras que también agrega en algún est
Cómo introducir el iRobot Create reto

Cómo introducir el iRobot Create reto

actualización: concurso plazo extendido a 11:59 pm PDT el domingo 9 de septiembre!Si tu robot es recalcitrante, utilizar los días adicionales para navegar un fix o intentar otra estrategia. Si tu robot es fabuloso, post-it y los días adicionales para
Voz controlada iRobot Create

Voz controlada iRobot Create

Recientemente recibí un accesorio android Development Kit (ADK) y, coincidentemente, también recibió mi iRobot cree.  Así que, decidí poner los dos juntos para conseguir que un robot controlado por voz usando las APIs de Android como una manera fácil
Arduino Uno y Visuino: controlar Robot coche Smart con Joystick y L298N controlador de Motor

Arduino Uno y Visuino: controlar Robot coche Smart con Joystick y L298N controlador de Motor

Que coche elegante se establece cuando se combinan con Los módulos de controladores Motor L298N, ofrecen una de las maneras más fáciles de fabricar coches robot. El Módulo del controlador Motor L298N es fácil de controlar con Arduino, y con la ayuda
Controlar cualquier cosa remotamente con señales infrarrojas.

Controlar cualquier cosa remotamente con señales infrarrojas.

¿Quién hubiera pensado que cualquier accesorio de Arduino se puede controlar de algún modo con un control remoto de TV? Ahora es el momento para averiguar cómo.Paso 1: Instalación y materiales La configuración para esto es bastante básica. El verdade
Cómo controlar un RGB LED con un Arduino

Cómo controlar un RGB LED con un Arduino

En este Instructable, yo lo se que muestra cómo controlar un LED RGB con un Arduino.Para completar este proyecto, necesitarás:1 x Arduino (estoy usando la Arduino Uno R3)1 LED x RGB3 x 150-220 ohm resistencias4 x cables de puente1 x Breadboard1 x ord
IRobot Create Personal hogar Robot

IRobot Create Personal hogar Robot

introducir un robot casero personal en torno a la plataforma de Create de iRobot y un sistema mini-itx.Nunca ha sido más fácil y más asequible para diseñar y construir robots aprovechando las economías de escala del software, PC, juguetes y otras ind
Modificar un iRobot Create a pintura

Modificar un iRobot Create a pintura

este es un proyecto de robótica que probablemente podría ser completado por alguien que no tiene experiencia con los robots en todas. Lo digo porque antes de empezar, yo no tenía experiencia con robots. O escribir programas. De hecho, sabía cómo pint
Controlar tu réflex con el iPhone y Arduino BLE módulo

Controlar tu réflex con el iPhone y Arduino BLE módulo

Aquí le damos 10 minutos instructable para controlar la cámara réflex digital con Arduino y el iPhone.Paso 1: Lista de piezasUn Arduino UNO o Mega o Nano o etc.He utilizado un módulo HM-10 Bluetooth bajo pero creo que otros módulos de Ble funcionará
Controlar una impresora 3D con gestos con las manos

Controlar una impresora 3D con gestos con las manos

que he escrito antes pero administrar un laboratorio de tecnología creativa en la Universidad de California de los artes. I ayudar a los estudiantes con una amplia gama de habilidades, crear una amplia gama de proyectos. Uno de muchas partes de mi tr
Cómo controlar una impresora 3D con un teléfono a través de bricolaje AstroBox

Cómo controlar una impresora 3D con un teléfono a través de bricolaje AstroBox

Este Instructable le mostrará cómo configurar un servidor de impresión basado en Raspberry Pi para controlar y monitorear la impresora 3D remotamente (incluyendo corte remoto) desde un teléfono, tablet o computadora.Impresión inalámbricaPor supuesto,
Controlar tu habitación con tu móvil

Controlar tu habitación con tu móvil

Este instructable le mostrará cómo conectar la bombilla a su teléfono móvil y control mediante sensor de infrarrojos.Usted puede controlar cualquier cosa eléctrica en su casa después de este instructable, si comprende los principales conceptos.El har
Cómo controlar casi cualquier cosa con una cámara 3D (incluyendo su Arduino)

Cómo controlar casi cualquier cosa con una cámara 3D (incluyendo su Arduino)

si controlas su aplicación por el teclado, ratón o joystick después de fácil de controlar con gestos con las manos utilizando una cámara 3D. Este tutorial le mostrará cómo se puede hacer usando el emulador de dispositivos, un pedazo limpio de código