Using Arduino-Pins with LinuxCNC

Hello,
ive found some tutorials that use the Arduino-Pins for Analog and Digital Inputs and Outputs.
The Problem is that i cant find Projects that let me use ALL pins as digital inputs.
So ive tried to modify one project.
The Sketch on the Arduino looks like that:

byte port=0;
void setup() {
Serial.begin(9600);
for (int port = 2; port <= 13; port++) {
pinMode(port, INPUT_PULLUP);
}
}

byte byteout=0;

void loop() {
for (int port = 2; port <= 13; port++)
{

byteout |= digitalRead(port) << (port-2);

}
Serial.write(byteout);
byteout = 0;
}

My Problem is, that i can use pin 2-9 without problems but when the pinnumber is bigger than 9 the pin is not useable/changing states.
LinuxCNC is listing me all Pins but 10-13 are shown as "LOW".

The second problem is, that i cant really figure out what
byteout |= digitalRead(port) << (port-2);
really does..

Could someone help me?

LinuxCNC is listing me all Pins but 10-13 are shown as "LOW".

What is actually driving the pins?

The second problem is, that i cant really figure out what
byteout |= digitalRead(port) << (port-2);
really does..

Then why do you have it in your code? Have you looked at the documentation for the digitalRead() function? Have you looked at the documentation for the << operator? Have you looked at the documentation for the |= operator?

The digitalRead() function returns a 0 or 1. The left shift operator moves that bit to the left. The |= operator ors the value with what is already in byteout, without affecting any other bits, and stores the result back in byteout.

"port" is a very unfortunate name. The code is actually affecting the Arduino pins and "ArduinoPin" would be a better name. The Arduino also has ports which represent a group of pins.

I think the line of code you mention reads the pins in succession and creates a byte with the values. The << moves the data to the left by the number of bits represented by port-2

However I have no idea how they think 11 pins will fit in an 8-bit byte.

I have no idea why the code starts with byte port = 0; when that is never used and later an int called port is created.

All in all, it seems like crap code to me.

I don't know what you mean by

My Problem is, that i can use pin 2-9 without problems but when the pinnumber is bigger than 9

as there seems nothing in your code that is limited to pins 2-9.

...R

Thank you for your Informations.
The Code is not from me. Ive tried to adapt it to use alle pins as input and failed as you can see.
The guy who wrote the code gave the names.. i think i would name the pins "pin" and not port but thats something like cosmetic..

Every pin has a button connected and i can read the state that the arduino sends to the computer in the linuxcnc-gui.
A python-script is reading the state and pushs it to the HAL-Interface so i could connect it to the required functions.
Ive tried to figure out what this functions does. i know how digitalread works but ive not used those operands before and i was a little confused what the << (port-2) really does.
Correct me if im wrong but when it stores the pins in an 8-bit-byte i have the limit to 8 pins there...
Is there a possibility to output 8+ states?
Thank you for your help.

as there seems nothing in your code that is limited to pins 2-9.

Except for the fact that a byte is 8 bits...

dapeace:
Is there a possibility to output 8+ states?
Thank you for your help.

Forget all about the code you posted and just describe what it is you want to do. And keep in mind that I am not familiar with LinuxCNC although I have written code to drive steppers for my small lathe.

...R

i need the state of the pins sent to the python-script.
If i understand the code right, its reading all pins and write a sequence of bits to the serial-port.
At the moment its only working for 8 pins because of the limitation of the byte-variable.
I would like to send the state of pin 2-13 and, if possible, from the analog-pins too (that should be 2-19 then).

dapeace:
i need the state of the pins sent to the python-script.

Why not something like this pseudo code

for (byte n = 2; n < 13; n++) { // change the range to suit your requirement
  pinVal[n] = digitalRead(n);
}

Serial.print("<");
for (byte n = 2; n < 13; n ++) {
  Serial.print(pinVal[n]);
  Serial.print(",");
}
Serial.print(">");

That will send all the values like this "<1,0,0,1,....>"

The Python program can then do what it needs to with them.

This Python-Arduino demo may be useful

...R

the reason why i didnt rewrite all is, that i have no clue about python-coding and especially no clue how to use that hal-module that is needed for the interaction with linuxcnc.

