Kate's Comment

Thoughts on British ICT, energy & environment, cloud computing and security from Memset's MD

Using HiTechnic sensor multiplexer in NXC

BOB NXT with new sensors awaiting install In order to give BOB all the capabilities I need more than the 4 standard sensor inputs. To that end I ordered two HiTechnic sensor multiplexers, one powered one (the one in front of him in the picture) which can do any sensor and one for just touch sensors (the one connected in the picture, distinguished by a lack of a battery).

Adding touch to the any-sensor multiplexer

I found a NXC driver for the multiplexer by Xaander Soldaat which was a Godsend – I’d ben dreading having to write one myself after reading some of the documentation.

I found a couple of minor issues with Xander’s driver (see comment on his site) but the light sensor one needs more investigation since based on his replies thus far I think it may not actually be supported at all. I did write a touch sensor handler to work with the full multiplexer, which Xander has incorporated into version 0.5 of the driver. 🙂 That code is below:

bool smuxReadSensorLegoTouch(const byte muxport)
  if ( HTSMUXreadAnalogue(muxport) < TOUCH_SENSOR_THRESHOLD )     return TRUE;   else     return FALSE; }

Debugging the touch sensor multiplexer

However, after writing that I remember that I had bought two multiplexers and that one was touch-only! *facepalm* With it came a code snippet from HiTechnic, but it did not work at first. I accidentally discovered the first issue; you need to set the port to be a touch sensor, for example:


I had assumed that one would set it to be a raw sensor input! The supplied code still didn’t work so I set about reading the raw values. On investigation using the setup you can see in the picture (the touch sensor multiplexer connected to input 1 and four touch sensors connected into that) and some code to output the values to BOB’s screen I discovered that the values being returned by the device were not-quite binary multiples:

B1 pressed: 24-29
B2 pressed: 55-56
B3 pressed: 106-109
B4 pressed: 194-195

That looked “close enough”, and indeed they appeared to be being added together when multiple buttons were pressed, however when I pressed all four buttons I got 310-313, whereas the minimum sum of the above is about 380! This presents something of a problem, but I have written a function that works in most situations I want:

// Read the HiTechnic touch sensor multiplexer (different to the any-sensor smux)
// The code snippet supplied did not work when tested for two reasins:
// 1) You must use SetSensorTouch() on the appropriate port first
// 2) The values returned are no-quite binary
// This function takes the port the touch smux is connected to and a pointer to a 4-long bool array
// It returns TRUE if any sensor was active and sets each, FALSE if none are set
// NOTE: The readings are unreliable if switches 3 & 4 are pressed simultaneously & code may require calibration!
// For more information please see http://v.gd/OpukAf

bool readTouchesSmux( const byte port, byte &switches[] )
  ArrayInit( switches, 0, 4 );
  int powers[4] = {1,2,4,8};
  float value = 1023 – SensorRaw(port);
  bool pressed = FALSE;

  value *= 256;
  value /= 192; // correct for approximate error
  value += 16; // to ensure rounding-up
  value /= 32; // convert to binary value
  int ival = value; // Cast to an int and hopefully will be about right

  for ( int i=0; i<4; i++ )     {       if ( ival & powers[i] )         {           pressed = TRUE;           switches[i] = TRUE;         }       }     }   return pressed; }

Unfortunately the error from buttons 3 & 4 when combined with other buttons means that some a few multiple-button-pressed states unreliable. Any combination of buttons 1+2+3 is okay, and combinations of buttons 1+2+4, but if 3 & 4 are pressed together the results become unreliable. To counter this I have used 3 & 4 for BOB’s rear sensors which I do not expect to ever be pressed at the same time.

Bugged hardware – may need to calibrate

The unit is clearly defective so I shall ask HiTechnic about that but I suspect that they are all like that so hopefully this will help others with similar units. I played around with the pictured setup to get the best correction value (256/192). One could do a cruder system with a list of value ranges which would work in all cases probably but that was too inelegant for my tastes and it may well be that the ranges vary depending on the individual smux.

Their suggested code for the conversion is shown below. The fact that they have taken a not-dissimilar approach to mine and it has some “fine tuning” in it suggests that there is variance between bricks – if I plug in the code below using my touch smux then it works for some cases but not for most!

int ival;
ival = 339 * value;
ival /= 1023-value;
ival += 5;
ival /= 10;

If you plan to use a similar setup to mine and want to be able to read multiple sensors that may be pressed together I suggest that you calibrate your own setup by adjusting the “192” a little to find the value that works best with your particular touch smux.

Update: RTFMS!

After Xander’s helpful pointer I found the ReadSensorHTTouchMultiplexer() NXT function, which was online but not in the PDF version I had downloaded for local reference.

That function works perfectly. Given my struggles I expect it uses an internal lookup table for ranges rather than bitwise operators. My function above can be simply rewritten thus:

// Read the HiTechnic touch sensor multiplexer into a supplied array
// Returns TRUE if any button was pressed

bool readTouchesSmux( const byte port, byte &switches[] )
  ArrayInit( switches, 0, 4 );
  int t0,t1,t2,t3;

  ReadSensorHTTouchMultiplexer(port, t0, t1, t2, t3 );
  switches[0] = t0; switches[1] = t1; switches[2] = t2; switches[3] = t3;

  return ( t0 || t1 || t2 || t3 );

It was an interesting reminder of bitwise operations regardless!

Some of you may note that I should have been able to do without the local instantiation of variables (t*), or failing that done it more elegantly with a local array and a for loop. However, NXC is indeed “not exactly C” and you cannot pass pointers to individual array elements between arrays, only pointers to whole data objects (array, integer etc).