打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
实验室:两个
最初由Tom Igoe
2015年10月5日撰写。最后由Tom Igoe 于2016年10月4日修改

介绍

内容[ 显示 ]

异步串行通信实验室简介中,您了解了通过异步串行通信管理计算机之间通信的各种方法。其中包括将数据格式化为ASCII编码的字符串或原始串行字节,并使用握手管理数据流。在  P5.js串行输入实验室中,您将数据从一个传感器发送到个人计算机。在本实验中,您将从多个传感器将数据发送到P5.js中的程序。您将使用传感器中的数据创建指向和选择设备(即鼠标)。

你应该知道什么

为了充分利用本教程,您应该知道微控制器是什么以及如何对它们进行编程您还应该了解微控制器和个人计算机之间的异步串行通信您还应该了解P5.js的基础知识首先要完成以下实验:

这些视频也有助于理解本实验室:

Things You’ll Need

For this lab, you’ll need the hardware below, and you’ll need to download the P5.js complete library. You’ll also need to install node.js and the P5.serialserver (instructions here). You can use the P5.js web editor or your favorite text editor for this (the Atom text editor works well).

solderless breadboardArduino module22-AWG hookup wire
accelerometer (or two other analog sensors)switch or pushbutton

Connect the sensors

Connect two analog sensors to analog pins 0 and 1 like you did in the analog lab. Connect a switch to digital pin 2 like you did in the digital lab.

The photos and schematic in this lab show an accelerometer and a pushbutton. You don’t have to use these, though. Use whatever sensors are appropriate to your final application. While you’re figuring what sensors to use, use the most convenient sensors you’ve got in hand; perhaps two potentiometers for the analog sensors and a pushbutton?

The circuit:
Schematic viewArduino with accelerometer and pushbutton

(Diagram made with Fritzing)

Note: Not all accelerometers are the same. However, Analog Electronics makes a very popular series of accelerometers, the ADXL3xx series, that have three analog outputs for X, Y, and Z acceleration. This schematic should work interchangeably for most of them.

Sending Multiple Serial Data using Punctuation

You’re going to program the microcontroller to read the pushbutton and two axes of the accelerometer (X and Y) just like you did in the Intro to Serial Communications Lab. When you have to send multiple data items, you need a way to separate them. If you’re sending them as ASCII-encoded strings, it’s simple: you can just put non-numeric punctuation bytes between them (like a comma or a space) and a unique termination punctuation at the end (like a newline and/or carriage return).

This program will send the two accelerometer values and then the pushbutton. All three will be ASCII-encoded numeric strings, separated by commas. The whole line of sensor values will be terminated by carriage return (\r, ASCII 13) and newline (\n, ASCII 10).

Here’s the code:

const int buttonPin = 2;      // digital input
 void setup() {
   // configure the serial connection:
   Serial.begin(9600);
   // configure the digital input:
   pinMode(buttonPin, INPUT);
 }
void loop() {
   // read the X axis:
   int sensorValue = analogRead(A0);
   // print the results:
   Serial.print(sensorValue);
   Serial.print(",");
   // read the y axis:
   sensorValue = analogRead(A1);
   // print the results:
   Serial.print(sensorValue);
   Serial.print(",");
   // read the button:
   sensorValue = digitalRead(buttonPin);
   // print the results:
   Serial.println(sensorValue);
}

When you run this and output it to the Serial Monitor, you should see something like this:

348,363,1344,362,1345,363,1344,375,0365,374,0358,369,0355,369,0352,373,0356,373,0

Tilt the accelerometer all the way on both the X and Y axes to find the upper and lower limits of both. For the one used to write this lab, both axes ranged from 250 to 410. Yours may vary. Now you’ve got a data format: three sensors, comma-separated, terminated by carriage return and newline. This means that you already have an algorithm for how you’re going to program P5.js to read the serial input:

Read the incoming serial data into a string until a carriage return and newline appearsplit the string into substrings on the commasconvert the substrings into numbersassign the numbers to variables to change your program

Now that you’ve got a plan, put it into action

Receive the data in P5.js

Now write a P5.js sketch that reads the data as formatted by the Arduino program above.

As you saw in the Serial Input to P5.js lab,  you’ll need to copy the p5.seriaport.js lbrary into your sketch’s libraries folder. You’ll need to run p5.serialcontrol, or run the p5.serialserver from the command line as you did in the Serial Input to P5.js lab as well.