Here is the counterpart on the linuxcnc-site that is creating the pins for the HAL-Interface and setting the value the arduino is sending. Maybe you could help me out with that?
Both parts together work for 8 pins at the moment..
the pins 10-13 are not responsing in the HAL-Viewer.

#!/usr/bin/python

import serial
import hal
import sys
import time

#PORT = "/dev/ttyACM0"

#allow the port to be overridden
if len(sys.argv) > 1:
PORT = sys.argv[1]

pinmapin = [2,3,4,5,6,7,8,9,10,11,12,13]

#Establish serial link
ser = serial.Serial(PORT, 9600, timeout=2)

#Setup the HAL component and pins
c = hal.component("arduino")
for port in range(12):
c.newpin("digital-in-%02d" % pinmapin[port], hal.HAL_BIT, hal.HAL_OUT)
c.newpin("digital-in-%02d-not" % pinmapin[port], hal.HAL_BIT, hal.HAL_OUT)
c.ready()

fromArduino=0
sum1=0
try:
while 1:
while ser.inWaiting():
port=0
fromArduino=ord(ser.read())
for port in range(12):
c["digital-in-%02d" % pinmapin[port]]= ((fromArduino >> port) & 1)
c["digital-in-%02d-not" % pinmapin[port]]=(~(c["digital-in-%02d" % pinmapin[port]])) & 1
ser.write(chr(sum1))
sum1=0
time.sleep(.002)
except (KeyboardInterrupt,):
raise SystemExit, 0

How should i change that to use the commaseperated values?

the pins 10-13 are not responsing in the HAL-Viewer.

Because the Arduino code is shifting the information into the bit bucket. The poorly named byteout needs to be an int.

dapeace:
Here is the counterpart on the linuxcnc-site that is creating the pins for the HAL-Interface

You are referring to stuff that means absolutely nothing to me. Please explain the terms you use.
And you are using language very loosely - software cannot create pins.

How should i change that to use the commaseperated values?

What format is the existing code expecting ?
If the Arduino can send that format there would be no need for changing the Python code.

...R

byteout |= digitalRead(port) << (port-2);

The Output of that is, what the python-script is expecting.

LinuxCNC has hardware and softwarepins. The Python-script is rerouting the hardwarepins to the softwarepins via serial-interface. The Python-Script takes the data from the arduino, creates the software-pins and connects the information and state of the Pins. The Hardware Abstraction Layer of LinuxCNC names these Pins really "Pins" :smiley:
This Linux-Distribution is using something like virtual wiring. First you connect some piece of hardware that gives you I/Os and then you can create the Virtual Pins for that I/Os and use them with different functions.
My main problem is still that i cant use more than 8 pins of the arduino. Changing the byteout to int didnt give me any breaktrough. Its still the same. Pin 2-9 are Working, Rest is not reacting.

dapeace:
The Output of that is, what the python-script is expecting.

That was not the question I was asking. But when I look at your Arduino code in your Original Post the next line is

Serial.write(byteout);

which suggests that the PC program just expects a series of bytes without any separator or start- or end-markers.

When I wrote Reply #7 I had assumed that you had written the Python program and you could change it to suit yourself.

It probably is possible to re-write the Python program you posted but it would take a lot of time and testing. It is probably easier to make the Arduino code comply with it without changes.

