您尝试做的事情有点令人困惑,但据我所知,困惑在于串行通信。
以下是我如何理解通信如何与您当前的代码一起工作以及一些问题:
1. 截断
您正在编写px
映射到草图尺寸的内容(我在任何地方都看不到,所以猜测它是默认的 100x100 吗?)。
如果尺寸大于 255,这可能是个问题。
即使通过处理串行write(int)需要一个 int,它在幕后使用jssc.Serial.writeInt()取值从 0 到 255。(本质上它写入一个字节,但在 0-255 范围内,其中byte
Processing java中的类型是从 -127 到 128)。
如果要发送大于 255 的值,则需要将它们拆分为单独的字节。(请参阅 ARGB 值拆分示例,使用位移位和 AND 掩码以及使用OR将各个字节组合成一个多字节整数)
2. 重复
px
在 for 循环中再次发送:myPort.write(lista[i]);
代码无论如何都被注释了,但要注意这一点。就我个人而言,我制作了新的简单测试草图来解决单个简单问题,而不是大型未使用的块,这使得代码更难阅读/导航并最终调试。我鼓励你将更大的问题分解为多个更简单的单个问题,并一次解决一个。
3. 数据终止
注释代码尝试发送 4 个整数,但 Arduino 无法知道数据到达的顺序。如果出现任何问题,将很难说出顺序是什么。
有多种方法可以做到这一点。理想情况下,您会编写一个通信协议。(关于这个主题有很多资源。)
学习使用位/字节/字节数组并从头开始将通信协议与某种形式的数据验证(校验和 / CRC / 等)组合在一起,这听起来像是一个有趣的项目
如果您时间紧迫,并且您只想驱动伺服器而不必担心通过串行可靠地发送多个(可能)大值,我建议您尝试Firmata 处理
您需要将 Firmata 固件刷新到您的 Arduino,然后使用 Firmata 处理库连接到串行端口(使用正确的波特率)并arduino.servoWrite()
根据需要调用。另请参阅库的arduino_servo
示例。
根据您对 0 -> 100 之间的映射值的评论,您可以使用大于 100 的任何其他字符重新调整SerialEvent 示例的用途,以区分数据与字符串终止符字符。请记住,您将失去精度:
getValue()
返回float
具有 32 位精度的
- 理论上,您可以对 0-254 使用相同的技术(使用 255 作为终止符)。0-100 范围使用 6 位
考虑到代码尚未使用实际设备进行测试,以下是代码中可能看起来的粗略示例:
加工:
import processing.serial.*;
import org.gamecontrolplus.gui.*;
import org.gamecontrolplus.*;
import net.java.games.input.*;
Serial myPort;
ControlIO control;
ControlDevice stick;
float px, py, pz, pw;
// px,py,pz,pw remapped to 0-100 range
int[] lista = new int[4];
// px,py,pz as bytes + terminator character (255)
byte[] toArduino = {0,0,0,0,(byte)255};
public void setup() {
size(100,100);
lista = new int[4];
String portName = Serial.list()[2];
try{
myPort = new Serial(this, portName, 9600);
}catch(Exception e){
println("error connecting to serial port: " + portName);
e.printStackTrace();
}
surface.setTitle("GCP Joystick example");
control = ControlIO.getInstance(this);
try{
stick = control.filter(GCP.STICK).getMatchedDevice("joystick");
}catch(Exception e){
e.printStackTrace();
}
if (stick == null) {
println("No suitable device configured");
}
}
public void getUserInput() {
if(stick == null){
return;
}
// map values
px = map(stick.getSlider("X").getValue(), -1, 1, 0, width);
py = map(stick.getSlider("Y").getValue(), -1, 1, 0, height);
pz = map(stick.getSlider("Z").getValue(), -1, 1, 0, width);
pw = map(stick.getSlider("W").getValue(), -1, 1, 0, height);
// cast to int
lista[0] = (int)px;
lista[1] = (int)py;
lista[2] = (int)pz;
lista[3] = (int)pw;
// update bytearray
toArduino[0] = (byte)lista[0];
toArduino[1] = (byte)lista[1];
toArduino[2] = (byte)lista[2];
toArduino[3] = (byte)lista[3];
}
// Event handler for the SHADOW button
public void draw() {
getUserInput(); // Polling the input device
background(255, 255, 240);
fill(0, 0, 255, 32);
noStroke();
text("px: " + px
+"\npy: " + py
+"\npz: " + pz
+"\npw: " + pw
,5,15);
if(myPort != null){
myPort.write(toArduino);
}
}
阿杜诺:
/*
Serial Event example
When new serial data arrives, this sketch adds it to a String.
When a newline is received, the loop prints the string and clears it.
A good test for this is to try it with a GPS receiver that sends out
NMEA 0183 sentences.
NOTE: The serialEvent() feature is not available on the Leonardo, Micro, or
other ATmega32U4 based boards.
created 9 May 2011
by Tom Igoe
This example code is in the public domain.
http://www.arduino.cc/en/Tutorial/SerialEvent
*/
String inputString = ""; // a String to hold incoming data
bool stringComplete = false; // whether the string is complete
const char TERMINATOR = (char)255;
void setup() {
// initialize serial:
Serial.begin(9600);
// reserve 200 bytes for the inputString:
inputString.reserve(200);
}
void loop() {
// in case serialEvent() isn't called automatically
serialEvent();
// print the string when a newline arrives:
if (stringComplete) {
// process string
uint8_t px = inputString.charAt(0);
uint8_t py = inputString.charAt(1);
uint8_t pz = inputString.charAt(2);
uint8_t pw = inputString.charAt(3);
// TODO: pass this to servos
// debug print
Serial.print("px:");
Serial.print(px);
Serial.print("\tpy:");
Serial.print(py);
Serial.print("\tpz:");
Serial.print(pz);
Serial.print("\tpw:");
Serial.println(pw);
// clear the string:
inputString = "";
stringComplete = false;
}
}
/*
SerialEvent occurs whenever a new data comes in the hardware serial RX. This
routine is run between each time loop() runs, so using delay inside loop can
delay response. Multiple bytes of data may be available.
*/
void serialEvent() {
while (Serial.available()) {
// get the new byte:
char inChar = (char)Serial.read();
// add it to the inputString:
inputString += inChar;
// if the incoming character is a newline, set a flag so the main loop can
// do something about it:
if (inChar == TERMINATOR) {
stringComplete = true;
}
}
}