IO interface with Arduino over Ethernet

More
13 Mar 2017 20:50 #89549 by mariusl
Also look at the System Workbench for STM32. It's an Eclipse based IDE for STM. Very powerful environment. The Arduino framework is limited and most developed for the F103 so you might have some success. It is still very green though.

Regards
Marius


www.bluearccnc.com

Please Log in or Create an account to join the conversation.

More
13 Mar 2017 21:32 #89552 by DocStein99

Im looking at ordering a stm32f103c8t6 and a enc28j60 network adapter to see how much speed i can get for encoder counting... The arm cortex-m3 runs at 72mhz and it looks like it can be programmed from the arduino ide. I'll let you know how i go.


That's obviously much faster than the Uno or Nano boards I'm testing with. Are you using the encoders for position feedback?

Please Log in or Create an account to join the conversation.

More
13 Mar 2017 21:35 #89553 by DocStein99

Also look at the System Workbench for STM32. It's an Eclipse based IDE for STM. Very powerful environment. The Arduino framework is limited and most developed for the F103 so you might have some success. It is still very green though.


It's all the libraries and example support I rely on for Arduino, that helps me to learn and get a project done.

Please Log in or Create an account to join the conversation.

More
14 Mar 2017 03:55 #89568 by M4MazakUser
Yes i want to see if I can use it for position feedback. The board should turn up by the end of the week. Im very keen to see what i can squeeze out of it. Id like to be able to do pwm and encoder reading to run a servo drive -linked into Linux cnc as best as I can.(over ethernet).I'll look up the ide you named thanks! (I am quite used to the arduino ide and 20+ years of g coding helps lol!).

Please Log in or Create an account to join the conversation.

More
14 Mar 2017 09:18 #89577 by DocStein99
I have a stepper with an encoder on it, I never tested yet. I have never used the positioning feedback system in LinuxCNC, all the machines I've built just had steppers open loop.

There is a latency in the transmission of the data between the Linux box and my Arduino, definately enough time to foul up positioning, if I were to use parallel pins local and expect position feedback through an network.

Do you plan also to send the step & direction pulses through the network as well? If that's the case - the packets would have to travel to the module through the network latency - then be even more latent to receive the encoder feedback. The module would need a complicated algorithm to work. At that point, the module is pretty much driving the motion, instead of HAL.

Please Log in or Create an account to join the conversation.

More
14 Mar 2017 09:58 #89578 by M4MazakUser
my answer is... mesa does it, even if it requires using linuxcnc only to provide settings and if the magic is done on the card, its the cost!. -im in australia.... trump is in... US $ is up... aussie dollar is crud!

Please Log in or Create an account to join the conversation.

More
15 Mar 2017 10:17 #89654 by M4MazakUser
after doing some searching ive found that the stm32 (or the stm32f107c i ordered) has hardware encoder counters -timers that can be configured as quadrature encoder counters.
example as follows. -using arduino ide


/*
* Hardware Timer as an Encoder interface.
*
* The STM32 Timers have the possibility of being used as an encoder interface.
* This can be both a quadrature encoder (mode 3) or pulse encoder with a signal to give direction (modes 1 and 2).
* The default behavior is for quadrature encoder.
*
* To avoid overflowing the encoder (which may or may not happen (although with 16 bits, it's likely), the following code
* will interrupt every time the number of pulses that each revolution gives to increment/decrement a variable (ints).
*
* This means that the total number of pulses given by the encoder will be (ints * PPR) + timer.getCount()
*
* To test this library, make the connections as below:
*
* TIMER2 inputs
* D2
* D3
*
* COUNTING DIRECTION:
* 0 means that it is upcounting, meaning that Channel A is leading Channel B
*
* EDGE COUNTING:
*
* mode 1 - only counts pulses on channel B
* mode 2 - only counts pulses on Channel A
* mode 3 - counts on both channels.
*
*/



