用Arduino与Mathematica编写世界

作者:Ian Johnson, Wolfram Research

原文:http://community.wolfram.com/groups/-/m/t/315748

大家好,今天我来给大家演示一下Mathematica写的Arduino驱动,
使用了Mathematica 10中的新函数。下面的演示用到了以下工具:

  • Mathematica 10
  • Arduino IDE
  • Arduino板(推荐使用Uno)
  • 220Ω电阻
  • 10kΩ电阻
  • LED
  • 瞬时按压按钮
  • 两个电位计

上面当中的硬件都可以在Arduino官方的新手包找到,市面上几乎所有的Arduino包也都有这些东西。

我开发的函数理论上是和操作系统无关的,也就是说,Linux、Mac OS X、Windows等等都可以跑。但是我在开发时是用的Windows,所以我只能保证它在Windows上好使。很欢迎其他同好在Linux和Mac OS X上试试,并把结果贴出来。

第一步是把我给Arduino写的程序(Arduino sketch)上传到Arduino上,你可以用Arduino IDE来做这一步。

想要下载Arduino程序的话,请看帖子附件。我把文件扩展名从.ino改成.txt了,所以你得把它改回来,才能让Arduino读取。

然后选择你的Arduino型号(我这个是给Uno做的,我只能保证它在Uno上正常工作,就像前面说的,理论上可以在任何Arduino型号上运行),打开你下载的.ino文件,把它上传到板子上。

程序上传完成后,连接Arduino,确定你的Arduino接到了哪个串口上。有一个简单的方法:打开Arduino IDE,在菜单中找“工具→端口”。在Windows系统上,端口名是"COMXX""XX"是一个非负整数。在Mac上,一般是"/dev/tty.usbmodemXXXXXX",或者"/dev/tty.usbserialXXXXXX",“X”是由字母和数字组成的字符串。在Linux中,一般是"/dev/ttyXXXX",“X”也是字母和数字构成的字符串。把这个串口名记住,过一会我们要用。

最后一步是安装驱动。可以在帖子附件下载到。下载之后用Mathematica 10打开,然后运行:

1
<< "文件路径/ArduinoDriver.m"

“文件路径”即你下载的文件所在路径,比如在Windows上,可能是C:\Users\Ian\Downloads\ArduinoDriver.m

现在打开我们正在使用设备的连接:

1
arduinoObject = DeviceOpen["Arduino", "COM4"]

“COM4”是我的串口,把它换成你的Arduino连接的串口。为了实现基本的设备控制,我们可以用:

1
DeviceWrite[arduinoObject, <|pinNumber -> 1|>]

这样就可以控制pinNumber的数字状态。pinNumber可以是2到13的整数,也可以是代表模拟针脚的字符串,即“A0”到“A5”,注意首字母必须大写。

按照下面的Fritzing图接好LED:



然后就可以在Mathematica中写LED闪烁的代码了:

1
2
3
4
5
Do[(
DeviceWrite[arduinoObject, <|pinNumber -> 1|>];
Pause[1];
DeviceWrite[arduinoObject, <|pinNumber -> 0|>];
Pause[1]), {5}]

这么做会使连接在pinNumber的LED闪烁5次,每次1秒钟。注意pinNumber必须在别处定义过,对于上述代码应该是11。

我们也可以使用DeviceWrite函数向Arduino发送信息,使Arduino模拟输出。语法如下:

1
DeviceWrite[arduinoObject, {pinNumber, "analogOutput", state}]

pinNumber是一个有效的针脚数值,state是从0到255的整数,对应着PWM针脚的8位输出。

如果你的LED正如上图连接着,下面的代码可以让你调节LED亮度。注意,当数值大幅变化时,亮度会回跳,这是一个已知的bug。

1
Manipulate[DeviceWrite[arduinoObject, {11, "analogOutput",  analogWriteValue} ], { {analogWriteValue, 0, "Value"}, 0, 255, 1}]

我们也可以从Arduino读取针脚状态,使用DeviceRead函数。但是在我们可以读取数据之前,我们需要用DeviceConfigure函数配置数据读取。通过以下语句将pinNumber针脚配置为一个数字输入:

1
DeviceConfigure[arduinoObject, <|pinNumber -> "digitalInput"|>]

模拟针脚同样适用。语法相同,只需要把“digitalInput”改成“analogInput”。注意,在使用多个针脚时,上面的语句是可以扩充的,用了一个关联(association,Mathematica 10引入的新特性,类似于其他语言中的“字典”,译者注)。在这种情况下,我们只需要在联合中增加新的键值对就行了。

我们来试一试在下面的简单电路中读取一个针脚,用到了一个按钮和一个电阻:



对上面的电路,为了读取数值,用如下语句:

1
DeviceRead[arduinoObject, pinNumber]

这条语句返回针脚的数值,0代表低电平,1代表高电平。如果就按上面的电路图搭建的话,按钮按下时表达式估值返回1,没有按下时返回0。在表达式第一次估值时,串口读取缓存可能一次会读取两个数值再更新,但是这之后就会变得正常起来。

如果pinNumber指定了一个模拟输入针脚,返回值应该是0到1023的一个数,对应着Arduino模拟针脚上的10位输出。这一函数同样可以使用一个针脚编号列表作为参数,返回值就成了一个由多个针脚与对应读到数值构成的关联(association)。注意,pinNumber既可以是2到13的非负整数,也可以是一个字符串表示“AX”,X是0到5的非负整数。
如下所示:

1
DeviceRead[arduinoObject, {pinNumber1, pinNumber2, ...}]

返回为一个关联<|pinNumber1->state1, pinNumber2->state2, ... |>

下面的电路演示模拟输入函数。最理想的是用游戏摇杆做这个,但是下面我们仅仅用两个电位器就可以实现(其实游戏摇杆就是电位器)。



下面的代码可以在Mathematica中显示一个坐标系,由两个电位计控制。首先要做的事是初始化模拟输入的针脚。我们可以从DeviceRead中通过关联(association)读取两个电位器,然后用Values函数得到数值,再将坐标系单位除以1023,使圆的坐标映射到0和1之间。我们也同样将中间值从0.5移到原点。

1
2
3
4
5
6
DeviceConfigure[arduinoObject, <|"A0" -> "analogInput", "A1" -> "analogInput"|>];
Dynamic[Graphics[{Blue,
Circle[ (Values[DeviceRead[arduinoObject, { {"A0", "A1"} }]])/1023 - .5, 0.1]},

Axes -> True, ImageSize -> {800, 800},
PlotRange -> { {-.75, .75}, {-.75, .75} }],
UpdateInterval -> .5]

电位器控制坐标系中的圆

谢谢!