Done it all by the book, but Serial Write still doesn't work?
in
Core Library Questions
•
1 year ago
I used Serial object in its simplest form to write a String to a COM port. That is to send some data to Arduino. But Serial object's .write() method sometimes works and sometimes not, without any rime or reason. When main program does lots of calculations before Serial write() than it doesn't work. If one just writes a short program, no calcs, no screen updates, than Serial write() works brilliantly.
This is the main program, that has the problem. It simulates a spherical joystick. When this program completes all the screen redraws and calcs, it send X and Y to the Arduino, via Serial object, like: objSerial.write("servox" + nfs(int(50 * x),0) + "\n"); I temporarily switched that line off, and replaced it with: objSerial.write("servox 888\n"); just for debugging.
In order to verify that Serial write() syntax works, I wrote two more programs. One sending data from Processing, one receiving data on the Arduino side. Both these test programs work flawlessly, right of the but. Here is the first one, for Processing:
Here is the Arduino sketch, receiving the data. Arduino has 4x20 LCD attached, and this sketch works perfectly well with the above Processing syntax test program.
What is strange is that I am using the same Serial write() syntax in both working and non-working programs. I simply can't see what is wrong?
This is the main program, that has the problem. It simulates a spherical joystick. When this program completes all the screen redraws and calcs, it send X and Y to the Arduino, via Serial object, like: objSerial.write("servox" + nfs(int(50 * x),0) + "\n"); I temporarily switched that line off, and replaced it with: objSerial.write("servox 888\n"); just for debugging.
- /**
* v2.00.b
*
* Spherical Joystick converts Cartesian screen mouse cursor coordinates into Polar coordinates.
* As well, it graphically and numerically shows the current orientation of the joystick.
*
* Spherical coordinate system defined according to the convention used in mathematics, check:
*
* http://en.wikipedia.org/wiki/Spherical_coordinate_system
*
* Revisions:
*
* 15:41 8.5.12 - Added Serial communication with Arduino sketch:
* Arduino_Servo_x2_PPM_Serial_v1_00_a
*
* @author Dejan Corovic: dejan.corovic@btinternet.com
*
* Professional Programming in: Java, JSP, SQL Server, MySQL, JavaScript and AJAX.
*/
import processing.serial.*;
float D; // Diameter of the joystick sphere, in pixels,
float x; // Mice's X-axis coordinate, relative to translated origin, in pixels,
float y; // Mice's Y-axis coordinate, relative to translated origin, in pixels,
float z; // Z-axis coordinate of the north pole of the spherical joystick,
float theta; // Polar coordinate: the clockwise angle from X-axis, in radians,
float phi; // Polar coordinate: the angle from Z-axis, in radians,
float phi_x, phi_y; // phi angle's projection onto X-Z and Y-Z plane, respectively,
// in radians,
float inclined_r_x; // Projection of the radius of the inclined meridian Y-Z plane's
// circle onto X-axis, in pixels,
float inclined_r_y; // Projection of the radius of the inclined meridian X-Z plane's
// circle onto Y-axis, in pixels,
PFont objLoadedFont; // Object for storing bitmap fonts,
Serial objSerial; // Serial communication object.
boolean blnResetJoystick; // First mouse click locks joystick to the origin. Second
// click releases it to follow user's movement.
float screen_center_X = 100.0; // Not used, but nice to have.
float screen_center_Y = 100.0;
void setup() {
size(200, 300);
smooth();
// This is bitmap font, originally in size 12. File can be found in the 'data'
// subdirectory of this Processing scetch.
objLoadedFont = loadFont("TheSans-Plain-12.vlw");
textFont(objLoadedFont);
// Serial communication setup. Check which comport Arduino is on and type it here.
println(Serial.list());
objSerial = new Serial(this, "COM6", 9600);
///objSerial.bufferUntil('\n');
// Define known variables: spherical joystick's diameter, reset mouse.
D = 100.0;
blnResetJoystick = true;
fill(0,0,255); textSize(12); text("Click to continue", -65, -95);
}
void draw() {
background(192);
rectMode(CENTER); // show bounding boxes
translate(width/2, 100); // Move the origin of canvas to x= 100, y= 100 pix.
stroke(0); line(-90, 100, 90, 100); // Decorative.
// Get mice's Cartesian coordinates position. Computer screen's Y-axis needs to
// be inverted because it grows downwards. Mouse click locks joystick back to
// the origin. Next click releases joystick. So, mouse click works like toggle.
if (!blnResetJoystick) {
x = round( (mouseX / float(width) - 0.5) * float(width) );
y = round( (0.5 - mouseY / float(200)) * float(200) );
fill(192); textSize(12); text("Click on center to continue", -75, -60);
} else {
x = 0; y = 0;
fill(0,0,255); textSize(12); text("Click on center to continue", -75, -60);
}
// DRAW THE GRAPHICS:
fill(0); textSize(16); text("Spherical Joystick", -65, -80);
// Display mouse cursor's Cartesian coordinates on the canvas.
fill(0); textSize(12);
text("x= " + int(x) + " pix", -80, 120);
text("y= " + int(y) + " pix", 10, 120);
// Print to the console, for debugging.
//DEBUG//println("r = " + D / 2);
//DEBUG//println("x = " + x);
//DEBUG//println("y = " + y); println();
// Transfer from screen's Cartesian pixel coordinates into the Polar coordinates.
z = sqrt(sq(D/2) - (sq(x) + sq(y))); //DEBUG//println("z = " + z);
phi = acos(2*z/D); //DEBUG//println("phi = " + phi);
theta = atan2(y, x); //DEBUG//println("theta= " + theta);
phi_x = atan(abs(x/z)); //DEBUG//println("phi_x= " + phi_x);
phi_y = atan(abs(y/z)); //DEBUG//println("phi_y= " + phi_y);
// Display the above results on the canvas.
fill(0);
text("z= " + nfs(z, 0, 2) + " pix", -80, 135);
text("phi = " + nfs(phi, 1, 3) + " rad / " + nfs(degrees(phi), 0, 2) + " deg", -80, 165);
text("theta= " + nfs(theta, 1, 3) + " rad / " + nfs(degrees(theta), 0, 2) + " deg", -80, 180);
// Projections onto X and Y axis of the meridian circles.
inclined_r_x = D * sin(phi_x); //DEBUG//println("inclined_r_x= " + inclined_r_x);
inclined_r_y = D * sin(phi_y); //DEBUG//println("inclined_r_y= " + inclined_r_y);
// The outer edge of the spherical joystick:
noStroke(); fill(255); ellipse(0, 0, D, D);
// Inclined X-Z plane ellipse:
noFill(); stroke(128);
arc(0, 0, D, inclined_r_y, ((0 < y) ? PI : 0), ((0 < y) ? 2 * PI : PI));
// Inclined Y-Z plane ellipse:
noFill(); stroke(128);
arc(0, 0, inclined_r_x, D, ((0 < x) ? 1.5 * PI : 0.5 * PI), ((0 < x) ? 2.5 * PI : 1.5 * PI));
// Linear joystick, as a green line. We'll extend joystick by 5 pixels so it is
// easier to see its orientation.
stroke(64, 255, 64); strokeWeight(3); strokeCap(ROUND);
line(0, 0, ((0 < x) ? 1.0 : -1.0) * (D/2 + 5) * sin(phi_x), - ((0 < y) ? 1.0 : -1.0) * (D/2 + 5) * sin(phi_y));
strokeWeight(1);
// Inclined X-Y equator:
noFill(); stroke(0);
pushMatrix();
rotate(PI/2 - theta);
arc(0, 0, D, D * cos(phi), ((0 < y) ? 0 : 0), ((0 < y) ? PI : PI) );
popMatrix();
// Send positioning commands to Arduino, for X and Y servos.
///print("servox" + nfs(int(50 * x),0) + "\n");
print("servox 888\n");
objSerial.write("servox 888\n");
///objSerial.write("servox" + nfs(int(50 * x),0) + "\n");
///objSerial.write("servoy" + nfs(int(50 * y),0) + "\n");
delay(1000);
} // void draw() ...
void mouseClicked() {
if (blnResetJoystick) {
blnResetJoystick = false;
} else {
blnResetJoystick = true;
}
}
In order to verify that Serial write() syntax works, I wrote two more programs. One sending data from Processing, one receiving data on the Arduino side. Both these test programs work flawlessly, right of the but. Here is the first one, for Processing:
- /**
* v1.00.a
*
* This sketch illustrates how to send commands with parameters to an Arduino sketch. Commands
* need to be terminated with LF or CR. This Processing sketch is made to work with Arduino
* sketch:
*
* Arduino_LCD_Serial_ByVac_BV4618_and_Serial_Com
*
* Arduino needs to have LCD display attached and configured. The above Arduino sketch is using
* the HD44780 LCD (4x20) controller with ByVac BV4618 serial controler.
*
*
* Updates:
*
* 15:37 9.5.12 - v1.00.a = Initial code.
*
*/
import processing.serial.*;
// The serial port:
Serial myPort;
int i = -1; // Counter for switch() statement must start from -1, not 0, as one
// would imagine.
void setup() {
// List all the available serial ports:
println(Serial.list());
// Just pick up the serial port to which Arduino is hooked, or find where Arduno
// sits in Control Panel > System > Device Manager > USB Ports.
myPort = new Serial(this, "COM6", 9600);
}
void draw() {
/*
* It was found through experimentation that Processing wants to execute only one write()
* statement per loop. If you try to execute two write()'s it freezes, it doesn't even reset
* Arduino, what is otherwise normal at a begining of Processing sketch run!
*
* Processing's switch() statement, on other hand, wants to start itterator from -1, not 0,
* as it would be logical.
*
* For multiple write() statements, sending multiple commands to Arduino, just stuck them up,
* like: "servox 472\nsrx 2437\n", by using '\n' as command delimeter.
*/
switch (i) {
case 0:
// Line must be terminated either '\n' or '\r' characters.
myPort.write("servox 1379\n"); break;
case 1:
myPort.write("servoy 20\r"); break;
case 2:
// Comands can be stuck up, one after another, like this:
myPort.write("srx 640\nsry 480\n"); i = -1; break;
}
i++;
// HUGE DISCOVERY!!! Only send one write() statement per loop. Trying this second one, blocks
// the Processing code, at a runtime, and it doesn't even reset Arduino!
///myPort.write("servoy 20\n");
delay(3000);
}
Here is the Arduino sketch, receiving the data. Arduino has 4x20 LCD attached, and this sketch works perfectly well with the above Processing syntax test program.
- /**
* v1.00.a
*
* Sending characters and words, via terminal like Serial Monitor, to Arduino and displaying
* them on the attached ByVac BV4618 serial interface. ByVac BV4618 is attached to Negative
* Black LCD Display HD44780 4x20 (YMFC-C2004).
*
* Modified the original example file by removing all that looked like keypad instruction.
*
* Circuit:
*
* - ByVac BV4618, the HD44780 LCD controller with Serial, RS232 and I2C interface,
* http://doc.byvac.com/index.php5?title=Product_BV4618
*
* - LCD Display HD44780 4x20 Black NEG Backlight (YMFC-C2004),
* http://www.ebay.co.uk/itm/LCD-Display-HD44780-4x20-chr-20x4-Black-NEG-Backlight-/170440872374?pt=Bauteile&hash=item27af1151b6
*
* - power from Arduino, Vcc= +5.0V (red wire) and Gnd (black wire),
* - 2.7kOhm resistor between LCD's Gnd (1st pin) and Vo (3rd pin),
* - Ard.PWM.pin #4 - Ard's TX pin, to BV4618's RX pin, white wire,
* - Ard.PWM.pin #5 - Ard's RX pin, to BV4618's TX pin, green wire,
*
* Usage:
*
* Settings:
*
* - Terminal program of choice, like Arduino IDE's Serial Monitor, must be set to:
*
* - Baud rate ........... 9,600
* - Line termination .... Newline
*
* - If instructions are sent via serial port from another program, like Processing, than
* lines must be terminated with '\n' or '\r'. For example, these are good ones:
*
* "servox 1375\n" or "SRY 12\r"
*
* Space or ' ', is not used as delimeter. Space ' ' is treated just as any other character.
*
* Input:
*
* - Type in: 'test1' (without quotes), than press return. Line termination must bed done
* with LF and CR. If you want to use ' ' or char(32) for line termination, you must change
* code.
* - Output to above will be 'test1,' (without quotes), etc. All outputs will follow
* each other like: test1,test 2,test3,test4 etc.
*
* This Arduino sketch is made to work with Processing sketch:
*
* Processing_Serial_Write_Command_Line_1
*
* Updates:
*
* 15:37 9.5.12 - v1.00.a = Initial code.
*
*/
#include <BSerial.h>
#include <bv4618_S.h>
#define rxPin 5
#define txPin 4
BV4618_S lcdByVacSerial(rxPin, txPin);
boolean blnLCDRefresh = true;
char incomingChar = 0; // Arduino receiving incoming serial data into int variable.
const int SERIAL_INPUT_BUFFER_SIZE = 32; // Input line lenght up to 31 characcters.
char arrChrBuffer[SERIAL_INPUT_BUFFER_SIZE];
int i;
void setup() {
// 9600 Baud, 0 delay, '*' as ACK
lcdByVacSerial.begin(9600,50,'*');
// N.B. puts() is for arrays of char-s, or char*, but not Sting-s, putch() for individual Char-s.
// 4 x 20 display
lcdByVacSerial.puts("\e[4L\e[20c");
// clear screen, needs a delay
lcdByVacSerial.puts("\e[2J"); delay(50);
// cursor on, as a static underline.
lcdByVacSerial.puts("\e[?25h");
// Start up our serial port, we configured our XBEE devices for 38400 bps.
Serial.begin(9600);
}
void loop() {
// Only print to LCD if there is a new stuff to show. Otherwise LCD characters blink anoyingly.
if (blnLCDRefresh) {
///lcdByVacSerial.puts("Awaiting input:");
// Set LCD's cursor to line 2, column 1.
///lcdByVacSerial.puts("\e[2;1H");
blnLCDRefresh = false;
}
// If character was received, show it on LCD display.
while (Serial.available() > 0) {
// Read the received bytes:
incomingChar = Serial.read(); // Incoming char will become int ASCII ordinal.
// Write into the character array all characters, except line termination ones, like: LF
// and CR.
if (incomingChar != '\n' && incomingChar != '\r') {
arrChrBuffer[i] = arrChrBuffer[i] + incomingChar;
i++;
} else {
// This break enables stucking up of multiple commands together, like: "srx 640\nsry 480\n"
// Individual commands just need to be separated by '\n' characters. When first '\n' is met,
// character array that was extracted up to that point is processed. But the rest of multi-
// command is still in the serial buffer and it is extracted in the next loop. Voila!
break;
}
}
// LF and CR are used for line termination.
if (incomingChar == '\n' || incomingChar == '\r') {
// Output to LCD.
// N.B. puts() is for arrays of char-s, or char*, but not Sting-s, putch() for individual Char-s.
lcdByVacSerial.puts(arrChrBuffer); lcdByVacSerial.putch(',');
// Move LCD's cursor up one place.
///lcdByVacSerial.puts("\e[1A");
// Set LCD's cursor to line 2, column 1.
///lcdByVacSerial.puts("\e[2;1H");
// After printing to LCD, reset all the auxiliary variables.
for (int j=0;j < SERIAL_INPUT_BUFFER_SIZE;j++) { arrChrBuffer[j] = '\0'; }
i = 0; incomingChar = '\0';
}
// Catch a breath.
delay(1000); // Wait a second or two.
}
What is strange is that I am using the same Serial write() syntax in both working and non-working programs. I simply can't see what is wrong?
1