#include "HardwareTimer.h"


//Encoder stuff

//Pulses per revolution
#define PPR 1024

HardwareTimer timer(2);

unsigned long ints = 0;

void func(){
if (timer.getDirection()){
ints--;
} else{
ints++;
}
}


void setup() {
//define the Timer channels as inputs.
pinMode(D2, INPUT_PULLUP); //channel A
pinMode(D3, INPUT_PULLUP); //channel B

//configure timer as encoder
timer.setMode(0, TIMER_ENCODER); //set mode, the channel is not used when in this mode.
timer.pause(); //stop...
timer.setPrescaleFactor(1); //normal for encoder to have the lowest or no prescaler.
timer.setOverflow(PPR); //use this to match the number of pulse per revolution of the encoder. Most industrial use 1024 single channel steps.
timer.setCount(0); //reset the counter.
timer.setEdgeCounting(TIMER_SMCR_SMS_ENCODER3); //or TIMER_SMCR_SMS_ENCODER1 or TIMER_SMCR_SMS_ENCODER2. This uses both channels to count and ascertain direction.
timer.attachInterrupt(0, func); //channel doesn't mean much here either.
timer.resume(); //start the encoder...

}

//Support variables.
unsigned long interval=0; //variable for status updates...
char received = 0;

void loop() {
//encoder code
if (millis() - interval >= 1000) {
Serial.print(timer.getCount());
Serial.println(" counts");
Serial.print("direction ");
Serial.println(timer.getDirection());
Serial.print("Full Revs: ");
Serial.println(ints);
interval = millis(); //update interval for user.
}
}

this shows a lot of promise.

Please Log in or Create an account to join the conversation.

More
15 Mar 2017 15:00 - 15 Mar 2017 15:02 #89669 by DocStein99
I already got my code to transmit encoder signals to LinuxCNC to manually jog. I'll post my code - it's not polished up clean, but you get the idea:
/*
https://forum.linuxcnc.org/media/kunena/attachments/9308/udpcomms.txt

Modified 	2-13-2017 - begin, Erich Stein
			2-14-2017 - process code, make adjustments
			2-20-2017 - debugged transmit failure, continue to speed test

The purpose of this program is to provide a wireless hardware interface to LinuxCNC.

Features:

	Input:

	1 Encoder interface					2 DI			- Multipurpose jog positioning
	1 Analog potentiometer input		1 AI			- Speed feed override
	2 Pushbuttons						2 DI			- 1) Toggle encoder axis, 2) Toggle encoder precision
	3 Switches							3 DI			- Machine on-ready, 2 undefined
	
	Output:
	2 Digital signals output				2 DO		- Machine on, Error stop
	3 Digital signals output 				3 DO		- System homed x, y, z
	Sound buzzer - TODO Optional 			1 DO		- Audio output interface, errors, ready, done, input required
	
	Budget:								6 + 6			- 12 SIGNALS, speaker, audio amplifier
	

*/

//#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
//#include <string.h>
//#include <stdio.h>
//#include <stdlib.h>
//#include <ctype.h>

#include <WiFiEsp.h>
#include <WiFiEspUdp.h>
#include <Encoder.h>

// emulate Serial1 if not present
#ifndef HAVE_HWSERIAL1
  #include "SoftwareSerial.h"
  SoftwareSerial Serial1(5, 4); // RX, TX
#endif

//#define cDebug true
#define cDebug false

WiFiEspUDP Udp;														// An EthernetUDP instance to let us send and receive packets over UDP
//IPAddress ipLocal(192, 168, 16, 200);								// local ip address
IPAddress ipRemote(192, 168, 16, 9);								// remote ip address
char ssid[]		= "my_local_wifi_ssid";
char pass[]		= "mySSIDpassword";

unsigned int portLocal = 8888;      								// local port 
unsigned int portRemote = 8888;										// remote port

