can bricks be "linked"

Discussion specific to the intelligent brick, sensors, motors, and more.
mattallen37
Posts: 1818
Joined: 02 Oct 2010, 02:19
Location: Michigan USA
Contact:

Re: can bricks be "linked"

Post by mattallen37 »

I have some RS485 libraries that seem to work very well for me. If anyone is interested in them, to use, then I will post them as they currently exist. I have a matching C++ for Arduino library as well (for RS485 communication between the NXT and Arduino). The protocol I use includes addresses and error detection.
Matt
http://mattallen37.wordpress.com/

I'm all for gun control... that's why I use both hands when shooting ;)
HaWe
Posts: 2500
Joined: 04 Nov 2014, 19:00

Re: can bricks be "linked"

Post by HaWe »

I am interested (although I only have 1 NXT + 1 or 2 of a friend any longer).
mattallen37
Posts: 1818
Joined: 02 Oct 2010, 02:19
Location: Michigan USA
Contact:

Re: can bricks be "linked"

Post by mattallen37 »

I know the RS485 library should work, but I haven't run either of these test programs for a while.

NXC RS485 library

Code: 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
rx test program

Code: 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]);
      }
    }
  }
}
tx test program

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);
  }
}
Matt
http://mattallen37.wordpress.com/

I'm all for gun control... that's why I use both hands when shooting ;)
HaWe
Posts: 2500
Joined: 04 Nov 2014, 19:00

Re: can bricks be "linked"

Post by HaWe »

thank you!
it's rather late here tonight in Europe so I'll try it probably tomorrow.
If you don't mind, I'll link your post / your code to the German Mindstorms forum so that more people may test it and have a benefit.

the code e.g. for a simple RCX motor control on a remote NXT currently goes like this to drive a RCXmotor1 to the down, or the medium, or the upper positions, running in seperate tasks to be stoppable at any time by
remote-void MotorOff(const byte &port),
using touch sensors S1 (dn), S2 (md), S3 (up) which indicate the correct position
(2 additional RCX motors (not in that code) are running the pneumatic pressure pump and the electromagnetic pneumatic valves).
The remote1-RCX motor is attached to a remote-MS-Mmux.

Code: Select all

//------------------------------------------------------------------------------
char CmdRdy;

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
inline void MotorOff(const byte &port)
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
{
   SetOutput(port, Power, 0,
             OutputMode,  OUT_MODE_COAST,
             RegMode,     OUT_REGMODE_IDLE,
             RunState,    OUT_RUNSTATE_IDLE,
             UpdateFlags, UF_UPDATE_MODE + UF_UPDATE_SPEED);
}


//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
task Claw_up() {
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
   CmdRdy=false;
   OUT_MSMux(RCXMMux_Port, OUT_Claw, 1024);
   Wait(1);
   while(!(SensorValue(S3))) {  // dn pos = S3
     OUT_MSMux(RCXMMux_Port, OUT_Claw, -100);
     Wait(1);
     if (SensorValue(S3)) {
        OUT_MSMux(RCXMMux_Port, OUT_Claw, 1024);
        Wait(50);
     }
  }
  OUT_MSMux(RCXMMux_Port, OUT_Claw, 0);
  CmdRdy=true;
  Wait(1);
}


//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
task Claw_md() {
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  char speed ;
  speed=100;
  CmdRdy=false;

  OUT_MSMux(RCXMMux_Port, OUT_Claw, 1024);
  Wait(1);
  while(!(SensorValue(S2))) {
      if(SensorValue(S1)) speed=-100;
      OUT_MSMux(RCXMMux_Port, OUT_Claw, speed);
      Wait(1);
      if (SensorValue(S2)) {  // dn pos = S1
        OUT_MSMux(RCXMMux_Port, OUT_Claw, 1024);
        speed=0;
        Wait(50);
      }
  }
  OUT_MSMux(RCXMMux_Port, OUT_Claw, 0);
  CmdRdy=true;
  Wait(1);
}

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
task Claw_dn() {
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  CmdRdy=false;
  OUT_MSMux(RCXMMux_Port, OUT_Claw, 1024);
  Wait(1);
  while(!(SensorValue(S1))) {
      OUT_MSMux(RCXMMux_Port, OUT_Claw, 100);
      Wait(1);
      if (SensorValue(S1)) {  // dn pos = S1
        MotorOff(OUT_Claw);
        Wait(50);
      }
  }
  OUT_MSMux(RCXMMux_Port, OUT_Claw, 0);
  CmdRdy=true;
  Wait(1);
}
I will have to try to run the 3 RCX1 motor tasks and the motor stop procedure at a remote-MS-mMux remote-controlled by rs485.
The master has to know at any time if remote-RCX1 is busy or idle.
Because all over 3 RCX motors are currently running via a MS RCX MMux at remote-S4, I will have to attach the sensors S1/2/3 to a remote HT touch mux at remote1-S1, remote1-S2 then will be needed for a pneumatic pressure sensor (currently at master-S4), the RCX mMux is switched to remote1-S3, and both master-S4 and remote1-S4 will be free for rs485 cable connection.

Then I will have to run the remote1-RCX2 and remote1-RCX3 motor tasks also attached to the remote1-MS-mMux via rs485.

The next step will be to pass an array char[129] plus about 8 extra char values from the master to 1 - 2 (-10 -20 -30) different slaves, start remote calculation tasks based on these arrays and extra values on all of them (while running the same calculations locally), and all return the calculation status (calc_busy or calc_finished) and, in case, remote results (int) to the master when finished. The master has to recognize when any has finished or may interrupt any remote calculations on demand.

I will report and start a new thread in case it's useful.

Looking forward to a more relaxed and more professional way of cooperation.
mattallen37
Posts: 1818
Joined: 02 Oct 2010, 02:19
Location: Michigan USA
Contact:

Re: can bricks be "linked"

Post by mattallen37 »

The header is five bytes long, and I think the RS485 buffers of the NXT are 128 bytes. 128 - 5 = 123, so 123 user bytes is probably the limit (per transmission).
Matt
http://mattallen37.wordpress.com/

I'm all for gun control... that's why I use both hands when shooting ;)
HaWe
Posts: 2500
Joined: 04 Nov 2014, 19:00

Re: can bricks be "linked"

Post by HaWe »

Actually 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.
I started a new thread about serial I/O remote control functions.
https://sourceforge.net/apps/phpbb/mind ... f=4&t=1723
Post Reply

Who is online

Users browsing this forum: Semrush [Bot] and 18 guests