2011-04-29 10 views
8

Tengo una aplicación en mi iPhone llamada iSeismometer que lee los acelerómetros del iPhone y actúa como un servidor que transmite estos datos a través de UDP (puedo establecer la dirección IP y el número de puerto). La pregunta es cómo leer esta secuencia de datos con Mathematica. Aparentemente, Dreeves ha estado buscando en este 12 years ago, así que imagino que algo debe haber sucedido mientras tanto.Conectando a una corriente de datos UDP con Mathematica

Actualización
Recibí dos excelentes respuestas hasta el momento; uno de WReach y uno de Mark McClure. Ambos están usando JLink para obtener los datos. Esto parece un buen enfoque. Sin embargo, me acordé de un trabajo que hice en la tabla de equilibrio WII. Utilizando algunos programas gratuitos (GlovePIE y PPJoy) obtuve este periférico bluetooth para que aparezca como un joystick en Windows, y por lo tanto también en Mathematica (a través del ControllerState). Por supuesto, bluetooth y UDP son bastante diferentes, pero ¿se podría hacer algo similar en la misma línea?

+0

Supongo que ninguna de las sugerencias en ese hilo funciona para usted, ¿verdad? –

+0

@ Mr.Wizard Parecía tratar con TCP en lugar de UDP, también involucraba a MathLink con el que no estoy muy familiarizado, usando código para una plataforma diferente (Unix/Solaris), basado en versiones antiguas de mma. Francamente, parecía mucho trabajo. Como podría haber paquetes cómodos escritos desde entonces, pensé que sería mejor esperar primero las sugerencias. –

+0

Mi pregunta puede haber dado a entender que debería buscar soluciones en ese hilo, pero esa no era mi intención. Por el contrario, solo quería confirmar que no sería de agradecer publicar una versión de una de las respuestas a ese hilo. Supongo que se podría suponer, y por lo tanto mi pregunta no tenía sentido. :-) –

Respuesta

4

JLink es definitivamente el camino a seguir. Prefiero mantener mi código Java y mi código de Mathematica separados compilando un programa Java que luego llamo desde Mathematica. He creado un programa de Notebook y compañero de Java que se puede agarrar aquí: http://facstaff.unca.edu/mcmcclur/UDPFiles.tar.gz

Aquí está el código esencial Mathematica:

Needs["JLink`"]; 
InstallJava[]; 
AddToClassPath[NotebookDirectory[]]; 
udpReader = JavaNew["myClient"]; 
i = 0; 
While[True && i++ < 100, 
    Print[[email protected][10552]]] 

La clase updReader se define por el siguiente código Java.

// A simple UDP client to read from iseismometer: 
// http://www.iseismometer.com/ 
// You can run this from the command line via "java myClient" 
// to check that your iseismometer setup is correct or you can 
// call the the udpReadOne method from another program. 

import java.io.*; 
import java.net.*; 
import java.util.*; 

public class myClient { 
    public static void main() throws IOException { 
     DatagramSocket socket = new DatagramSocket(10552); 
     byte[] buffer = new byte[500]; 
     DatagramPacket packet = new DatagramPacket(buffer, buffer.length); 
     while(true) { 
      socket.receive(packet); 
      String received = new String(packet.getData(), 0, packet.getLength()); 
      System.out.println(received); 
     } 
    } 

    public static String udpReadOne(int port) throws IOException { 
     DatagramSocket socket = new DatagramSocket(port); 
     byte[] buffer = new byte[100]; 
     DatagramPacket packet = new DatagramPacket(buffer, buffer.length); 
     socket.receive(packet); 
     String received = new String(packet.getData(), 0, packet.getLength()); 
     socket.close(); 
     return received; 
    } 
} 

Tenga en cuenta que puede utilizar el método principal de la clase MyClient para comprobar que su configuración está funcionando sin Mathematica, teniendo esencialmente un problema potencial fuera del circuito.

+0

Gracias Mark! Ver también mis comentarios @WReach. Difícil determinar cuál es la mejor solución.Ambos funcionan muy bien para hacer un gráfico en vivo de los datos que ingresan. Parece que el suyo es algo más fácil de usar si desea leer más iPhones al mismo tiempo, mientras que WReach es autónomo en mma y no requiere jugando con cosas externas de Java. –

4

Suponiendo que la configuración se discutió en un blog entry en el sitio web iSeismometer, un par de opciones vienen a la mente.