#define iPacketSize 100
byte rxChar;
char workBuffer[iPacketSize];
char rxTokens[5];
char *newToken;
const char sComma[2] = ",";
char *token;

//char packetBuffer[UDP_TX_PACKET_MAX_SIZE]; 							// buffer to hold incoming packet,
char packetBuffer[iPacketSize]; 										// buffer to hold incoming packet,
char  ReplyBuffer[iPacketSize];// = "acknowledged";       				// a string to send back
String sMessage = "";
uint16_t adcResult;

int pinADC=A0;															// pin number for analog input
uint8_t firstbyte=0x0;

const byte byPinsInput = 6;												// number of input pins.
const byte  byPinsOutput = 6;											// number of output pins.  For some reason, is receiving ?!?!
const byte byPinsOutputAnalog = 2;										// number of analog input pins
byte pinMapOut[byPinsOutput] = {A1,A2,8,9,10,11};						// Output pins
byte pinMapIn[byPinsInput] = {A1,A2,8,9,10,11};							// Output pins
uint8_t dacPinMap[1] = {A3};											// appears to be only 1 (2?) analog outputs

// encoder section
#define ENCODER_OPTIMIZE_INTERRUPTS
//Encoder myEncoder(5, 4);												// Encoder interface
Encoder myEncoder(3, 2);												// Encoder interface
char cCounter[2] = {0,0};
char oldPosition = -1;
char newPosition = 0;

void setup() 
{
	pinMode(2, INPUT_PULLUP);
	pinMode(3, INPUT_PULLUP);
	//pinMode(4, INPUT_PULLUP);
	//pinMode(5, INPUT_PULLUP);

	Serial.begin(115200);
	Serial.println(F("Initiate program emc2interface v1.1.1"));

	// start the Ethernet and UDP:
	Serial1.begin(9600);
	WiFi.init(&Serial1);
	WiFi.begin(ssid, pass);
	
	while (WiFi.status() != WL_CONNECTED)
	{
		delay(64);
		Serial.print(F(". "));
	}

	Serial.println();
	Serial.print(F("Connect WiFi, IP: "));  
	Serial.println(WiFi.localIP());

	Udp.begin(portLocal);
	
}

void loop() 
{
	//	encodeTx();															// moved from [here]

	// if there's data available, read a packet
	int packetSize = Udp.parsePacket();
	if(packetSize)
	{
		
		Udp.read(packetBuffer, iPacketSize);
		
		if (cDebug)
		{
			Serial.print(F("Packet size:"));
			Serial.print(packetSize);
			Serial.print(F(" Buffer:"));
			Serial.println(packetBuffer);
		}
		
		decodeRx(packetBuffer, packetSize);
		
		memset(packetBuffer,'\0',sizeof(packetBuffer));
		
		//delay(10);

		encodeTx(); 														// moved to [here]
		
	}

	//process encoder data
	newPosition = char(myEncoder.read());
	if (newPosition>=126 || newPosition<=-126)
	{
		myEncoder.write(0);
		oldPosition = -1;
		newPosition = 0;
	}
	if (newPosition != oldPosition)
	{
		if (cDebug)
		{
			Serial.print(F("PosNew:"));
			Serial.print(int(newPosition));
			Serial.print(F(", "));
			Serial.print(int(cCounter[1]));
			Serial.print(F(" PosOld:"));
			Serial.print(int(oldPosition));
			Serial.print(F(", "));
			Serial.print(int(cCounter[0]));
			Serial.println();
		}
		cCounter[0] = oldPosition;
		cCounter[1] = newPosition;
		oldPosition = newPosition;
	}

	//delay(1);
}

