使用Mathematica连接到UDP数据流

时间:2011-04-29 21:29:26

标签: udp wolfram-mathematica

我的iPhone上有一个名为iSeismometer的应用程序,可以读取iPhone的加速度计,并充当通过UDP传输此数据的服务器(我可以设置IP地址和端口号)。问题是如何使用Mathematica读取此数据流?显然,Dreeves一直在研究这个12 years ago,所以我想在此期间肯定会发生一些事情。

更新
到目前为止我得到了两个很好的答案一个来自WReach,一个来自Mark McClure。两者都使用JLink来获取数据。这似乎是一个很好的方法。但是,我想起了我在WII平衡板上所做的一些工作。使用一些免费程序(GlovePIE和PPJoy),我得到了这个蓝牙外设,它作为Windows的操纵杆出现,因此也出现在Mathematica(通过ControllerState)。当然,蓝牙和UDP是完全不同的,但也可以使用同样的东西来工作吗?

2 个答案:

答案 0 :(得分:4)

假设在iSeismometer网站的blog entry中讨论了这个设置,我会想到几个选项。

导入

第一种选择是使用外部程序捕获数据包,然后使用Import引入结果,例如

Import["!someexternalprog", "Lines"]

唉,博客文章中提到的Python程序在这里不会很好用,因为它在无限循环中运行,必须手动终止。仅当该程序被修改为在固定数量的数据包或时间限制之后停止时,Import方法才有效。

<强> JLINK

通过使用JLink,无需离开舒适的Mathematica环境即可实现替代方法。好吧,或许可以说我们留在Mathematica中是因为有相当多的有趣的Java代码与Mathematica代码混合在一起。尽管如此,它确实说明了Mathematica的每个副本附带的内置Java发行版的实用性:

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

ClearAll@ListenToISeismometer
ListenToISeismometer[port_] :=
  JavaBlock@Module[{socket, packet, listen, record = Null, listening = True}
  , packet = JavaNew["java.net.DatagramPacket", JavaNew["[B", 1024], 1024]
  ; listen[] :=
      If[$Failed =!= Quiet[socket@receive[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]
    ; socket@setSoTimeout[1000]
    ; Reap[While[listening, listen[]]; socket@close[]][[2, 1]]
    ]
  ]

在异常处理,数据包解码等方面已经采取了一些快捷方式,以便将此示例保持在可管理的长度。

需要为

ListenToISeismometer提供要侦听的UDP端口号。让我们使用与博客文章10552中相同的端口:

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

stop button

该函数将侦听该端口上的所有UDP事件,直到被告知停止。为此目的提供了一个按钮,每个数据包在接收时沿着一侧闪烁。 按下该按钮时,该函数返回收到的数据包列表:

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使成为可能的,但是没有逃避使用JLink需要掌握Java知识的事实。

答案 1 :(得分:4)

JLink绝对是您的选择。我更喜欢通过编译Java程序来保持我的Java代码和Mathematica代码分离,然后我从Mathematica调用它。我设置了一个笔记本和伴侣Java程序,您可以在此处获取: http://facstaff.unca.edu/mcmcclur/UDPFiles.tar.gz

以下是Mathematica的基本代码:

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

updReader类由以下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;
    }
}

请注意,您可以使用myClient类的main方法检查您的设置是否在没有Mathematica的情况下正常工作,实质上是将一个潜在问题排除在循环之外。