importación

La primera opción sería utilizar un programa externo para capturar los paquetes, y luego usar Import a traer a los resultados, por ejemplo,

Import["!someexternalprog", "Lines"] 

Por desgracia, el programa de Python se menciona en el blog no va a funcionar bien aquí ya que se ejecuta en un bucle sin fin que debe ser terminado manualmente. El enfoque Import solo funcionaría si ese programa se modificara para detenerse después de un número fijo de paquetes o un límite de tiempo o algo así.

JLINK

Un enfoque alternativo se puede implementar sin salir del entorno Mathematica cómoda mediante el uso de JLINK. Bueno, tal vez sea exagerado decir que nos quedamos dentro de Mathematica ya que una buena cantidad de código Java de aspecto divertido se mezcla con el código de Mathematica. Sin embargo, sirve para ilustrar la utilidad de los que los buques incorporados en la distribución de Java con cada copia de Mathematica:

Needs["JLink`"] 
LoadJavaClass["java.util.Arrays"]; 

[email protected] 
ListenToISeismometer[port_] := 
    [email protected][{socket, packet, listen, record = Null, listening = True} 
    , packet = JavaNew["java.net.DatagramPacket", JavaNew["[B", 1024], 1024] 
    ; listen[] := 
     If[$Failed =!= Quiet[[email protected][packet], Java::excptn] 
     , record = 
      JavaNew[ 
      "java.lang.String" 
      , java`util`Arrays`copyOfRange @@ packet /@ {getData[], getOffset[], getLength[]} 
      ]@toString[] // Sow 
     ] 
    ; Row[{Button["Stop", listening = False], Dynamic[record]}, " "] // PrintTemporary 
    ; AbortProtect[ 
     socket = JavaNew["java.net.DatagramSocket", port] 
    ; [email protected][1000] 
    ; Reap[While[listening, listen[]]; [email protected][]][[2, 1]] 
    ] 
    ] 

Algunos accesos directos se han tomado con respecto al manejo de excepciones, decodificación de paquetes y similares con el fin de mantener esta ejemplo en una longitud manejable.

ListenToISeismometer necesita recibir el número de puerto UDP para escuchar. Vamos a utilizar el mismo puerto como en la entrada del blog, 10552:

In[33]:= data = ListenToISeismometer[10552]; 

stop button

La función va a escuchar a todos los eventos de UDP en el puerto hasta que dicho parar. Se presenta un botón para este propósito, con cada paquete parpadeando a lo largo del lado tal como se recibió. Cuando se pulsa el botón, la función devuelve una lista de los paquetes recibidos:

In[34]:= data // Column 
Out[34]= 1,83575.099,0.029,0.044,0.094 
     1,83575.781,0.056,0.033,0.099 
     1,83575.924,0.047,0.054,0.094 
     1,83575.613,0.096,0.092,0.057 
     1,83575.748,0.073,0.049,0.061 
     1,83575.577,0.008,0.089,0.020 
     ... 

JLINK hace que este posible, pero no se puede escapar el hecho de que el uso de JLINK requiere un conocimiento práctico de Java.

+0

¡Gracias! Esto es fácilmente adaptable para mostrar un gráfico en vivo de los 3 canales del acelerómetro. Usar una matriz con 400 puntos de datos y un poco de 'RotateLeft' con los datos más recientes en la última posición me da un gráfico flotante agradable. Noté un poco de retraso que parece crecer con el tiempo. ¿Un búfer de lectura/escritura que se escribe más rápido de lo que se lee? No creo que se pueda ejecutar más de una instancia de 'ListenToISeismometer', ¿o sí? Si eso fuera posible, podría usar el iPhone de mi esposa y nuestro iPad para ver cómo las olas de la construcción del ferrocarril cercano viajan a través de nuestra casa. –

+0

@Sjoerd ListenToISeismometer no admitirá varias instancias tal como están escritas. La entrada del blog tiene una captura de pantalla que muestra un botón de "difusión" en ISeismometer - ¿quizás es compatible con la multidifusión UDP? Si es así, ListenToISeismometer debería cambiarse para usar sockets de multidifusión. Hay formas más directas de acelerar el rendimiento de paquetes mediante el uso de diferentes API de Java, pero no estoy seguro de si lo probaría a través de JLink. Probablemente inserte la mayor parte de la lógica en una clase Java normal, como en la solución de @Mark. – WReach