NXC: 1 NXT controls other NXTs - rs485 I/O remote control
Posted: 06 Jan 2013, 09:27
Thank you again, Matthew, for providing us with your following code for low-level sending byte arrays via rs485:
Of course, for this we have to have advanced functions which are built upon these basic low level send-byte-array functions.
So we need to write wraps around Matthew's message procedure with kind of the following functionality and sort of the following syntax ("RS" indicates rs485 opposite to "BT" which could indicate Bluetooth for a later implementation in order to keep the same syntax):
Unfortunately I currently can't imagine yet how to use these byte-array-send/receive procedures for multiple remote-sensor- and motor-control, not for single devices and especially not for sensors and motors at remote-multiplexers.
So how could one implement these high level functions for easy and trouble-free access?
What would be the code for the master, what for the slaves?
If once being resolved for these examples, then step by step we then can build a remote library for all other NXT compatible sensors.
Any ideas?
Based upon this library, now the first step for all communication for 1 NXT to control other NTXs is : how can one control remote sensors and remote motors easily ?mattallen37 wrote:I know the RS485 library should work, but I haven't run either of these test programs for a while.
NXC RS485 libraryrx test programCode: Select all
/* * Matthew Richardson * matthewrichardson37<at>gmail.com * http://mattallen37.wordpress.com/ * Aug. 11 / 2012 * * You may use this code as you wish, provided you give credit where it's due. * * This is library for easy use of RS485 master/slave transactions. */ /* My RS485 protocol data specs: Sending byte array looks like this (based on how Mark Crosby does it) : byte type description 0 MSG_TYPE The type of message. 1 BYTE_COUNT The count of bytes in the message body, excluding the header. 2 CHECKSUM CRC8 checksum computed across the message body. 3 DEST_ADDR Destination address for the message, or 0 for BROADCAST. 4 SRC_ADDR Source address of the message sender. 5-n The data Returned values -6 wrong message length -5 wrong checksum -4 not even the entire header was received -3 not my address -2 timeout -1 something went wrong 0 Destination address was BROADCAST 1 Destination address was mine */ #ifndef _MyRS485Base_h_ #define _MyRS485Base_h_ void MyRS485BaseWriteArray (byte My485Address, byte TargetAddress, byte MsgType, byte SendData[], byte Length = 0){ byte ByteCount = ArrayLen(SendData); if(Length){ ByteCount = Length; } byte SendCompleteData[]; byte SendCompleteDataLength = ByteCount + 5; ArrayInit(SendCompleteData, 0, SendCompleteDataLength); SendCompleteData[0] = MsgType; SendCompleteData[1] = ByteCount; SendCompleteData[2] = ArraySum(SendData, NA, ByteCount) & 0xFF; SendCompleteData[3] = TargetAddress; SendCompleteData[4] = My485Address; for(byte i = 0; i < ByteCount; i++){ SendCompleteData[i + 5] = SendData[i]; } RS485Write(SendCompleteData); until(HSOutputBufferOutPtr() == SendCompleteDataLength); } int MyRS485BaseRead(byte My485Address, byte & MsgType, byte & InArray[], int timeout = 250){ byte RawInArray[]; long OrigionalTick = CurrentTick(); until(RS485DataAvailable()){ // Wait until data has been received if(timeout && (CurrentTick() - OrigionalTick >= timeout))return -2; // return -2 if it timed-out waiting for the responce. Yield(); } byte DataAvailable = RS485DataAvailable(); Wait(1); while(DataAvailable < RS485DataAvailable()){ // If it's been 1 ms since the last data was received, assume it's the end of the message. DataAvailable = RS485DataAvailable(); Wait(1); } RS485Read(RawInArray); if(DataAvailable < 5)return -4; // Not even the entire header was received. MsgType = RawInArray[0]; byte ByteCount = RawInArray[1]; byte Checksum = RawInArray[2]; byte DestAddr = RawInArray[3]; byte SrcAddr = RawInArray[4]; if (DestAddr == My485Address || DestAddr == 0) { if(ByteCount != DataAvailable - 5){ return -6; } byte ChecksumComputed = ArraySum(RawInArray, 5, NA) & 0xFF; if(Checksum != ChecksumComputed){ return -5; } ArraySubset(InArray, RawInArray, 5, NA); return DestAddr?1:0; } else{ return -3; } return -1; } void RS485Init(byte speed = HS_BAUD_921600) // Turn on RS485 and set a baud rate { UseRS485(); Wait(MS_10); SetHSDataMode(DATA_MODE_RAW); Wait(MS_10); RS485Uart(speed, HS_MODE_DEFAULT); Wait(MS_10); SetHSInputBufferInPtr(0); SetHSInputBufferOutPtr(0); } void RS485UnInit(){ // Turn off the RS485 port of the NXT SetSensorType(S4, SENSOR_TYPE_NONE); SetHSFlags(HS_UPDATE); SetSensorType(S4, SENSOR_TYPE_NONE); } #endif
tx test programCode: Select all
#include "MyRS485Base lib.nxc" byte Array[]; byte MsgType; task main(){ RS485Init(HS_BAUD_115200); while(true){ //NumOut(0, LCD_LINE5, MyRS485BaseRead(2, MsgType, Array, 100)); int result = MyRS485BaseRead(2, MsgType, Array, 100); ClearScreen(); NumOut(0, LCD_LINE1, result); if(result >= 0){ NumOut(0, LCD_LINE2, MsgType); for(byte i = 0; i < ArrayLen(Array); i ++){ NumOut(50, LCD_LINE1 - (i*8), Array[i]); } } } }
Code: Select all
#include "MyRS485Base lib.nxc" byte Array[6]; byte MsgType; byte b1, b2, lx, ly, rx, ry; task main(){ RS485Init(HS_BAUD_115200); SetSensorLowspeed(S3); while(true){ ReadSensorMSPlayStation(S3, 0x02, b1, b2, lx, ly, rx, ry); Array[0] = b1; Array[1] = b2; Array[2] = lx; Array[3] = ly; Array[4] = rx; Array[5] = ry; MsgType = ButtonPressed(BTNCENTER)?2:0; MyRS485BaseWriteArray(1, 2, MsgType, Array); Wait(10); } }
Of course, for this we have to have advanced functions which are built upon these basic low level send-byte-array functions.
So we need to write wraps around Matthew's message procedure with kind of the following functionality and sort of the following syntax ("RS" indicates rs485 opposite to "BT" which could indicate Bluetooth for a later implementation in order to keep the same syntax):
Code: Select all
RemoteSetSensor(RS, 2, S1, SENSOR_TOUCH); // via RS485: config at NXT #2: Touch sensor at S1
RemoteSetSensor(RS, 10, S2, SENSOR_US); // via RS485: config at NXT #10: US sensor at S2
RemoteSetSensor(RS, 4, S3, SENSOR_RAW); // via RS485: config at NXT #4: analog sensor (ADC raw) at S3
int x=RemoteSensorTouch(RS, 2, S1); // via rs485: read at NXT #2: Touch Sensor value at S1
int x=RemoteSensorUS(RS, 10, S2); // via rs485: read at NXT #10: US Sensor value at S2
int x=RemoteSensorRaw(RS, 4, S3); // via rs485: read at NXT #4: analog sensor value (ADC raw) at S3
RemoteOnFwd(RS, 3, OUT_A, pwr); // via rs485: onFwd at NXT #3: OUT_A by pwr
RemoteOnFwdReg(RS, 5, OUT_B, pwr, regmode); // via rs485: onFwdReg at NXT #5: OUT_B by pwr, regmode
long e=RemoteMotRotCounter(RS, 9, OUT_C); // via rs485: at NXT #9: read motor rotation counter of OUT_C
So how could one implement these high level functions for easy and trouble-free access?
What would be the code for the master, what for the slaves?
If once being resolved for these examples, then step by step we then can build a remote library for all other NXT compatible sensors.
Any ideas?