Next, set up the beginning of your program as you did in the P5.js Serial Input lab, to import the serial library and make a global variable to hold an instance of it. Then in the setup(), create a canvas (640×480), make an instance of the serialport library, and declare your callback functions.  Then open the serial port that you want to use.

var serial;          // variable to hold an instance of the serialport library
var portName = '/dev/cu.usbmodem1411'; // fill in your serial port name here
function setup() {
 createCanvas(640, 480);          // make canvas
 smooth();                        // antialias drawing lines
 serial = new p5.SerialPort();    // make a new instance of the serialport library
 serial.on('list', printList);    // set a callback function for the serialport list event
 serial.on('connected', serverConnected); // callback for connecting to the server
 serial.on('open', portOpen);     // callback for the port opening
 serial.on('data', serialEvent);  // callback for when new data arrives
 serial.on('error', serialError); // callback for errors
 serial.on('close', portClose);   // callback for the port closing
 serial.list();                   // list the serial ports
 serial.open(portName);           // open a serial port
}

Program the draw() function to draw a circle that’s dependent on three global variables, locH, locV, and circleColor. Add these three globals to the top of the program:

var locH, locV;        // location of the circle
var circleColor = 255; // color of the circle
function draw() {
 background(0);               // black background
 fill(circleColor);           // fill depends on the button
 ellipse(locH, locV, 50, 50); // draw the circle
}

The serial event handlers are all the same as you saw in the P5.js Serial Input Lab, except for the serialEvent(). Here are all but the serialEvent():

// get the list of ports:
function printList(portList) {
 // portList is an array of serial port names
 for (var i = 0; i < portList.length; i++) {
 // Display the list the console:
 println(i + " " + portList[i]);
 }
}
function serverConnected() {
 println('connected to server.');
}
function portOpen() {
 println('the serial port opened.')
}
function serialError(err) {
 println('Something went wrong with the serial port. ' + err);
}
function portClose() {
 println('The serial port closed.');
}

Program the serialEvent() function to read the incoming serial data as a string until it encounters a carriage return and newline (‘\r\n’). Then check to see that the resulting string has a length greater than 0 bytes. If it does, use the split() function to split it in to an array of strings. If the resulting array is at least three elements long, you have your three sensor readings. The first reading is the X axis of the accelerometer, and can be mapped to the horizontal movement using the locH variable. The second is the Y axis and can be mapped to the locV variable. The third is the button. When it’s 0, set the circleColor variable equal to 255 and when it’s 1, set the variable to 0. Here’s how:

function serialEvent() {
  // read a string from the serial port
  // until you get carriage return and newline:
  var inString = serial.readStringUntil('\r\n');
  //check to see that there's actually a string there:
  if (inString.length > 0 ) {
    var sensors = split(inString, ',');            // split the string on the commas
    if (sensors.length > 2) {                      // if there are three elements
      locH = map(sensors[0], 250, 410, 0,width);   // element 0 is the locH
      locV = map(sensors[1], 250, 410, 0, height); // element 1 is the locV
      circleColor = 255 - (sensors[2] * 255);      // element 2 is the button
    }
  }
}

Note the mappings of sensor[0] and sensor[1]. You should use the input mappings for your accelerometer instead of 250 and 410. If your analog values are greater than 640 or 480, the circle will be offscreen, which is why you have to map your sensor range to the screen size.

If you run this, you should see the circle moving onscreen whenever you tilt the accelerometer. When you press the pushbutton, the circle will disappear. Okay, it’s not exactly a  mouse, but you are controlling an animation from a device that you built.

Flow Control: Call and Response (Handshaking)

You’ve seen now that by coming up with a serial format (called a protocol), you can write the algorithm for receiving it even before you see any data. You can send multiple pieces of data this way, as long as you format it consistently.

Sometimes you can run into a problem when the sender sends faster than the receiver can read. When this happens, the receiver program slows down as the serial buffer fills up. You can manage this by implementing some form of flow control. The simplest way do to this is using a call-and-response method, where the sending program only sends when it’s told to do so, and the receiving program has to request new data every time it finishes reading what it’s got.

You can add handshaking to the code above fairly simply. Modify the Arduino code as follows. First, add a a new block of code in the setup() This block sends out a message until it gets a byte of data from the remote computer:

void setup() {
  Serial.begin(9600);
  while (Serial.available() <= 0) {
    Serial.println("hello"); // send a starting message
    delay(300);              // wait 1/3 second
  }
}

Now, modify the loop() by adding an if() statement to look for incoming serial data and read it.