void decodeRx(char* rxBuffer, int iBufferLength)
{
	int iInt = 0;
	
	memset(workBuffer,'\0',sizeof(workBuffer));									// clear memory
	
	if (cDebug)
	{
		Serial.print(F("rxBuffer:"));
		for(int iTemp=0;iTemp<iBufferLength;iTemp++)
			Serial.write(rxBuffer[iTemp]);
	}

	if(rxBuffer[0] != '[')
	  return;
	
	strncpy(workBuffer,&rxBuffer[5],iBufferLength);
	if (cDebug)
	{
		Serial.print(F(" sCopy5:"));
		Serial.print(&rxBuffer[5]);
		Serial.print(F(" workBuffer:"));
		Serial.println(workBuffer);
	}
	
	/* get the first token */
	token = strtok(workBuffer, sComma);
	newToken = skip_spaces(token);
	rxTokens[iInt] = atoi(newToken);
	iInt++;
	/* walk through other tokens */
	while( token != NULL ) 
	{
		token = NULL;
		token = strtok(NULL, sComma);
		newToken = skip_spaces(token);
		rxTokens[iInt] = atoi(newToken);
		iInt++;
	}

	for (char xChar = 0; xChar < 4; xChar++)										// 0 - 3
	{
		rxChar = rxTokens[xChar];

		switch (xChar)
		{
		case 0:
			if (cDebug)
			{// get the analog output value
				//analogWrite(dacPinMap[xChar], rxChar);
				Serial.print(F(" aWr:"));
				Serial.print(dacPinMap[xChar]);
				Serial.print(F(" ~ "));
				Serial.println((byte)rxChar);
			}
			break;
		case 1:																		// get the number of output pins
			for (int zCounter = 0; zCounter < byPinsOutput; zCounter++)
			{
				uint8_t  iOutTemp = 0;
				iOutTemp = ((rxChar >> zCounter) & 1);
				if (cDebug)
				{
					Serial.print(F(" dWrite:"));
					Serial.print(pinMapOut[zCounter]);
					Serial.print(F(" ~ "));
					Serial.println(iOutTemp);
					//digitalWrite(pinMapOut[z], iOutTemp);
				}
			}
			
		
			break;
		case 2:				 														// get the values for output pins
		/*
			Serial.print(F(" oC Pins:"));
			Serial.print(rxChar);
			//Serial.print(F(" oPins:"));
			//byPinsOutput = rxChar;
			//Serial.println(byPinsOutput);
			for (byte byPinCounter = 0; byPinCounter < byPinsInput; byPinCounter++)
			{
				if(byPinCounter < byPinsOutput) 											// set only the output pins ????
				{
					Serial.print(F(" PinOutM:"));
					Serial.print(pinMap[bPinout]);
					Serial.print(F(" ~ "));
					//pinMode(pinMap[bPinout], OUTPUT);
				}
				else // set the input pins
				{
					Serial.print(F(" PinInM:"));
					Serial.print(pinMap[bPinout]);
					Serial.print(F(" ~ "));
					//pinMode(pinMap[bPinout], INPUT);
				}
			}
			Serial.println();
			*/	
			break;		
		case 3: 																	// get the pullup values for input pins
		/*
			for (int nCounter = 0; nCounter < byPins; nCounter++)
			{
				uint8_t iDirTemp = 0; 
				if (nCounter >= byPinsInput) 										// only for input pins
				{
					iDirTemp = ((rxChar >> nCounter) & 1);
					Serial.print(F(" PullUp:"));
					Serial.print(pinMap[nCounter]);
					Serial.print(F(" Dir:"));
					Serial.print(iDirTemp);
					Serial.print(F(" ~ "));
					//digitalWrite(pinMap[n], iDirTemp);
				}
			}
			Serial.println();
			*/
			break;
		}

	}
}