If you use a FOR loop to read the inputs (as in my code in Reply #7)

for (byte n = 2; n < 13; n++) { // change the range to suit your requirement
  pinVal[n] = digitalRead(n);
}

you then need to write some code to convert those values into two 8-bit bytes. For example (for 1 byte)

byte byteVal = 0;
for (byte n = 0; n <=7; n++) {
  byteVal = byteVal * 2 + pinVal[n];
}

I THINK your Python code expects a 16-bit value (two bytes) so it will be essential for the Arduino to send them in the correct order (I have no idea what that is - do you have any documentation ?)

The order of the bits within each byte will also be important (and, again, I don't know what is expected)

...R

Hello Robin2, thank you for helping me.
There is no real documentation.

Here is a basic information what that Project in its Original State should do.

Project Site

The Russian guy thats hosting the site modified the original scripts to give 8 inputs and 8 outputs.
Ive deleted the outputs of his files (arduino and python)and tried to expand the inputs to more than 8 without sucess.

I think changing the arduino-code instead of rewriting the python-script is easier too.
I will try to get your snippet working.

I got it working for me now. Ive rewriten the python-code (very very quick and dirty because my knowledge about python was ZERO in the morning) and the arduino-part as well (very simple now without checksums and stuff so handle with care).
Thank you guys for helping me.
If someone could explain me how to get the python-script simpler a hint would be very nice.
I could figure out how to do that without getting out of index range-errors.

Python:

#!/usr/bin/python

import serial
import hal
import sys
import time

PORT = "/dev/ttyUSB0"
pinmapin = [2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19]

ser = serial.Serial(PORT, 9600, timeout=2)

def is_number(var):
try:
if var == int(var):
return True
except Exception:
return False

#Setup the HAL component and pins
c = hal.component("arduino")
for port in range(18):
c.newpin("digital-in-%02d" % pinmapin[port], hal.HAL_BIT, hal.HAL_OUT)
c.ready()

zeilelesen = 0
try:
while 1:
while ser.inWaiting():
port=0
zeilelesen=(ser.readline())
zeilenlaenge = len(zeilelesen)
for port in range(zeilenlaenge):
test = zeilelesen[port]
if test == "0" and port == 0:
c["digital-in-%02d" % pinmapin[port]]= True
elif test == "1" and port == 0:
c["digital-in-%02d" % pinmapin[port]]= False
if test == "0" and port == 1:
c["digital-in-%02d" % pinmapin[port]]= True
elif test == "1" and port == 1:
c["digital-in-%02d" % pinmapin[port]]= False

if test == "0" and port == 2:
c["digital-in-%02d" % pinmapin[port]]= True
elif test == "1" and port == 2:
c["digital-in-%02d" % pinmapin[port]]= False
if test == "0" and port == 3:
c["digital-in-%02d" % pinmapin[port]]= True
elif test == "1" and port == 3:
c["digital-in-%02d" % pinmapin[port]]= False
if test == "0" and port == 4:
c["digital-in-%02d" % pinmapin[port]]= True
elif test == "1" and port == 4:
c["digital-in-%02d" % pinmapin[port]]= False
if test == "0" and port == 5:
c["digital-in-%02d" % pinmapin[port]]= True
elif test == "1" and port == 5:
c["digital-in-%02d" % pinmapin[port]]= False
if test == "0" and port == 6:
c["digital-in-%02d" % pinmapin[port]]= True
elif test == "1" and port == 6:
c["digital-in-%02d" % pinmapin[port]]= False
if test == "0" and port == 7:
c["digital-in-%02d" % pinmapin[port]]= True
elif test == "1" and port == 7:
c["digital-in-%02d" % pinmapin[port]]= False
if test == "0" and port == 8:
c["digital-in-%02d" % pinmapin[port]]= True
elif test == "1" and port == 8:
c["digital-in-%02d" % pinmapin[port]]= False

if test == "0" and port == 9:
c["digital-in-%02d" % pinmapin[port]]= True
elif test == "1" and port == 9:
c["digital-in-%02d" % pinmapin[port]]= False
if test == "0" and port == 10:
c["digital-in-%02d" % pinmapin[port]]= True
elif test == "1" and port == 10:
c["digital-in-%02d" % pinmapin[port]]= False
if test == "0" and port == 11:
c["digital-in-%02d" % pinmapin[port]]= True
elif test == "1" and port == 11:
c["digital-in-%02d" % pinmapin[port]]= False
if test == "0" and port == 12:
c["digital-in-%02d" % pinmapin[port]]= True
elif test == "1" and port == 12:
c["digital-in-%02d" % pinmapin[port]]= False
if test == "0" and port == 13:
c["digital-in-%02d" % pinmapin[port]]= True
elif test == "1" and port == 13:
c["digital-in-%02d" % pinmapin[port]]= False
if test == "0" and port == 14:
c["digital-in-%02d" % pinmapin[port]]= True
elif test == "1" and port == 14:
c["digital-in-%02d" % pinmapin[port]]= False
if test == "0" and port == 15:
c["digital-in-%02d" % pinmapin[port]]= True
elif test == "1" and port == 15:
c["digital-in-%02d" % pinmapin[port]]= False
if test == "0" and port == 16:
c["digital-in-%02d" % pinmapin[port]]= True
elif test == "1" and port == 16:
c["digital-in-%02d" % pinmapin[port]]= False
if test == "0" and port == 17:
c["digital-in-%02d" % pinmapin[port]]= True
elif test == "1" and port == 17:
c["digital-in-%02d" % pinmapin[port]]= False
if test == "0" and port == 18:
c["digital-in-%02d" % pinmapin[port]]= True
time.sleep(.002)
except (KeyboardInterrupt,):
raise SystemExit, 0

Arduino-Part:

void setup() {
Serial.begin(9600);
for (int port = 2; port <= 19; port++) {
pinMode(port, INPUT_PULLUP);
}
}

void loop() {

for (int port = 2; port <= 19; port++) {
Serial.print(digitalRead(port));
}
Serial.print("\n");
delay(15);

}

This is a bit of a guess, but I think this will be sufficient for all the ports

if test == "0" :
     c["digital-in-%02d" % pinmapin[port]]= True
elif test == "1":
     c["digital-in-%02d" % pinmapin[port]]= False

and I wonder if this would be sufficient ?

c["digital-in-%02d" % pinmapin[port]]= test

...R

Hello,
ive found some tutorials that use the Arduino-Pins for Analog and Digital Inputs and Outputs.
The Problem is that i cant find Projects that let me use ALL pins as digital inputs.
So ive tried to modify one project.
The Sketch on the Arduino looks like that:

My Problem is, that i can use pin 2-9 without problems but when the pinnumber is bigger than 9 the pin is not useable/changing states.
LinuxCNC is listing me all Pins but 10-13 are shown as "LOW".

The second problem is, that i cant really figure out what
byteout |= digitalRead(port) << (port-2);
answer or onto digitalRead(port) shift left (higher) this many bits (value of port -2)

so for:
port = 2
port 2 is HIGH
B00000001 = B0000000 | 1 << (2-2 is 0) or B00000001
port = 3
port 3 = HIGH
B00000011 = B0000001 | 1 << (3-2 is 1) or B00000010
port = 4
port 4 = LOW
B00000011 = B0000011 | 0 << (4-3 is 2) or B00000000
port = 5
port 5 = HIGH
B00001011 = B0000011 | 1 << (5-2 is 3) or B00000100

really does..

Could someone help me?

I'm working on interfacing a Arduino MEGA to linuxcnc

// file name udpLCNCMEGA.ino edit for using pin 10 or not. I modded my ethernet W5100 to use pin 53 instead of pin10
// I can't find in the arduino source if that matters.
// look below for
// file udpioMEGA.hal edit for your IP numbers
// file updioMEGA.py edit for your IP numbers
// file define.h for Arduino edit your IP numbers

const float pi=3.14159265358979;
//#include <Encoder.h>
#include <SPI.h> // needed for Arduino versions later than 0018
#include <Ethernet.h>
#include <EthernetUdp.h> // UDP library from: bjoern@cs.stanford.edu 12/30/2008
#includ

Get the complete file from MEGAEtherStepperANDOTHERFILES.ino - Pastebin.com
*/

[/quote]

Robin2:
Why not something like this pseudo code

for (byte n = 2; n < 13; n++) { // change the range to suit your requirement

pinVal[n] = digitalRead(n);
}

Serial.print("<");
for (byte n = 2; n < 13; n ++) {
  Serial.print(pinVal[n]);
  Serial.print(",");
}
Serial.print(">");




That will send all the values like this "<1,0,0,1,....>"

The Python program can then do what it needs to with them.

This [Python-Arduino demo](http://forum.arduino.cc/index.php?topic=225329.msg1810764#msg1810764) may be useful

...R

cromaglious:
The second problem is, that i cant really figure out what
byteout |= digitalRead(port) << (port-2);

really does..

Write a short program that does each piece on a separate line so you can print all the intermediate values

Your naming is confusing. Normally "port" means all 8 pins on an I/O port. digitalRead() works on a pin, not a port.

...R