I was able to expand the GUI to talk to two serial ports at once. I have the Arduino reading the serial encoders on COM10, and the Arduino with the motor shields on COM11. Both Arduinos print back their coordinate to the serial port.
The positions are read back from the Arduinos to the GUI display. The buttons fire off HPGL PR commands to the Arduino HPGL interpretor. w00t!
The machine moves, the encoders increment.
Next step is to add some flow control to the GUI and the ability to spool in a large HPGL command in small chunks so as not to overflow the Arduino serial buffer and give it time to move from point to point.
The code is getting pretty long to post, so I'm setting up a download site
Hobby blog about tech tips I've picked up, projects I'm working on, or links to useful information and cool stuff. I'm an Electrical Engineer and professional Analog IC designer for 25 years playing in my spare time. Arduino, hacking consumer electronics, video game hardware, satellite TV, PC building, Android apps, appliance repairs and whatever else that interests me.
Search This Blog
Monday, March 28, 2011
Saturday, March 26, 2011
Notes on Learning to Make a Java GUI for the CNC machine
Not sure if this is the way I will go, but I'm exploring using Java to create a small GUI to control the Arduino based XYZ CNC machine. I did see some folks have already done this, so I may go back and use their code.
This is a place to store my notes as I explore this topic.
My hardware is an Arduino with two motor shields from Adafruit attached (see my post on modding the shield to stack) and another Arduino reading three rotary encoders (see my post on this). These control a Zen toolworks 7x7 CNC machine.
I've written the code for the Arduino to respond to serial commands to move in straight line at constant velocity from current location to a new location. Ideally this is all that ever needs to run on the Arduino. I wrote a simple HPGL interpretor, but the serial communication wasn't working out. When I used the Arduino GUI to dump a serial file to the Arduino, the Arduino did not process the commands fast enough, obviously it has to move motors, etc, and the serial input would overrun the input buffer in the Arduino and trash the data. The Arduino can't do this job all by itself. i will never be able to send a whole HPGL file to the Arduino, it needs to be passed a bit at a time by a PC program.
So the goal here is to write a GUI that will allow the PC to feed the Arduino a file a bit at a time, and also have manual buttons to move the motors and display the encoder postions. Maybe even the limit switches. All the arduino will do is move from X,Y,Z to X,Y,Z point as commanded.
Downloaded Netbeans and Java JDK here:
https://cds.sun.com/is-bin/INTERSHOP.enfinity/WFS/CDS-CDS_Developer-Site/en_US/-/USD/ViewFilteredProducts-SingleVariationTypeFilter
Found some information on talking to the serial port here:
http://java.sun.com/developer/Books/javaprogramming/cookbook/11.pdf
That book says I may need to download the Java Communication API, which I found here
http://www.oracle.com/technetwork/java/index-jsp-141752.html
but this looks to be for LINUX only. The text says for windows...
To use that, download javax.comm for the 'generic' platform (which provides the front-end javax.comm API only, without platform specific back-end implementations bundled). Then acquire the Windows binary implementation rxtx-2.0.7pre1 from http://www.rxtx.org.
Found a web page with specific instructions! Here:
http://pradnyanaik.wordpress.com/2009/04/07/communicating-with-ports-using-javaxcomm-package-for-windows/
So I registered at sun and downloaded the generic package java communication API
https://cds.sun.com/is-bin/INTERSHOP.enfinity/WFS/CDS-CDS_SMI-Site/en_US/-/USD/ViewFilteredProducts-SingleVariationTypeFilter
Now I'm puzzled, only the comm.jar file is there, not the win32com.dll or the javax.comm.properties
Found another example that seems more clear;
http://edn.embarcadero.com/article/31915
Points to the same oracle page that got me only comm.jar. hmmmm.
And rxtx.org points to a isp dead end page.
Friend sent me rxtx-2.1-7-bins-r2 dont know where he got it. But no worries, it is on the web see below
Instructions were similar, but now i had a jar file and a dll.
README referred to this web page, which had the files on it
http://rxtx.qbang.org/wiki
Windows
RXTXcomm.jar goes in \jre\lib\ext (under java)
rxtxSerial.dll goes in \jre\bin
Then went here to use in netbeans
http://rxtx.qbang.org/wiki/index.php/Using_RXTX_In_NetBeans
I did the right click on libraries to add the jar file but i had already copied the files into the locations above, so i think i'm done
Went to the sample project
http://rxtx.qbang.org/wiki/index.php/Documented_interface_to_communicate_with_serial_ports_for_beginners,_including_example_project
Even mentions arduinos - w00t
downloaded the zip file RXTXexample.zip
Bleh, not really sure how to use this with netbeans. README talks about ant in linux.
Tried opening as a project in netbeans...no dice
Opened the project my friend sent, myRxTxTest2. I will go back and figure out how he made this later, sorry for the trail that can't be followed. Here is the basic Java code that makes up Main.java. There is
also a GUI form that goes with it, but nothing earth shaking there.
//--------------------------------------------------------------------------------------------------
import java.io.*;
import java.util.*;
import gnu.io.*;
import java.awt.event.MouseAdapter;
//import javax.comm.*;
/**
*
* @author eric
*/
public class RealMain {
Enumeration portList;
CommPortIdentifier portId;
SerialPort serialPort;
OutputStream outputStream;
InputStream inputStream;
boolean outputBufferEmptyFlag = false;
Thread readThread;
Thread writeThread;
boolean wrFlag=true;
boolean rdg=true;
String msgin;
String msginmod;
public void Go(){
//inForm inf = new inForm("MyForm");
//inf.go();
trash trh = new trash();
trh.setVisible(true);
try{
portId= CommPortIdentifier.getPortIdentifier("COM11");
}catch(Exception e){
System.out.println("Error getting port ID"+ e);
Enumeration ports = CommPortIdentifier.getPortIdentifiers();
//tomw - addeed dump of all active ports
System.out.println("Active ports found:");
while(ports.hasMoreElements()){
CommPortIdentifier port = (CommPortIdentifier) ports.nextElement();
System.out.println(port.getName());
}
}
try{
serialPort = (SerialPort) portId.open("My RxTx test", 2000);
System.out.println("Got Serial Port Open");
System.out.println("type something in the console window to send it (15 characters max) - type exit to quit ");
}catch(Exception e){
System.out.println("Error opening port "+ e);
System.exit(1);
}
try {
outputStream = serialPort.getOutputStream();
} catch (IOException e) {
System.out.println("Error setting output stream "+e);
}
try {
inputStream = serialPort.getInputStream();
} catch (IOException e) {
System.out.println("Error setting input stream "+e);
}
try {
serialPort.setSerialPortParams(9600,
SerialPort.DATABITS_8,
SerialPort.STOPBITS_1,
SerialPort.PARITY_NONE);
} catch (UnsupportedCommOperationException e) {}
ReadHandler RH = new ReadHandler();
Thread RT = new Thread(RH);
RT.start();
InputStreamReader cmlIn = new InputStreamReader(System.in);
BufferedReader brIn = new BufferedReader(cmlIn);
PrintWriter pr = new PrintWriter(outputStream,true);
while (rdg){
try{
msgin = brIn.readLine();
System.out.println("You typed "+ msgin);
try{
//pr.print(msgin);
//outputStream.write('w');
//outputStream.write(0x000a);
// pr.print(0x00);
// pr.println();
if(msgin.length()>15){
msginmod=msgin.substring(0, 15);
System.out.println("more than 15 characters - will truncate to " + msginmod);
}else{
msginmod=msgin;
}
pr.println(msginmod);
}catch(Exception e){
System.out.println("error writing to device "+ e);
}
if (msgin.equalsIgnoreCase("exit")){
rdg=false;
System.out.println("leaving now");
outputStream.close();
inputStream.close();
brIn.close();
pr.close();
serialPort.close();
System.exit(1);
}
}catch(Exception e){
System.out.println("error reading line"+ e);
}
}
}
public void Write(){
System.out.println("got here");
}
class ReadHandler implements Runnable {
volatile boolean on;
public void run(){
int c;
String msgback;
InputStreamReader IS = new InputStreamReader(inputStream);
BufferedReader BR = new BufferedReader(IS);
while(rdg){
try{
msgback=BR.readLine();
System.out.println("line back is "+ msgback);
}catch(Exception e){
//tomw - commented out, screen if filling with this message
//System.out.println("error reading back"+ e);
}
}
}
}
}
//--------------------------------------------------------------------------------------------------------
It complained it had non existing paths to my friends RXTXcomm.jar and others. Trying to point it to my own files
OK - found that right click on Libraries in the project tree, hit properties, brings up the GUI to remove the broken links. Still missing java.boot.jar looks like i can ignore this. Complains the port doesn't exist.
looks like the code points to a port /dev/ttySO, since he uses Linux, I'm still using windows. trying this instead:
Found some code at the bottom of this page that tells how to read what ports are active:
http://stackoverflow.com/questions/274179/nosuchportexception-using-rxtx-java-library-on-windows
Bingo - I get:
COM1
COM11
LPT1
So changing the port to "COM11" where my Arduino is and error goes away, but the form flashes up then disappears immediately from within Netbeans, Duh - the arduino app was open and the port was busy.
Closed it and things are looking up!
For testing I made a tiny sketch for the Arduino to respond to serial inputs, turns off LED, etc
//-------------------------------------------------------------------------------------
// Test program for the Arduino
// for development of a serial interface GUI on the PC
// Just makes communication on the serial interface
char inByte = '0'; // incoming serial byte
char outByte = '0'; // outgoing serial byte
boolean contact = false; //indicates a link partner was found
void setup()
{
// start serial port at 9600 bps:
Serial.begin(9600);
pinMode(13, OUTPUT);
}
void loop()
{
if (Serial.available()) {
contact = true;
inByte = Serial.read();
if (inByte == 'U') digitalWrite(13, HIGH); // set the LED on
if (inByte == 'D') digitalWrite(13, LOW); // set the LED off
// mess with it a bit to show something happened
outByte = inByte + 1;
Serial.println(outByte);
} else {
//spew junk to let the world know you want to talk
if (!contact) Serial.print(",");
}
}
//-------------------------------------------------------------------
OK, some success. The console window shows the responses from the Arduino. The form is not working but at least it is talking to the Arduino from the Java console!!! w00t!
Had to switch to my laptop, so brief recap of what i had to do to get netbeans back to this point.....
Download Java netbeans JDK
Download Java Communication API, and get the file comm.jar from the generic platform
Download rxtx-2.1-7-bins-r2 from http://rxtx.qbang.org/wiki and put the RXTXcomm.jar and rxtxSerial.dll in the folders in netbeans where the README says
OK - back to our show.....
Have the very basics of the GUI working now by splicing together demo GUI program with the rxtx. I can push a button on the GUI, send a 'U' to the serial interface and turn on the LED. Awesome! 'D' turns it off. The port initialization was stolen directly from the code i posted further up. The Arduino sends back the position and the GUI displays it. Left a place for the encoders to read back, that requires more work from a second serial port.
Using the basic GUI builder in Netbeans. The form is just made with the form builder and the functions pasted into it's fields.
I'm in business. Now the drudgery of making the full GUI, passing coordinate messages, spooling a HPGL file, etc to the real Arduino stepper motor control program. I'll spare some details until I have a more complete interface put together and write that up.
Here is the Java and the Arduino programs.
package Serial_Comm_GUI;
//imports all the java rxtx libs
import java.io.*;
import java.util.*;
import gnu.io.*;
import java.awt.event.MouseAdapter;
//import javax.comm.*;
/**
*
* @author tomw
*/
public class RealMain {
Form1 myform;
boolean toggle = false;
Enumeration portList;
CommPortIdentifier portId;
SerialPort serialPort;
OutputStream outputStream;
InputStream inputStream;
boolean outputBufferEmptyFlag = false;
Thread readThread;
Thread writeThread;
boolean wrFlag=true;
boolean rdg=true;
String msgin;
String msginmod;
String portName = "COM11";
public void go() {
// Pops up the GUI
myform = new Form1(this);
myform.setVisible(true);
myform.setLabel2(portName);
myform.setLabel11("contacting...");
myform.setLabel7("contacting...");
// Opens the serial port and configures it, handles errors
try{
portId= CommPortIdentifier.getPortIdentifier(portName);
System.out.println(portName);
}catch(Exception e){
System.out.println("Error getting port ID"+ e);
Enumeration ports = CommPortIdentifier.getPortIdentifiers();
//tomw - addeed dump of all active ports
System.out.println(portName);
System.out.println("Port not Found - Active ports found:");
while(ports.hasMoreElements()){
CommPortIdentifier port = (CommPortIdentifier) ports.nextElement();
System.out.println(port.getName());
}
}
try{
serialPort = (SerialPort) portId.open("My RxTx test", 2000);
System.out.println("Serial Port Open");
System.out.println("type in the console window to send commands");
}catch(Exception e){
System.out.println("Error opening port "+ e);
System.exit(1);
}
try {
outputStream = serialPort.getOutputStream();
} catch (IOException e) {
System.out.println("Error setting output stream "+e);
}
try {
inputStream = serialPort.getInputStream();
} catch (IOException e) {
System.out.println("Error setting input stream "+e);
}
try {
serialPort.setSerialPortParams(9600,
SerialPort.DATABITS_8,
SerialPort.STOPBITS_1,
SerialPort.PARITY_NONE);
myform.setLabel11("0:0:0");
} catch (UnsupportedCommOperationException e) {}
ReadHandler RH = new ReadHandler();
Thread RT = new Thread(RH);
RT.start();
InputStreamReader cmlIn = new InputStreamReader(System.in);
BufferedReader brIn = new BufferedReader(cmlIn);
}
public void longTextChange() {
if (toggle == false) {
myform.setLabel2("Oops!");
toggle = true;
} else {
myform.setLabel2("Ahhhh!");
toggle = false;
}
System.out.println("You pushed me!!");
}
public void pushedUp(){
PrintWriter pr = new PrintWriter(outputStream,true);
pr.println('U');
System.out.println("Up");
}
public void pushedDown(){
PrintWriter pr = new PrintWriter(outputStream,true);
pr.println('D');
System.out.println("Down");
}
public void pushedRight(){
PrintWriter pr = new PrintWriter(outputStream,true);
pr.println('R');
System.out.println("Right");
}
public void pushedLeft(){
PrintWriter pr = new PrintWriter(outputStream,true);
pr.println('L');
System.out.println("Left");
}
public void pushedZup(){
PrintWriter pr = new PrintWriter(outputStream,true);
pr.println('Z');
System.out.println("Z up");
}
public void pushedZdown(){
PrintWriter pr = new PrintWriter(outputStream,true);
pr.println('W');
System.out.println("Z down");
}
class ReadHandler implements Runnable {
volatile boolean on;
public void run(){
int c;
String msgback;
InputStreamReader IS = new InputStreamReader(inputStream);
BufferedReader BR = new BufferedReader(IS);
while(rdg){
try{
msgback=BR.readLine();
System.out.println("Position "+ msgback);
myform.setLabel11(msgback);
}catch(Exception e){
//tomw - commented out, screen if filling with this message
//System.out.println("error reading back"+ e);
}
}
}
}
}
//--------------------------------------------------------------------------------------------------------------------------------
// Test program for the Arduino
// for development of a serial interface GUI on the PC
// Just makes communication on the serial interface
char inByte = '0'; // incoming serial byte
char outByte = '0'; // outgoing serial byte
boolean contact = false; //indicates a link partner was found
int stepperX = 0;
int stepperY = 0;
int stepperZ = 0;
void setup()
{
// start serial port at 9600 bps:
Serial.begin(9600);
pinMode(13, OUTPUT);
}
void loop()
{
if (Serial.available()) {
contact = true;
inByte = Serial.read();
switch( inByte ) {
case 'U' :
digitalWrite(13, HIGH); // set the LED on
stepperY++;
break;
case 'D' :
digitalWrite(13, LOW); // set the LED off
stepperY--;
break;
case 'R' :
for( int i=0; i<3 ; i++) {
digitalWrite(13, LOW); // set the LED off
delay(300);
digitalWrite(13, HIGH); // set the LED on
delay(300);
}
stepperX++;
break;
case 'L' :
for( int i=0; i<5 ; i++) {
digitalWrite(13, LOW); // set the LED off
delay(100);
digitalWrite(13, HIGH); // set the LED on
delay(100);
}
stepperX--;
break;
case 'Z' :
for( int i=0; i<10 ; i++) {
digitalWrite(13, LOW); // set the LED off
delay(50);
digitalWrite(13, HIGH); // set the LED on
delay(50);
}
stepperZ++;
break;
case 'W' :
for( int i=0; i<10 ; i++) {
digitalWrite(13, LOW); // set the LED off
delay(50);
digitalWrite(13, HIGH); // set the LED on
delay(150);
}
stepperZ--;
break;
default :
// ignore unknown letter command
break;
}
Serial.print(stepperX);Serial.print(":");Serial.print(stepperY);Serial.print(":");Serial.println(stepperZ);
} else {
//spew junk to let the world know you want to talk
if (!contact) Serial.print(",");
}
}
This is a place to store my notes as I explore this topic.
My hardware is an Arduino with two motor shields from Adafruit attached (see my post on modding the shield to stack) and another Arduino reading three rotary encoders (see my post on this). These control a Zen toolworks 7x7 CNC machine.
I've written the code for the Arduino to respond to serial commands to move in straight line at constant velocity from current location to a new location. Ideally this is all that ever needs to run on the Arduino. I wrote a simple HPGL interpretor, but the serial communication wasn't working out. When I used the Arduino GUI to dump a serial file to the Arduino, the Arduino did not process the commands fast enough, obviously it has to move motors, etc, and the serial input would overrun the input buffer in the Arduino and trash the data. The Arduino can't do this job all by itself. i will never be able to send a whole HPGL file to the Arduino, it needs to be passed a bit at a time by a PC program.
So the goal here is to write a GUI that will allow the PC to feed the Arduino a file a bit at a time, and also have manual buttons to move the motors and display the encoder postions. Maybe even the limit switches. All the arduino will do is move from X,Y,Z to X,Y,Z point as commanded.
Downloaded Netbeans and Java JDK here:
https://cds.sun.com/is-bin/INTERSHOP.enfinity/WFS/CDS-CDS_Developer-Site/en_US/-/USD/ViewFilteredProducts-SingleVariationTypeFilter
Found some information on talking to the serial port here:
http://java.sun.com/developer/Books/javaprogramming/cookbook/11.pdf
That book says I may need to download the Java Communication API, which I found here
http://www.oracle.com/technetwork/java/index-jsp-141752.html
but this looks to be for LINUX only. The text says for windows...
To use that, download javax.comm for the 'generic' platform (which provides the front-end javax.comm API only, without platform specific back-end implementations bundled). Then acquire the Windows binary implementation rxtx-2.0.7pre1 from http://www.rxtx.org.
Found a web page with specific instructions! Here:
http://pradnyanaik.wordpress.com/2009/04/07/communicating-with-ports-using-javaxcomm-package-for-windows/
So I registered at sun and downloaded the generic package java communication API
https://cds.sun.com/is-bin/INTERSHOP.enfinity/WFS/CDS-CDS_SMI-Site/en_US/-/USD/ViewFilteredProducts-SingleVariationTypeFilter
Now I'm puzzled, only the comm.jar file is there, not the win32com.dll or the javax.comm.properties
Found another example that seems more clear;
http://edn.embarcadero.com/article/31915
Points to the same oracle page that got me only comm.jar. hmmmm.
And rxtx.org points to a isp dead end page.
Friend sent me rxtx-2.1-7-bins-r2 dont know where he got it. But no worries, it is on the web see below
Instructions were similar, but now i had a jar file and a dll.
README referred to this web page, which had the files on it
http://rxtx.qbang.org/wiki
Windows
RXTXcomm.jar goes in \jre\lib\ext (under java)
rxtxSerial.dll goes in \jre\bin
Then went here to use in netbeans
http://rxtx.qbang.org/wiki/index.php/Using_RXTX_In_NetBeans
I did the right click on libraries to add the jar file but i had already copied the files into the locations above, so i think i'm done
Went to the sample project
http://rxtx.qbang.org/wiki/index.php/Documented_interface_to_communicate_with_serial_ports_for_beginners,_including_example_project
Even mentions arduinos - w00t
downloaded the zip file RXTXexample.zip
Bleh, not really sure how to use this with netbeans. README talks about ant in linux.
Tried opening as a project in netbeans...no dice
Opened the project my friend sent, myRxTxTest2. I will go back and figure out how he made this later, sorry for the trail that can't be followed. Here is the basic Java code that makes up Main.java. There is
also a GUI form that goes with it, but nothing earth shaking there.
//--------------------------------------------------------------------------------------------------
import java.io.*;
import java.util.*;
import gnu.io.*;
import java.awt.event.MouseAdapter;
//import javax.comm.*;
/**
*
* @author eric
*/
public class RealMain {
Enumeration portList;
CommPortIdentifier portId;
SerialPort serialPort;
OutputStream outputStream;
InputStream inputStream;
boolean outputBufferEmptyFlag = false;
Thread readThread;
Thread writeThread;
boolean wrFlag=true;
boolean rdg=true;
String msgin;
String msginmod;
public void Go(){
//inForm inf = new inForm("MyForm");
//inf.go();
trash trh = new trash();
trh.setVisible(true);
try{
portId= CommPortIdentifier.getPortIdentifier("COM11");
}catch(Exception e){
System.out.println("Error getting port ID"+ e);
Enumeration ports = CommPortIdentifier.getPortIdentifiers();
//tomw - addeed dump of all active ports
System.out.println("Active ports found:");
while(ports.hasMoreElements()){
CommPortIdentifier port = (CommPortIdentifier) ports.nextElement();
System.out.println(port.getName());
}
}
try{
serialPort = (SerialPort) portId.open("My RxTx test", 2000);
System.out.println("Got Serial Port Open");
System.out.println("type something in the console window to send it (15 characters max) - type exit to quit ");
}catch(Exception e){
System.out.println("Error opening port "+ e);
System.exit(1);
}
try {
outputStream = serialPort.getOutputStream();
} catch (IOException e) {
System.out.println("Error setting output stream "+e);
}
try {
inputStream = serialPort.getInputStream();
} catch (IOException e) {
System.out.println("Error setting input stream "+e);
}
try {
serialPort.setSerialPortParams(9600,
SerialPort.DATABITS_8,
SerialPort.STOPBITS_1,
SerialPort.PARITY_NONE);
} catch (UnsupportedCommOperationException e) {}
ReadHandler RH = new ReadHandler();
Thread RT = new Thread(RH);
RT.start();
InputStreamReader cmlIn = new InputStreamReader(System.in);
BufferedReader brIn = new BufferedReader(cmlIn);
PrintWriter pr = new PrintWriter(outputStream,true);
while (rdg){
try{
msgin = brIn.readLine();
System.out.println("You typed "+ msgin);
try{
//pr.print(msgin);
//outputStream.write('w');
//outputStream.write(0x000a);
// pr.print(0x00);
// pr.println();
if(msgin.length()>15){
msginmod=msgin.substring(0, 15);
System.out.println("more than 15 characters - will truncate to " + msginmod);
}else{
msginmod=msgin;
}
pr.println(msginmod);
}catch(Exception e){
System.out.println("error writing to device "+ e);
}
if (msgin.equalsIgnoreCase("exit")){
rdg=false;
System.out.println("leaving now");
outputStream.close();
inputStream.close();
brIn.close();
pr.close();
serialPort.close();
System.exit(1);
}
}catch(Exception e){
System.out.println("error reading line"+ e);
}
}
}
public void Write(){
System.out.println("got here");
}
class ReadHandler implements Runnable {
volatile boolean on;
public void run(){
int c;
String msgback;
InputStreamReader IS = new InputStreamReader(inputStream);
BufferedReader BR = new BufferedReader(IS);
while(rdg){
try{
msgback=BR.readLine();
System.out.println("line back is "+ msgback);
}catch(Exception e){
//tomw - commented out, screen if filling with this message
//System.out.println("error reading back"+ e);
}
}
}
}
}
//--------------------------------------------------------------------------------------------------------
It complained it had non existing paths to my friends RXTXcomm.jar and others. Trying to point it to my own files
OK - found that right click on Libraries in the project tree, hit properties, brings up the GUI to remove the broken links. Still missing java.boot.jar looks like i can ignore this. Complains the port doesn't exist.
looks like the code points to a port /dev/ttySO, since he uses Linux, I'm still using windows. trying this instead:
Found some code at the bottom of this page that tells how to read what ports are active:
http://stackoverflow.com/questions/274179/nosuchportexception-using-rxtx-java-library-on-windows
Enumeration ports = CommPortIdentifier.getPortIdentifiers();
while(ports.hasMoreElements()){
CommPortIdentifier port = (CommPortIdentifier) ports.nextElement();
System.out.println(port.getName());
}
}
Bingo - I get:
COM1
COM11
LPT1
So changing the port to "COM11" where my Arduino is and error goes away, but the form flashes up then disappears immediately from within Netbeans, Duh - the arduino app was open and the port was busy.
Closed it and things are looking up!
For testing I made a tiny sketch for the Arduino to respond to serial inputs, turns off LED, etc
//-------------------------------------------------------------------------------------
// Test program for the Arduino
// for development of a serial interface GUI on the PC
// Just makes communication on the serial interface
char inByte = '0'; // incoming serial byte
char outByte = '0'; // outgoing serial byte
boolean contact = false; //indicates a link partner was found
void setup()
{
// start serial port at 9600 bps:
Serial.begin(9600);
pinMode(13, OUTPUT);
}
void loop()
{
if (Serial.available()) {
contact = true;
inByte = Serial.read();
if (inByte == 'U') digitalWrite(13, HIGH); // set the LED on
if (inByte == 'D') digitalWrite(13, LOW); // set the LED off
// mess with it a bit to show something happened
outByte = inByte + 1;
Serial.println(outByte);
} else {
//spew junk to let the world know you want to talk
if (!contact) Serial.print(",");
}
}
//-------------------------------------------------------------------
OK, some success. The console window shows the responses from the Arduino. The form is not working but at least it is talking to the Arduino from the Java console!!! w00t!
Had to switch to my laptop, so brief recap of what i had to do to get netbeans back to this point.....
Download Java netbeans JDK
Download Java Communication API, and get the file comm.jar from the generic platform
Download rxtx-2.1-7-bins-r2 from http://rxtx.qbang.org/wiki and put the RXTXcomm.jar and rxtxSerial.dll in the folders in netbeans where the README says
OK - back to our show.....
Have the very basics of the GUI working now by splicing together demo GUI program with the rxtx. I can push a button on the GUI, send a 'U' to the serial interface and turn on the LED. Awesome! 'D' turns it off. The port initialization was stolen directly from the code i posted further up. The Arduino sends back the position and the GUI displays it. Left a place for the encoders to read back, that requires more work from a second serial port.
Using the basic GUI builder in Netbeans. The form is just made with the form builder and the functions pasted into it's fields.
Here is the Java and the Arduino programs.
package Serial_Comm_GUI;
//imports all the java rxtx libs
import java.io.*;
import java.util.*;
import gnu.io.*;
import java.awt.event.MouseAdapter;
//import javax.comm.*;
/**
*
* @author tomw
*/
public class RealMain {
Form1 myform;
boolean toggle = false;
Enumeration portList;
CommPortIdentifier portId;
SerialPort serialPort;
OutputStream outputStream;
InputStream inputStream;
boolean outputBufferEmptyFlag = false;
Thread readThread;
Thread writeThread;
boolean wrFlag=true;
boolean rdg=true;
String msgin;
String msginmod;
String portName = "COM11";
public void go() {
// Pops up the GUI
myform = new Form1(this);
myform.setVisible(true);
myform.setLabel2(portName);
myform.setLabel11("contacting...");
myform.setLabel7("contacting...");
// Opens the serial port and configures it, handles errors
try{
portId= CommPortIdentifier.getPortIdentifier(portName);
System.out.println(portName);
}catch(Exception e){
System.out.println("Error getting port ID"+ e);
Enumeration ports = CommPortIdentifier.getPortIdentifiers();
//tomw - addeed dump of all active ports
System.out.println(portName);
System.out.println("Port not Found - Active ports found:");
while(ports.hasMoreElements()){
CommPortIdentifier port = (CommPortIdentifier) ports.nextElement();
System.out.println(port.getName());
}
}
try{
serialPort = (SerialPort) portId.open("My RxTx test", 2000);
System.out.println("Serial Port Open");
System.out.println("type in the console window to send commands");
}catch(Exception e){
System.out.println("Error opening port "+ e);
System.exit(1);
}
try {
outputStream = serialPort.getOutputStream();
} catch (IOException e) {
System.out.println("Error setting output stream "+e);
}
try {
inputStream = serialPort.getInputStream();
} catch (IOException e) {
System.out.println("Error setting input stream "+e);
}
try {
serialPort.setSerialPortParams(9600,
SerialPort.DATABITS_8,
SerialPort.STOPBITS_1,
SerialPort.PARITY_NONE);
myform.setLabel11("0:0:0");
} catch (UnsupportedCommOperationException e) {}
ReadHandler RH = new ReadHandler();
Thread RT = new Thread(RH);
RT.start();
InputStreamReader cmlIn = new InputStreamReader(System.in);
BufferedReader brIn = new BufferedReader(cmlIn);
}
public void longTextChange() {
if (toggle == false) {
myform.setLabel2("Oops!");
toggle = true;
} else {
myform.setLabel2("Ahhhh!");
toggle = false;
}
System.out.println("You pushed me!!");
}
public void pushedUp(){
PrintWriter pr = new PrintWriter(outputStream,true);
pr.println('U');
System.out.println("Up");
}
public void pushedDown(){
PrintWriter pr = new PrintWriter(outputStream,true);
pr.println('D');
System.out.println("Down");
}
public void pushedRight(){
PrintWriter pr = new PrintWriter(outputStream,true);
pr.println('R');
System.out.println("Right");
}
public void pushedLeft(){
PrintWriter pr = new PrintWriter(outputStream,true);
pr.println('L');
System.out.println("Left");
}
public void pushedZup(){
PrintWriter pr = new PrintWriter(outputStream,true);
pr.println('Z');
System.out.println("Z up");
}
public void pushedZdown(){
PrintWriter pr = new PrintWriter(outputStream,true);
pr.println('W');
System.out.println("Z down");
}
class ReadHandler implements Runnable {
volatile boolean on;
public void run(){
int c;
String msgback;
InputStreamReader IS = new InputStreamReader(inputStream);
BufferedReader BR = new BufferedReader(IS);
while(rdg){
try{
msgback=BR.readLine();
System.out.println("Position "+ msgback);
myform.setLabel11(msgback);
}catch(Exception e){
//tomw - commented out, screen if filling with this message
//System.out.println("error reading back"+ e);
}
}
}
}
}
//--------------------------------------------------------------------------------------------------------------------------------
// Test program for the Arduino
// for development of a serial interface GUI on the PC
// Just makes communication on the serial interface
char inByte = '0'; // incoming serial byte
char outByte = '0'; // outgoing serial byte
boolean contact = false; //indicates a link partner was found
int stepperX = 0;
int stepperY = 0;
int stepperZ = 0;
void setup()
{
// start serial port at 9600 bps:
Serial.begin(9600);
pinMode(13, OUTPUT);
}
void loop()
{
if (Serial.available()) {
contact = true;
inByte = Serial.read();
switch( inByte ) {
case 'U' :
digitalWrite(13, HIGH); // set the LED on
stepperY++;
break;
case 'D' :
digitalWrite(13, LOW); // set the LED off
stepperY--;
break;
case 'R' :
for( int i=0; i<3 ; i++) {
digitalWrite(13, LOW); // set the LED off
delay(300);
digitalWrite(13, HIGH); // set the LED on
delay(300);
}
stepperX++;
break;
case 'L' :
for( int i=0; i<5 ; i++) {
digitalWrite(13, LOW); // set the LED off
delay(100);
digitalWrite(13, HIGH); // set the LED on
delay(100);
}
stepperX--;
break;
case 'Z' :
for( int i=0; i<10 ; i++) {
digitalWrite(13, LOW); // set the LED off
delay(50);
digitalWrite(13, HIGH); // set the LED on
delay(50);
}
stepperZ++;
break;
case 'W' :
for( int i=0; i<10 ; i++) {
digitalWrite(13, LOW); // set the LED off
delay(50);
digitalWrite(13, HIGH); // set the LED on
delay(150);
}
stepperZ--;
break;
default :
// ignore unknown letter command
break;
}
Serial.print(stepperX);Serial.print(":");Serial.print(stepperY);Serial.print(":");Serial.println(stepperZ);
} else {
//spew junk to let the world know you want to talk
if (!contact) Serial.print(",");
}
}
Wednesday, March 16, 2011
Arduino XYZ CNC Carving Machine Control Software
Working on control software for the CNC machine.
Wrote a basic program to do linear interpolation from coordinates received over the serial interface. Now I need to find an easy way to send coords from a graphics program.
Trying to decide what I need to write so that I can communicate with some open source machine control software. The Arduino can't do a lot on it's own, but it needs to interpret commands.
Looks like some machines support HPGL code. That is reasonably simple to implement but will require writing several functions. It is a short term solution
This guy made an HPGL GUI
http://www.linuxcnc.org/component/option,com_kunena/Itemid,20/func,view/catid,31/id,1870/lang,english/
www.securetech-ns.ca/camm-linux.html
Many graphics programs can output HPGL. This will be for mostly 2D projects, like PCB cutting.
this guy wrote an HPGL interpretor, that i looked at for ideas, but didn't end up trying to use it
http://sensi.org/~svo/motori/
This page has a simple HGL file that I used for test
http://www.winline.com/evalpen_center.html
http://www.winline.com/images/plotfiles/GL-C-O.plt
Wrote this very basic HPGL control layer to interface from basic HPGL commands to control the adafruit motor shield:
The bug i have right now is that if i send the very long coord lists in this file, i fill the Arduino serial buffer and it hoses the data, since the Arduino has to move the motors, reading the data as it comes doesn't quite work. Meanwhile this is what i have so far, that works will with manually entered commands.
// Stepper Motor Control Program
// For an XYZ stepper motor controller
// Receives serial commands from PC, controls 3 motor CNC machine
// Interprets basic HPGL style instructions
// Tom Wilson 2011
#define INCH 4000 //steps per inch of the machine = threads per inch * steps per rotation
#define RPM 30 //speed of the motors
#define SER_HEADER 'G' // Header tag for serial message
// Adafruit Motor shield library
// modified by tomw to drive 2 shields at once
// This requires a modified library
//with the second having MOTORLATCH on pin 13, renamed MOTORLATCHA
//and all functions renamed to A versions
#include <AFMotor.h>
#include <AFMotorA.h>
//Set up the steps per revolution and location of motors
AF_Stepper motorX(200, 1);
AF_Stepper motorY(200, 2);
AF_StepperA motorZ(200, 2);
// Set up the basic machine position variable
signed long int Xpos = 0;
signed long int Ypos = 0;
signed long int Zpos = 0;
// Set up the destination machine position variable
signed long int newXpos = 0;
signed long int newYpos = 0;
signed long int newZpos = 0;
// Set up global place to keep serial values
signed long int newSerialData;
bool XorY = false;
void setup() {
Serial.begin(9600); // set up Serial library at 9600 bps
Serial.println("Stepper Controller Online");
//set the default speed of the motors
motorX.setSpeed(RPM); ;
motorY.setSpeed(RPM); ;
motorZ.setSpeed(RPM); ;
delay(1000); // wait for the supply to come up
//step motors one step and back to power the coils
motorX.step(1, FORWARD, SINGLE);
motorY.step(1, FORWARD, SINGLE);
motorZ.step(1, FORWARD, SINGLE);
motorX.step(1, BACKWARD, SINGLE);
motorY.step(1, BACKWARD, SINGLE);
motorZ.step(1, BACKWARD, SINGLE);
// Home position
Xpos = 0;
Ypos = 0;
Zpos = 0;
newXpos = 0;
newYpos = 0;
newZpos = 0;
Serial.print("Current:");
Serial.print("\tX:");
Serial.print(Xpos);
Serial.print("\tY:");
Serial.print(Ypos);
Serial.print("\tZ:");
Serial.println(Zpos);
Serial.println("Ready for Commands");
}
void loop() {
while(Serial.available() ) {
// Loop simply accepts commands from serial and executes them
readHPGLcommand(); //read the command
}
}
void readHPGLcommand() {
// reads serial port for two letter HPGL command and optional coords that follow
char c;
bool coord_avail;
//make sure there is enough data there for form a command, at least "IN;"
if(Serial.available()>=3){
c = Serial.read();
// Interpret HPGL command, ingnore unsupported commands and whitespace
//http://paulbourke.net/dataformats/hpgl/ has definitions
switch( c ) {
case 'P' :
switch( Serial.read() ) {
case 'U' : // PU Pen Up
Serial.println("Pen Up \t/\\ /\\ /\\ /\\"); //lift pen and optionally move to new coords
zMove(50);
// expect either nothing or pairs of coords to follow
XorY = true;
coord_avail = true;
while( coord_avail ) {
coord_avail = readSerialNumber();
// hack to alternate reading values as X or Y
if ( XorY) {
newXpos = newSerialData;
XorY = false;
} else {
newYpos = newSerialData;
XorY = true;
Serial.print(newXpos); Serial.print(":"); Serial.print(newYpos); Serial.print("\t>>");
linearInterpolationMove( newXpos, newYpos);
}
}
break;
case 'D' : // PD Pen Down
Serial.println("Pen Down\t\\/ \\/ \\/ \\/"); //drop pen and optionally move to new coords
zMove(0);
coord_avail = false;
// expect either nothing or pairs of coords to follow
XorY = true;
coord_avail = true; //need to make sure the loop goes at least once
while( coord_avail ) {
coord_avail = readSerialNumber();
// hack to alternate reading values as X or Y
if ( XorY) {
newXpos = newSerialData;
XorY = false;
} else {
newYpos = newSerialData;
XorY = true;
// only valid coord if two values were found
Serial.print(newXpos); Serial.print(":"); Serial.print(newYpos); Serial.print("\t>>");
linearInterpolationMove( newXpos, newYpos);
}
}
break;
case 'G' : // PG Page Feed
Serial.println("Page Feed");
while( readSerialNumber() ) {} //keep reading until coords or ';' is found
// Command doesn't do anything yet
break;
case 'T' : // PG Pen Thickness
Serial.println("Pen Thickness");
while( readSerialNumber() ) {} //keep reading until coords or ';' is found
// expects one number to be returned, indicating pen
Serial.print("Pen Thickness Set to:");
Serial.println(newSerialData);
// currently not doing anything with this command
break;
default :
Serial.println("WARNING: Unknown command Px ignored");
while( readSerialNumber() ) {} //keep reading until coords or ';' is found
break;
}
break;
case 'I' :
switch( Serial.read() ) {
case 'N' : // IN Initialize
Serial.println("Initialize");
while( readSerialNumber() ) {} //keep reading until coords or ';' is found
// Home position
Xpos = 0;
Ypos = 0;
Zpos = 0;
break;
default :
Serial.println("WARNING: Unknown command Ix ignored: ");
while( readSerialNumber() ) {} //keep reading until coords or ';' is found
break;
}
break;
case 'S' :
switch( Serial.read() ) {
case 'P' : // SP Select Pen
Serial.println("Select Pen");
while( readSerialNumber() ) {} //keep reading until coords or ';' is found
// expects one number to be returned, indicating pen
Serial.print("Pen set to:");
Serial.println(newSerialData);
// currently not doing anything with this command
break;
default :
Serial.print("WARNING: Unknown command Sx ignored: ");
while( readSerialNumber() ) {} //keep reading until coords or ';' is found
break;
}
break;
default :
//Whitespace or unrecognized letter, ignore it
break;
} //cmd switch
} //if serial
}
bool readSerialNumber() {
//read coords from serial input
//commands end with ';' and lists of coords are separated by ','
//
// Three things can happen and need to differentiate
// 1) no coords at all, just a ; - need to return right away and break the calling while loop
// 2) a coordinate followed by , - need to output the coord and continue
// 3) a coordinate followed by ; - need to output the coord and break the calling while loop
signed long int coord = 0; //temp storage for coords from serial
signed int sign = 1; //temp storage for coord sign from serial
char c;
while ( c != ',' && c != ';' /*&& Serial.available()*/){
c = Serial.read();
if( c == '-' ) sign = -1; // capture the sign
if( c >= '0' && c <= '9'){
coord = (10 * coord) + (c - '0') ; // convert digits to a number
}
}
//put the data in the top level variable
newSerialData = coord * sign;
//detect the end of command ';' after the last coord
if( c == ';') return false;
return true;
}
void zMove (signed long int newZ) {
//calculates steps to move, and moves, to new Z position requested
signed long int distance = 0;
signed long int oldZ = Zpos;
distance = newZ - oldZ;
if ((distance < 8000) && (distance > -8000)) {
if (distance >= 1) motorZ.step(distance, FORWARD, SINGLE);
if (distance <= -1) motorZ.step(-1*distance, BACKWARD, SINGLE);
} else {
//movement requested is large and likely an error
Serial.println("ERROR - Z axis out of range");
}
Zpos = newZ; //update machine current position
}
void linearInterpolationMove ( signed long int newX, signed long int newY) {
float distance = 0;
int stepnum = 0;
signed long int nextX;
signed long int nextY ;
signed long int oldX = Xpos;
signed long int oldY = Ypos;
Serial.print("\t");
Serial.print(Xpos);
Serial.print(":");
Serial.print(Ypos);
Serial.print("\t --");
//find the hypotenuse, the total distance to be traveled
distance = sqrt((newX - oldX)*(newX - oldX) + (newY - oldY)*(newY - oldY) );
//round to integer number of steps that distance. Step by two to minimize 0 size steps.
for (stepnum=0; stepnum <= (distance + 0.5); stepnum++) {
//calculate the nearest integer points along the way
nextX = oldX + stepnum/distance*(newX-oldX);
nextY = oldY + stepnum/distance*(newY-oldY);
//move machine to that new coordinate, if 0 delta, don't move
if ((distance < 7*INCH) && (distance > -7*INCH)) { //trap crazy value
/* removed for test
if ((nextX-Xpos) >= 1) motorX.step((nextX - Xpos)*INCH/1000, FORWARD, SINGLE);
if ((nextX-Xpos) <= -1) motorX.step((Xpos - nextX)*INCH/1000, BACKWARD, SINGLE);
if ((nextY-Ypos) >= 1) motorY.step((nextY - Ypos)*INCH/1000, FORWARD, SINGLE);
if ((nextY-Ypos) <= -1) motorY.step((Ypos - nextY)*INCH/1000, BACKWARD, SINGLE);
*/
//update the machine current position
Xpos = nextX;
Ypos = nextY;
} else {
Serial.println("ERROR! Distance value too big");
break;
}
}
//move machine to the exact new coordinate, because rounding makes a small error
/* removed for test
if ((newX-Xpos) >= 1) motorX.step(newX - Xpos, FORWARD, SINGLE);
if ((newX-Xpos) <= -1) motorX.step(Xpos - newX, BACKWARD, SINGLE);
if ((newY-Ypos) >= 1) motorY.step(newY - Ypos, FORWARD, SINGLE);
if ((newY-Ypos) <= -1) motorY.step(Ypos - newY, BACKWARD, SINGLE);
*/
//update the machine current position
Xpos = newX;
Ypos = newY;
Serial.print("----> \t");
Serial.print(Xpos);
Serial.print(":");
Serial.println(Ypos);
}
Wrote a basic program to do linear interpolation from coordinates received over the serial interface. Now I need to find an easy way to send coords from a graphics program.
Trying to decide what I need to write so that I can communicate with some open source machine control software. The Arduino can't do a lot on it's own, but it needs to interpret commands.
Looks like some machines support HPGL code. That is reasonably simple to implement but will require writing several functions. It is a short term solution
This guy made an HPGL GUI
http://www.linuxcnc.org/component/option,com_kunena/Itemid,20/func,view/catid,31/id,1870/lang,english/
www.securetech-ns.ca/camm-linux.html
Many graphics programs can output HPGL. This will be for mostly 2D projects, like PCB cutting.
this guy wrote an HPGL interpretor, that i looked at for ideas, but didn't end up trying to use it
http://sensi.org/~svo/motori/
This page has a simple HGL file that I used for test
http://www.winline.com/evalpen_center.html
http://www.winline.com/images/plotfiles/GL-C-O.plt
Wrote this very basic HPGL control layer to interface from basic HPGL commands to control the adafruit motor shield:
The bug i have right now is that if i send the very long coord lists in this file, i fill the Arduino serial buffer and it hoses the data, since the Arduino has to move the motors, reading the data as it comes doesn't quite work. Meanwhile this is what i have so far, that works will with manually entered commands.
// Stepper Motor Control Program
// For an XYZ stepper motor controller
// Receives serial commands from PC, controls 3 motor CNC machine
// Interprets basic HPGL style instructions
// Tom Wilson 2011
#define INCH 4000 //steps per inch of the machine = threads per inch * steps per rotation
#define RPM 30 //speed of the motors
#define SER_HEADER 'G' // Header tag for serial message
// Adafruit Motor shield library
// modified by tomw to drive 2 shields at once
// This requires a modified library
//with the second having MOTORLATCH on pin 13, renamed MOTORLATCHA
//and all functions renamed to A versions
#include <AFMotor.h>
#include <AFMotorA.h>
//Set up the steps per revolution and location of motors
AF_Stepper motorX(200, 1);
AF_Stepper motorY(200, 2);
AF_StepperA motorZ(200, 2);
// Set up the basic machine position variable
signed long int Xpos = 0;
signed long int Ypos = 0;
signed long int Zpos = 0;
// Set up the destination machine position variable
signed long int newXpos = 0;
signed long int newYpos = 0;
signed long int newZpos = 0;
// Set up global place to keep serial values
signed long int newSerialData;
bool XorY = false;
void setup() {
Serial.begin(9600); // set up Serial library at 9600 bps
Serial.println("Stepper Controller Online");
//set the default speed of the motors
motorX.setSpeed(RPM); ;
motorY.setSpeed(RPM); ;
motorZ.setSpeed(RPM); ;
delay(1000); // wait for the supply to come up
//step motors one step and back to power the coils
motorX.step(1, FORWARD, SINGLE);
motorY.step(1, FORWARD, SINGLE);
motorZ.step(1, FORWARD, SINGLE);
motorX.step(1, BACKWARD, SINGLE);
motorY.step(1, BACKWARD, SINGLE);
motorZ.step(1, BACKWARD, SINGLE);
// Home position
Xpos = 0;
Ypos = 0;
Zpos = 0;
newXpos = 0;
newYpos = 0;
newZpos = 0;
Serial.print("Current:");
Serial.print("\tX:");
Serial.print(Xpos);
Serial.print("\tY:");
Serial.print(Ypos);
Serial.print("\tZ:");
Serial.println(Zpos);
Serial.println("Ready for Commands");
}
void loop() {
while(Serial.available() ) {
// Loop simply accepts commands from serial and executes them
readHPGLcommand(); //read the command
}
}
void readHPGLcommand() {
// reads serial port for two letter HPGL command and optional coords that follow
char c;
bool coord_avail;
//make sure there is enough data there for form a command, at least "IN;"
if(Serial.available()>=3){
c = Serial.read();
// Interpret HPGL command, ingnore unsupported commands and whitespace
//http://paulbourke.net/dataformats/hpgl/ has definitions
switch( c ) {
case 'P' :
switch( Serial.read() ) {
case 'U' : // PU Pen Up
Serial.println("Pen Up \t/\\ /\\ /\\ /\\"); //lift pen and optionally move to new coords
zMove(50);
// expect either nothing or pairs of coords to follow
XorY = true;
coord_avail = true;
while( coord_avail ) {
coord_avail = readSerialNumber();
// hack to alternate reading values as X or Y
if ( XorY) {
newXpos = newSerialData;
XorY = false;
} else {
newYpos = newSerialData;
XorY = true;
Serial.print(newXpos); Serial.print(":"); Serial.print(newYpos); Serial.print("\t>>");
linearInterpolationMove( newXpos, newYpos);
}
}
break;
case 'D' : // PD Pen Down
Serial.println("Pen Down\t\\/ \\/ \\/ \\/"); //drop pen and optionally move to new coords
zMove(0);
coord_avail = false;
// expect either nothing or pairs of coords to follow
XorY = true;
coord_avail = true; //need to make sure the loop goes at least once
while( coord_avail ) {
coord_avail = readSerialNumber();
// hack to alternate reading values as X or Y
if ( XorY) {
newXpos = newSerialData;
XorY = false;
} else {
newYpos = newSerialData;
XorY = true;
// only valid coord if two values were found
Serial.print(newXpos); Serial.print(":"); Serial.print(newYpos); Serial.print("\t>>");
linearInterpolationMove( newXpos, newYpos);
}
}
break;
case 'G' : // PG Page Feed
Serial.println("Page Feed");
while( readSerialNumber() ) {} //keep reading until coords or ';' is found
// Command doesn't do anything yet
break;
case 'T' : // PG Pen Thickness
Serial.println("Pen Thickness");
while( readSerialNumber() ) {} //keep reading until coords or ';' is found
// expects one number to be returned, indicating pen
Serial.print("Pen Thickness Set to:");
Serial.println(newSerialData);
// currently not doing anything with this command
break;
default :
Serial.println("WARNING: Unknown command Px ignored");
while( readSerialNumber() ) {} //keep reading until coords or ';' is found
break;
}
break;
case 'I' :
switch( Serial.read() ) {
case 'N' : // IN Initialize
Serial.println("Initialize");
while( readSerialNumber() ) {} //keep reading until coords or ';' is found
// Home position
Xpos = 0;
Ypos = 0;
Zpos = 0;
break;
default :
Serial.println("WARNING: Unknown command Ix ignored: ");
while( readSerialNumber() ) {} //keep reading until coords or ';' is found
break;
}
break;
case 'S' :
switch( Serial.read() ) {
case 'P' : // SP Select Pen
Serial.println("Select Pen");
while( readSerialNumber() ) {} //keep reading until coords or ';' is found
// expects one number to be returned, indicating pen
Serial.print("Pen set to:");
Serial.println(newSerialData);
// currently not doing anything with this command
break;
default :
Serial.print("WARNING: Unknown command Sx ignored: ");
while( readSerialNumber() ) {} //keep reading until coords or ';' is found
break;
}
break;
default :
//Whitespace or unrecognized letter, ignore it
break;
} //cmd switch
} //if serial
}
bool readSerialNumber() {
//read coords from serial input
//commands end with ';' and lists of coords are separated by ','
//
// Three things can happen and need to differentiate
// 1) no coords at all, just a ; - need to return right away and break the calling while loop
// 2) a coordinate followed by , - need to output the coord and continue
// 3) a coordinate followed by ; - need to output the coord and break the calling while loop
signed long int coord = 0; //temp storage for coords from serial
signed int sign = 1; //temp storage for coord sign from serial
char c;
while ( c != ',' && c != ';' /*&& Serial.available()*/){
c = Serial.read();
if( c == '-' ) sign = -1; // capture the sign
if( c >= '0' && c <= '9'){
coord = (10 * coord) + (c - '0') ; // convert digits to a number
}
}
//put the data in the top level variable
newSerialData = coord * sign;
//detect the end of command ';' after the last coord
if( c == ';') return false;
return true;
}
void zMove (signed long int newZ) {
//calculates steps to move, and moves, to new Z position requested
signed long int distance = 0;
signed long int oldZ = Zpos;
distance = newZ - oldZ;
if ((distance < 8000) && (distance > -8000)) {
if (distance >= 1) motorZ.step(distance, FORWARD, SINGLE);
if (distance <= -1) motorZ.step(-1*distance, BACKWARD, SINGLE);
} else {
//movement requested is large and likely an error
Serial.println("ERROR - Z axis out of range");
}
Zpos = newZ; //update machine current position
}
void linearInterpolationMove ( signed long int newX, signed long int newY) {
float distance = 0;
int stepnum = 0;
signed long int nextX;
signed long int nextY ;
signed long int oldX = Xpos;
signed long int oldY = Ypos;
Serial.print("\t");
Serial.print(Xpos);
Serial.print(":");
Serial.print(Ypos);
Serial.print("\t --");
//find the hypotenuse, the total distance to be traveled
distance = sqrt((newX - oldX)*(newX - oldX) + (newY - oldY)*(newY - oldY) );
//round to integer number of steps that distance. Step by two to minimize 0 size steps.
for (stepnum=0; stepnum <= (distance + 0.5); stepnum++) {
//calculate the nearest integer points along the way
nextX = oldX + stepnum/distance*(newX-oldX);
nextY = oldY + stepnum/distance*(newY-oldY);
//move machine to that new coordinate, if 0 delta, don't move
if ((distance < 7*INCH) && (distance > -7*INCH)) { //trap crazy value
/* removed for test
if ((nextX-Xpos) >= 1) motorX.step((nextX - Xpos)*INCH/1000, FORWARD, SINGLE);
if ((nextX-Xpos) <= -1) motorX.step((Xpos - nextX)*INCH/1000, BACKWARD, SINGLE);
if ((nextY-Ypos) >= 1) motorY.step((nextY - Ypos)*INCH/1000, FORWARD, SINGLE);
if ((nextY-Ypos) <= -1) motorY.step((Ypos - nextY)*INCH/1000, BACKWARD, SINGLE);
*/
//update the machine current position
Xpos = nextX;
Ypos = nextY;
} else {
Serial.println("ERROR! Distance value too big");
break;
}
}
//move machine to the exact new coordinate, because rounding makes a small error
/* removed for test
if ((newX-Xpos) >= 1) motorX.step(newX - Xpos, FORWARD, SINGLE);
if ((newX-Xpos) <= -1) motorX.step(Xpos - newX, BACKWARD, SINGLE);
if ((newY-Ypos) >= 1) motorY.step(newY - Ypos, FORWARD, SINGLE);
if ((newY-Ypos) <= -1) motorY.step(Ypos - newY, BACKWARD, SINGLE);
*/
//update the machine current position
Xpos = newX;
Ypos = newY;
Serial.print("----> \t");
Serial.print(Xpos);
Serial.print(":");
Serial.println(Ypos);
}
Subscribe to:
Posts (Atom)