void encodeTx()																								// send the input pin data + encoder positions
{
	String sTest = "";
	uint8_t iDigitalStack = 0;
	for(byte byCounter = 0; byCounter < byPinsInput; byCounter++)
	{
		// int dummy = byCounter;
		if (byCounter >= 2)																					// greater than 2 are digital
		{
			//int moredummy = byCounter;
			if(digitalRead(pinMapIn[byCounter-2]))
			{
				iDigitalStack |= (1<<byCounter);
			}
		} else
		{
			adcResult = analogRead(pinMapIn[byCounter]);														// send values for analog pin
			sprintf(ReplyBuffer, "%4d", adcResult);
	
			sTest += ReplyBuffer;
			sTest +=",";
		}
	}
	
	// output the chain of pinMap 
	sprintf(ReplyBuffer,"%3d", iDigitalStack);
	
	sTest += ReplyBuffer;
	sTest += ",";
	/*
	Serial.print(F("R-PinMap buffer: "));
	Serial.print(ReplyBuffer);
	Serial.print(F(" ~ "));
	*/
	// The following is legacy encoder live state transmission
	
	sprintf(ReplyBuffer,"%4d", cCounter[0]);
	
	sTest += ReplyBuffer;
	sTest += ",";
	/*
	Serial.print(F("mpg 0: "));
	Serial.print(ReplyBuffer);
	Serial.print(F(" "));
	*/
	sprintf(ReplyBuffer,"%4d", cCounter[1]);
	sTest += ReplyBuffer;
	sTest += "~";
	
	sTest.toCharArray(ReplyBuffer,sTest.length());
	
	if (cDebug)
	{
		Serial.print(F("sTest:"));
		Serial.print(sTest);
	
		//	sTest.toCharArray(ReplyBuffer,iPacketSize);
	

		Serial.print(F(" Reply:"));
		for(int iTemp=0;iTemp<sTest.length();iTemp++)
			Serial.write(ReplyBuffer[iTemp]);
	}
	
	Udp.beginPacket(Udp.remoteIP(), Udp.remotePort());
	//Udp.beginPacket(ipRemote, portRemote);
	Udp.write(ReplyBuffer);
	Udp.endPacket();
		
}

void charClear (char * cData)
{
	for( int iCounter = 0; iCounter < sizeof(cData);  ++iCounter )
		cData[iCounter] = (char)0;
}

char *skip_spaces(const char *str)
{
	while (isspace(*str))
		++str;
	return (char *)str;
}

Last edit: 15 Mar 2017 15:02 by DocStein99.

Please Log in or Create an account to join the conversation.

More
01 May 2017 03:08 #92405 by cromaglious
Hi Marius;

You sir, are a god! I've taken your code and ported it to the Arduino MEGA2560. I was able to get 24 pins for digital output, 10 pins for PWM output. 16 pins for digital input, and a further 6 pins being read by interrupts.

Using binary for data I was able to get the packet size down to 14bytes for receive to the Arduino and 3 bytes for the return packet. the packet size will grow a bit more when I get the serial communication working. pins 14,15,16,17 for serial. I'm using the analog pins as digitals, though I might make 8 pins analog in the future. Which would grow the send packet grow by 11 bytes 12bits per pin.. is a byte and a nibble. So I save a byte on the digital pins, and grow 12 bytes for the 8 12bits adc values.
// evens
byte wbuf[12];
for(i=0; i<8; i=i+2) { tbuf=analogRead(i); wbuf[i+ANALOGDATA]=char(tbuf & B11111111); wbuf[(i/2)+8]=char(tbuf>>8);}
//odds
for(i=1; i<8; i=i+2) { tbuf=analogRead(i); wbuf[i+ANALOGDATA]=char(tbuf & B11111111); wbuf[(i-1)/2+8]|=(tbuf>>4)&B11110000 ;}

having an issue with gwibber
my code isn't working at the second...

Please Log in or Create an account to join the conversation.

More
01 May 2017 03:46 #92406 by DocStein99
I had to go re-write the original code for I got mine to run. I couldn't figure out why it was changing the input/output modes from the digital pins in the main loop.

Please Log in or Create an account to join the conversation.

Time to create page: 0.126 seconds
Powered by Kunena Forum