void loop() {
  if (Serial.available() > 0) {
    // read the incoming byte:
    int inByte = Serial.read();
    // read the sensor:
    sensorValue = analogRead(A0);
    // print the results:
    Serial.print(sensorValue);
    Serial.print(",");
    // read the sensor:
    sensorValue = analogRead(A1);
    // print the results:
    Serial.print(sensorValue);
    Serial.print(",");
    // read the sensor:
    sensorValue = digitalRead(switchPin);
    // print the results:
    Serial.println(sensorValue);
  }
}

The rest of the sketch remains the same. When you run this and open the serial monitor, you’ll see:

hellohellohellohello

Type any character in the output box and click Send. You’ll get a string of sensor values at the end of your hellos:

510,497,0

Type another character and click Send. It doesn’t matter what character you send, but the loop will always wait for an incoming byte before sending a new set of sensor values. When you write a program to receive this format, it just has to behave the same way you did:

Open the serial portWait for a HelloSend a byte to request dataBegin loop:  Wait for one set of data  Send a byte to request new dataend loop

Next, modify the P5.js sketch.  All the changes are in the serialEvent() function. The initial “hello” messages will trigger this function, so when you get a “hello” or any other string, you need to send a byte back so that the Arduino has a byte available to read. Here’s the new serialEvent():

function serialEvent() {
  // read a string from the serial port
  // until you get carriage return and newline:
  var inString = serial.readStringUntil('\r\n');
  //check to see that there's actually a string there:
  if (inString.length > 0) {
    if (inString !== 'hello') {           // if you get hello, ignore it
      var sensors = split(inString, ','); // split the string on the commas
      if (sensors.length > 2) { // if there are three elements
        locH = map(sensors[0], 250, 410, 0, width); // element 0 is the locH
        locV = map(sensors[1], 250, 410, 0, height); // element 1 is the locV
        circleColor = 255 - (sensors[2] * 255);      // element 2 is the button
      }
    }
    serial.write('x'); // send a byte requesting more serial data
  }
}

That’s it. Your sketch should still run just as it did before, though the serial communication is managed better now, because Arduino’s only sending when P5.js is ready to receive.

The full code for all the examples in this lab can be found in this gitHub repository.

Advantages of Raw Binary vs. ASCII

All the examples shown here sent the sensor values as ASCII-encoded strings. As mentioned above, that means you sent three bytes to send a three-digit value. If that same value was less than 255, you could send it in one raw binary byte. So ASCII is definitely less efficient. However, it’s more readable for debugging purposes, and if the receiving program is well-suited to convert strings to numbers, then ASCII is a good way to go. If the receiver’s not so good at converting strings to numbers (for example, it’s more challenging to read a multiple byte string in Arduino than in Processing) then you may want to send your data as binary values.

Advantages of Punctuation or Call-and-Response

The punctuation method for sending multiple serial values may seem simpler, but it has its limitations. You can’t easily use it to send binary values, because you need to have a byte with a unique value for the punctuation. In the example above, you’re using the value 10 (ASCII newline) as punctuation, so if you were sending your sensor values as raw bytes, you’d be in trouble when the sensor’s value is 10. The receiver would interpret the 10 as punctuation, not as a sensor value. In contrast, call-and-response can be used whether you’re sending data as raw binary values or as ASCII-encoded values.

Sometimes the receiver reads serial data slower than the sender sends it. For example, if you have a program that does a lot of graphic work, it may only read serial data every few milliseconds. The serial buffer will get full in that case, you’ll notice a lag in response time. This is when it’s good to switch to a call-and-response method.

Get creative

This is just a suggestion for a short project. It’s not a requirement for the class homework.
You just duplicated the basic functionality of a mouse; that is, a device with two analog sensors that affect X and Y, and a digital sensor (mouse button). What applications can you think of that could use a better physical interface for a mouse? A video editor that scrubs forward and back when you tilt a wand? An action game that reacts to how hard you hit a punching bag? An instructional presentation that speeds up if you shift in your chair too much? A music program driven by a custom musical instrument that you design?

在Arduino和P5.js,Node.js,Processing或您选择的任何编程环境中创建原型。提出一个物理界面,清楚地说明哪些动作映射到什么动作和动作。找出可以并且应该可以同时执行哪些操作。提出您的想法的工作软件和硬件模型。

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
Sparki SLAM
Go语言字符串
Character Encodings for Localizing Alphabets
【玩转开源】基于Arduino的同步机械臂
用uno 和GSM900短信模块制作个简易的液化气报警器
关于sensor在android系统framework和应用中的使用 | 卓派观点
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服