Difference between revisions of "Talk:Cheesoid"

From Nottinghack Wiki
Jump to navigation Jump to search
Line 221: Line 221:
 
This sketch is a munge of http://letsmakerobots.com/node/2074 and http://itp.nyu.edu/physcomp/Labs/DCMotorControl
 
This sketch is a munge of http://letsmakerobots.com/node/2074 and http://itp.nyu.edu/physcomp/Labs/DCMotorControl
  
OK, I now have the motors mounted and coupled to the wheel assemblies but the whole thing is way too weak to drive the wheels when using the big 12v lead-acid batteries I have. It's a little better with the bench power supply at 12v and it's how I'd want it with the bench supply at 14v. I think there's multiple problems here: the wheel assemblies are heavy and the shed-built motor brackets are inaccurate, as are the polymorph couplings (an idea borrowed from here http://letsmakerobots.com/node/15354). I've joined the letsmakerobots.com forum and I'm going to ask some advice there.
+
OK, after a couple of nights at Hackspace I now have the motors mounted and coupled to the wheel assemblies but the whole thing is way too weak to drive the wheels when using the big 12v lead-acid batteries I have. It's a little better with the bench power supply at 12v and it's how I'd want it with the bench supply at 14v. I think there's multiple problems here: the wheel assemblies are heavy and the shed-built motor brackets are inaccurate, as are the polymorph couplings (an idea borrowed from here http://letsmakerobots.com/node/15354). I thought that the wheel assembly would be necessary to take some of the load off the motor axles but I see quite a lot of setups with the wheels attached directly to the motors as in this example that also uses 38mm motors: http://www.pololu.com/catalog/product/730
 +
 
 +
I'm tempted to redesign around some direct wheel couplings and purchased wheels even though I love the CD wheel idea.
 +
* http://www.active-robots.com/2-x-universal-hub-6mm-shaft.html
 +
* http://www.skpang.co.uk/catalog/pololu-universal-aluminum-mounting-hub-for-6mm-shaft-pair-p-800.html
 +
 
 +
I've joined the letsmakerobots.com forum and I'm going to ask some advice there.
  
 
--[[User:Msemtd|Michael Erskine]] 09:18, 8 October 2011 (EST)
 
--[[User:Msemtd|Michael Erskine]] 09:18, 8 October 2011 (EST)

Revision as of 15:28, 8 October 2011

Interaction Goals

Cheesoid is intended to be a fully autonomous mobile robot that interacts with people and objects in its environment. Human-Robot interaction is a massive subject but I intend to get some rudimentary (and comedic) speech and general input features in place as soon as possible. The environment interactions will develop as I learn more about sensing and mapping. Since the robot will live at Hackspace I have two basic goals for comedy value: -

  • interact with the fridge for cheese status
  • interact with the petrol pump for petrol status

So...

  • it needs to know where they are to go and talk to them
  • the status needs to be stored and needs to be set - Xino at each? Via IRC bot? Some web interface?
  • it need to be able to read the status from the fridge and the petrol pump - what sort of interface? IR remote control?

Petrol status

  • just a number!

Cheese status

  • many cheese types - each with use by date
  • Primula status is "in tube"

Human - Robot Interactions: speech

With the eeePC I have a very capable processor on board and I'm taking full advantage of that: -

  • using espeak for text to speech
  • using sphinx for speech recognition

Text to Speech with espeak

http://espeak.sourceforge.net/

The espeak voices aren't really robotic enough but can be made more so by creating a custom voice

speech recognition with sphinx

http://cmusphinx.sourceforge.net/wiki/tutorialconcepts

The sphinx packages

p    --\ sphinx2-bin                                                                                                                    <none>     0.6-2.1
  Description: speech recognition utilities
    Sphinx 2 is a real-time, speaker-independent speech recognition system.

    This package contains examples and utilities that use Sphinx. It also includes a sample language model that is capable of recognizing simple commands
    like "go forward ten meters" and other commands one might use to tell a robot where to move.
  Priority: optional
  Section: universe/sound
  Maintainer: Ubuntu MOTU Developers <ubuntu-motu@lists.ubuntu.com>
  Compressed size: 129k
  Uncompressed size: 500k
  Source Package: sphinx2
  --\ Depends (3)
    --- libc6 (>= 2.4)
    --- libsphinx2g0 (>= 0.6) (UNSATISFIED)
    --- sphinx2-hmm-6k (UNSATISFIED)
  --\ Packages which depend on sphinx2-bin (0)
  --\ Versions of sphinx2-bin (1)
p    0.6-2.1

Good examples of the use of sphinx: -

Conversations and dialogue

In order to have a meaningful (preferably amusing and slightly uncanny) interaction with humans there needs to be a dialogue and some involvement of non-verbal communications: perhaps some shared experience, empathy, etc. We can fake a lot of things to push the human participant closer to the goal!

Mobility

  • motors
  • wheels
  • chassis
  • motor power
  • motor control circuitry
  • big battery

Drive motors: I now have my 12V 150RPM gearmotors from China


OK, motors tested with a two motor circuit...

Motor Test sketch (non-PWM)

  1 int motor_left[] = {
  2   2, 3};
  3 int motor_right[] = {
  4   7, 8};
  5 const int ledPin = 13;      // LED 
  6 const int switchPin = 10;    // switch input
  7 const int enablePin = 9;    // H-bridge enable pin
  8 
  9 
 10 // ————————————————————————— Setup
 11 void setup() {
 12   Serial.begin(9600);
 13   pinMode(ledPin, OUTPUT);
 14   pinMode(switchPin, INPUT); 
 15   pinMode(enablePin, OUTPUT);
 16 
 17 
 18   // Setup motors
 19   int i;
 20   for(i = 0; i < 2; i++){
 21     pinMode(motor_left[i], OUTPUT);
 22     pinMode(motor_right[i], OUTPUT);
 23   }
 24   check_enable();
 25   // blink the LED 3 times. This should happen only once.
 26   // if you see the LED blink three times, it means that the module
 27   // reset itself,. probably because the motor caused a brownout
 28   // or a short.
 29   blink(ledPin, 3, 100);
 30 
 31 }
 32 
 33 
 34 void check_enable(){
 35   digitalWrite(enablePin, digitalRead(switchPin));
 36 }
 37 // ————————————————————————— Loop
 38 void loop() {
 39 
 40   drive_forward();
 41   delay(1000);
 42   motor_stop();
 43   Serial.println("1");
 44 
 45   drive_backward();
 46   delay(1000);
 47   motor_stop();
 48   Serial.println("2");
 49 
 50   turn_left();
 51   delay(1000);
 52   motor_stop();
 53   Serial.println("3");
 54 
 55   turn_right();
 56   delay(1000);
 57   motor_stop();
 58   Serial.println("4");
 59 
 60   motor_stop();
 61   delay(1000);
 62   motor_stop();
 63   Serial.println("5");
 64 }
 65 
 66 // ————————————————————————— Drive
 67 
 68 void motor_stop(){
 69   check_enable();
 70   digitalWrite(motor_left[0], LOW);
 71   digitalWrite(motor_left[1], LOW);
 72 
 73   digitalWrite(motor_right[0], LOW);
 74   digitalWrite(motor_right[1], LOW);
 75   delay(25);
 76 }
 77 
 78 void drive_forward(){
 79   check_enable();
 80   digitalWrite(motor_left[0], HIGH);
 81   digitalWrite(motor_left[1], LOW);
 82 
 83   digitalWrite(motor_right[0], HIGH);
 84   digitalWrite(motor_right[1], LOW);
 85 }
 86 
 87 void drive_backward(){
 88   check_enable();
 89   digitalWrite(motor_left[0], LOW);
 90   digitalWrite(motor_left[1], HIGH);
 91 
 92   digitalWrite(motor_right[0], LOW);
 93   digitalWrite(motor_right[1], HIGH);
 94 }
 95 
 96 void turn_left(){
 97   check_enable();
 98   digitalWrite(motor_left[0], LOW);
 99   digitalWrite(motor_left[1], HIGH);
100 
101   digitalWrite(motor_right[0], HIGH);
102   digitalWrite(motor_right[1], LOW);
103 }
104 
105 void turn_right(){
106   check_enable();
107   digitalWrite(motor_left[0], HIGH);
108   digitalWrite(motor_left[1], LOW);
109 
110   digitalWrite(motor_right[0], LOW);
111   digitalWrite(motor_right[1], HIGH);
112 }
113 
114 /*
115     blinks an LED
116  */
117 void blink(int whatPin, int howManyTimes, int milliSecs) {
118   int i = 0;
119   for ( i = 0; i < howManyTimes; i++) {
120     digitalWrite(whatPin, HIGH);
121     delay(milliSecs/2);
122     digitalWrite(whatPin, LOW);
123     delay(milliSecs/2);
124   }
125 }

This sketch is a munge of http://letsmakerobots.com/node/2074 and http://itp.nyu.edu/physcomp/Labs/DCMotorControl

OK, after a couple of nights at Hackspace I now have the motors mounted and coupled to the wheel assemblies but the whole thing is way too weak to drive the wheels when using the big 12v lead-acid batteries I have. It's a little better with the bench power supply at 12v and it's how I'd want it with the bench supply at 14v. I think there's multiple problems here: the wheel assemblies are heavy and the shed-built motor brackets are inaccurate, as are the polymorph couplings (an idea borrowed from here http://letsmakerobots.com/node/15354). I thought that the wheel assembly would be necessary to take some of the load off the motor axles but I see quite a lot of setups with the wheels attached directly to the motors as in this example that also uses 38mm motors: http://www.pololu.com/catalog/product/730

I'm tempted to redesign around some direct wheel couplings and purchased wheels even though I love the CD wheel idea.

I've joined the letsmakerobots.com forum and I'm going to ask some advice there.

--Michael Erskine 09:18, 8 October 2011 (EST)

MCU1 Motor Control

MCU1 will drive each motor via the SN754410 with three signals: Motor_Logic_1, Motor_Logic_2, and Motor_Enable (corresponding to the SN754410 pins). The Motor_Enable signals will be PWM thus using in total 2 PWM outputs plus 4 digital outputs. This allows a simple interface to the SN754410.

Control is via serial from the eeePC giving parameters of direction and speed for both motors at once. The motors can be put in hold with a stop command. The messages need to be quick for MCU1 to read and interpret but also easily human-readable.

 D[L-dir][L-speed][R-dir][R-speed]
 
 direction = 1 char, 'F' = forwards, 'B' = backwards, 'X' = hold
 speed = 3 ASCII decimal digits in range 000 to 255 left zero padded 

Examples: -

  • DF255F255 = full speed ahead
  • DF127F127 = half speed ahead
  • DF000F000 = freewheel?
  • DX000X000 = hold stop
  • DB255F255 = fast rotate left
  • DF255B255 = fast rotate right
  • DX000F255 = fast pivot left

The PWM will continue unless stopped so we should have a timeout on MCU1

Bodywork

  • battery regulation: http://letsmakerobots.com/node/3880
  • battery mounting - where?
    • chassis strong enough to carry those batteries? !!!!
    • aluminium cross bracing?
    • perhaps move to 2x 6V - keep it flexible
  • cylinder case mods
    • speakers in mouth plate/grill
    • side mount for MCU1 and support boards (temporary?)
    • top for beacon - keep on side for now
    • mounting of cylinder on chassis

Motor shaft couplings being the most annoying thing right now

  • I really need some well made couplings like these

Small hose clips may be the thing.

Brains

The current design makes use of a few processors: the small cheap eeePC 701 4G netbook and a couple of inexpensive (£7) Xino Arduino micros.

MCU1 and MCU2

Xino devices

MCU1 PIN usage summary table here on Google Docs

MCU1 software

  1 /*******************************************************************/
  2 /*                          CHEESOID MCU1                          */
  3 /*******************************************************************/
  4 
  5 // I/O Pin definitions...
  6 // The mode switch is on a digital input...
  7 const int PIN_MODESW = 4;
  8 // Two LEDs are used for eyes on two digital pins...
  9 const int PIN_EYE1 = 7;
 10 const int PIN_EYE2 = 8;
 11 // Built-in LED on pin 13 used for watchdog status...
 12 const int PIN_WDLED = 13;
 13 // Motor enable/speed PWM outputs...
 14 const int PIN_M1SPD = 9;
 15 const int PIN_M2SPD = 10;
 16 // Motor control logic digital outputs...
 17 const int PIN_M1C1 = 14;
 18 const int PIN_M1C2 = 15;
 19 const int PIN_M2C1 = 16;
 20 const int PIN_M2C2 = 17;
 21 // Bumper inputs...
 22 const int PIN_BMP1 = 18;
 23 const int PIN_BMP2 = 19;
 24 // Soft serial to MCU2...
 25 const int PIN_MCU2TX = 11;
 26 
 27 
 28 // Last watchdog time tracking...
 29 unsigned long wdoglast = 0;
 30 // main loop has 10ms sleeps...
 31 const int naptime = 10;
 32 // the eyes flash every 60 loops = 600ms...
 33 int eyefreq = 60;
 34 // info is sent out on the serial port every 90 loops = 900ms...
 35 int reportfreq = 90;
 36 // a simple loop counter is used to decide what to do...
 37 unsigned int loopcounter = 0;
 38 // mode switch state...
 39 int mode = 0;
 40 
 41 // System counters...
 42 // Max number of bytes read in one go...
 43 #define CTR_MAXREAD 0
 44 // number of buffer overflows avoided...
 45 #define CTR_OVERFLOW 1
 46 // Number of bytes received...
 47 #define CTR_BYTES 2
 48 // Number of unknown message commands...
 49 #define CTR_UNKMSG 3
 50 // Number of unknown message commands...
 51 #define CTR_WDOGTO 4
 52 static int counters[4];
 53 // watchdog timout in millis...
 54 #define WDOG_TIMEOUT (long)7000
 55 // size of our incoming message buffer...
 56 #define MAXMSG 50
 57 
 58 void setup() {
 59   Serial.begin(9600);
 60   pinMode(PIN_MODESW, INPUT);
 61   pinMode(PIN_EYE2, OUTPUT);
 62   pinMode(PIN_EYE1, OUTPUT);
 63   pinMode(PIN_WDLED, OUTPUT);
 64   //
 65   pinMode(PIN_M1SPD, OUTPUT);
 66   pinMode(PIN_M2SPD, OUTPUT);
 67   pinMode(PIN_M1C1, OUTPUT);
 68   pinMode(PIN_M1C2, OUTPUT);
 69   pinMode(PIN_M2C1, OUTPUT);
 70   pinMode(PIN_M2C2, OUTPUT);
 71   // TODO soft serial link to MCU2
 72   pinMode(PIN_MCU2TX, OUTPUT);
 73   //
 74   pinMode(PIN_BMP1, INPUT);
 75   pinMode(PIN_BMP2, INPUT);
 76     
 77   // announce startup...
 78   flasheyes(200);
 79   Serial.println("\n=== CHEESOID ===");
 80   // TODO: piezo buzzer to play a tune
 81   mode = digitalRead(PIN_MODESW);
 82 }
 83 
 84 void flasheyes(int zeds) {
 85   for(int i=0;i<6;i++){
 86     int onoff = i % 2;
 87     digitalWrite(PIN_EYE2, onoff);
 88     digitalWrite(PIN_EYE1, onoff);
 89     delay(zeds);
 90   }
 91 }
 92 
 93 void loop() {
 94   static int act;
 95   do_switch();
 96   do_eyes();
 97   act = do_report();
 98   act += do_serialinput();
 99   if(!act)
100     delay(naptime);
101   loopcounter++;
102 }
103 
104 void do_switch() {
105   // button debounce: state must remain stable for N samples.
106   // This is just a lightweight debouncer
107   // used if we want to avoid the more general purpose 
108   // but heavyweight Bounce library.
109 
110   const int debouncesamples = 5;
111   static int lastsample = 0;
112   static int steadycount = 0;
113   static int debounced = 0;
114   // if the value is steady for 
115   int sample = digitalRead(PIN_MODESW);
116   // a change of value - restart the steady count...
117   if(sample != lastsample){
118     lastsample = sample;
119     steadycount = 0;
120     return;
121   }
122   steadycount++;
123   if(steadycount < debouncesamples)
124     return;
125   steadycount = debouncesamples;
126   debounced = sample;
127   // set the actual mode switch value
128   mode = debounced;
129 }
130 
131 void do_eyes() {
132   static int eyestate = 0;
133   if(loopcounter % eyefreq != 0)
134     return;
135   eyestate = !eyestate;
136   digitalWrite(PIN_EYE2, eyestate);
137   digitalWrite(PIN_EYE1, !eyestate);
138 }
139 
140 int do_report() {
141   if(loopcounter % reportfreq != 0)
142     return 0;
143   Serial.print("CHEESOID: mode = ");
144   Serial.print(mode);
145   //~ Serial.print(" | eye = ");
146   //~ Serial.print(onoff);
147   Serial.print(" | loop = ");
148   Serial.println(loopcounter);
149 
150   // also timeout the watchdog if set...
151   // this activity is limited by the reportfreq
152   if(wdoglast != 0){
153     long now = millis();
154     if(now - wdoglast > WDOG_TIMEOUT){
155       digitalWrite(PIN_WDLED, LOW);
156       counters[CTR_WDOGTO]++;
157       wdoglast = 0;
158     }
159   }
160   return 100;
161 }
162 
163 int do_serialinput() {
164   // can we avoid buffer overflows when using the 
165   // standard serial library at a 10ms read rate at 9600 baud?
166   // Well, 9600 8-n-1 is 960 bytes per sec or 9.6 per 10ms
167   // The standard serial receive buffer holds 128 bytes so we're fine
168   // already nulled by compiler - we leave the final char alone!
169   static char msgbuf[MAXMSG+2];
170   static int len = 0;
171   // any data waiting?
172   int ba = Serial.available();
173   if(!ba)
174     return 0;
175   if(ba > counters[CTR_MAXREAD])
176     counters[CTR_MAXREAD] = ba;
177   for(int i = 0; i < ba; i++){
178     int c = Serial.read();
179     Serial.print("GOT:");
180     Serial.println(c, DEC);
181     // upon LF, process message...
182     if(c == 0x0A){
183       // NB: ignore incoming char - now looking at the buffer...
184       c = msgbuf[0];
185       if(c == 'E'){
186         flasheyes(50);
187         Serial.println("I OBEY: FLASH EYES!");
188         len = 0; // reset message
189         continue; // ignore rest of message!
190       }
191       // watchdog kick - proof that PC is alive
192       if(c == 'W'){
193         // LED on for a while (needs timeout)
194         // lastkick var
195         Serial.println("Watchdog!");
196         digitalWrite(PIN_WDLED, HIGH);
197         wdoglast = millis();
198         len = 0; // reset message
199         continue; // ignore rest of message!
200       }
201       // Drive command...
202       if(c == 'D'){
203         DriveInterpret(msgbuf, len);
204         len = 0; // reset message
205         continue;
206       }
207       // Test commands...
208       if(c == 'T'){
209         int testmode = msgbuf[1];
210         if(testmode == 'D') {
211             TestMotors();
212             len = 0;
213             continue;
214         }
215         len = 0; // reset message
216         continue;
217       }
218       counters[CTR_UNKMSG]++;
219       continue;
220     }
221     // check for and avoid overflow...
222     if(len > MAXMSG){
223       counters[CTR_OVERFLOW]++;
224       len = 0; // reset message
225       continue;
226     }
227     // add msg to end of buffer and carry on...
228     msgbuf[len] = c;
229     len++;
230     // null terminate for debugging - OK to do if buffer len is MAXMSG+2!
231     msgbuf[len] = '\0';
232   }
233   return ba;
234 }
235 
236 /*******************************************************************/
237 /*                  Motor drive control messages                   */
238 /*******************************************************************/
239 // 
240 //~ D[L-dir][L-speed][R-dir][R-speed]
241 //
242 //~ direction = 1 char, 'F' = forwards, 'B' = backwards, 'X' = hold
243 //~ speed = 3 ASCII decimal digits in range 000 to 255 left zero padded 
244 // 
245 // Each message is 9 chars long.
246 //
247 //~ Examples: -
248 //~ DF255F255 = full speed ahead
249 //~ DF127F127 = half speed ahead
250 //~ DF000F000 = freewheel?
251 //~ DX000X000 = hold stop
252 //~ DB255F255 = fast rotate left
253 //~ DF255B255 = fast rotate right
254 //~ DX000F255 = fast pivot left
255 //~ The PWM will continue unless stopped so we should have a timeout on MCU1
256 /*******************************************************************/
257 void DriveInterpret(const char* msg, int len)
258 {
259   int pwm1, pwm2, motor1_c1, motor1_c2, motor2_c1, motor2_c2;
260   // Validate input
261   if(msg == 0 || len < 9)
262       return;
263   pwm1 = ((msg[2]-'0')*100) + ((msg[3]-'0')*10) + (msg[4]-'0');
264   pwm2 = ((msg[6]-'0')*100) + ((msg[7]-'0')*10) + (msg[8]-'0');
265   // the motor directions are rather arbitrary as they 
266   // can be easily wired as necessary
267   if(msg[1] == 'F'){
268     motor1_c1 = HIGH;
269     motor1_c2 = LOW;
270   } else if(msg[1] == 'B'){
271     motor1_c1 = LOW;
272     motor1_c2 = HIGH;
273   } else { // default to hold
274     motor1_c1 = LOW;
275     motor1_c2 = LOW;
276   }
277   if(msg[5] == 'F'){
278     motor1_c1 = HIGH;
279     motor1_c2 = LOW;
280   } else if(msg[5] == 'B'){
281     motor1_c1 = LOW;
282     motor1_c2 = HIGH;
283   } else { // default to hold
284     motor1_c1 = LOW;
285     motor1_c2 = LOW;
286   }
287   DriveMotors(motor1_c1, motor1_c2, pwm1, motor2_c1, motor2_c2, pwm2);
288 }
289 
290 void DriveMotors(int motor1_c1, int motor1_c2, int pwm1, 
291     int motor2_c1, int motor2_c2, int pwm2)
292 {
293     // TODO timeout and bumpers!
294     digitalWrite(PIN_M1C1, motor1_c1);
295     digitalWrite(PIN_M1C2, motor1_c2);
296     analogWrite(PIN_M1SPD, pwm1);
297     digitalWrite(PIN_M2C1, motor2_c1);
298     digitalWrite(PIN_M2C2, motor2_c2);
299     analogWrite(PIN_M2SPD, pwm2);
300 }
301 
302 // TODO Test motors forever!
303 void TestMotors()
304 {
305     
306     
307 }


MCU2 software

  • drives LCD display
  • needs serial in from MCU1
  • status LED to panel

eeePC mods

Hardware and system mods to support "isolated usage".

  • soldered in an external power button cable
    • PWR button sub-assembly with safety keyswitch - mount on side panel
    • TODO LED in "Micro" and other nice illuminated buttons
    • Monostable/bistable startup flasher circuit for "Micro" switch?
  • "pizza box" container
    • power port extension
    • USB extension - USB hub - still powering MCU1 from USB - much drain?
#!/bin/sh
LID_STATE=`cat /proc/acpi/button/lid/LID/state | awk '{print $2 }'`

if [ $LID_STATE = "closed" ] ; then
#    /etc/acpi/suspend2ram.sh
        /bin/su user -c "/usr/bin/xrandr --output VGA --mode 800x600 --output LVDS --off"
fi
if [ $LID_STATE = "open" ] ; then
        /bin/su user -c "/usr/bin/xrandr --output LVDS --preferred --output VGA --off"
fi
exit 0

This is not enough: the eeePC will not power on with the lid closed so I had to disable the lid closed sensor by removing the magnet from screen section of the case

# minimal brightness
echo 0 > /sys/devices/platform/eeepc/backlight/eeepc/brightness"
# screen off after 2 minutes
xset dpms 0 0 120

eeePC problems

  • unionfs inode depletion causing "No space left on device" but df shows plenty of space!
  • running out of space due to other errors ~/.Xsession-errors
  • firefox won't start - oh well!

eeePC Software

  • console read and process
  • speech module
    • speech commands from stdin
    • speech thread - busy flag and job queue management
  • motor module
    • motor control input from STDIN
  • sensor module
    • camera module - look at Java interaction with V4L or whatever is in use
    • mic input - and speech recognition
    • GUI interface port and GUI app

One annoyance is having to open the eeePC to find out its IP address to get back in via SSH. My proposed solution is to display the eeePC wlan IP address on the LCD on MCU2.

Get IP address to report on LCD

 1 package com.tecspy.util;
 2 
 3 import java.net.Inet6Address;
 4 import java.net.InetAddress;
 5 import java.net.NetworkInterface;
 6 import java.net.SocketException;
 7 import java.net.UnknownHostException;
 8 import java.util.Enumeration;
 9 
10 import org.apache.log4j.BasicConfigurator;
11 import org.apache.log4j.Logger;
12 
13 public class NetUtils {
14     static Logger log = Logger.getLogger(NetUtils.class);
15     
16     public static String getIps() {
17         
18         StringBuilder buf = new StringBuilder();
19         char div = '|';
20         
21         try {
22             InetAddress localHost = InetAddress.getLocalHost();
23             NetworkInterface ni = NetworkInterface.getByInetAddress(localHost);
24             Enumeration<InetAddress> ia = ni.getInetAddresses();
25             while (ia.hasMoreElements()) {
26                 InetAddress el = ia.nextElement();
27                 buf.append(div);
28                 if (el instanceof Inet6Address) {
29                     buf.append("IPv6:");
30                 } else {
31                     buf.append("IPv4:");
32                 }
33                 buf.append(" hostname:");
34                 buf.append(el.getCanonicalHostName());
35                 buf.append(" address:");
36                 buf.append(el.getHostAddress());
37             }
38         } catch (NullPointerException e) {
39             log.error("Error: " + e.getMessage(), e);
40         } catch (SocketException e) {
41             log.error("Error: " + e.getMessage(), e);
42         } catch (UnknownHostException e) {
43             log.error("Error: " + e.getMessage(), e);
44         }
45         return buf.substring(1);
46     }
47     
48     /**
49      * @param args
50      */
51     public static void main(String[] args) {
52         BasicConfigurator.configure();
53         String ips = getIps();
54         log.info(ips);
55         
56     }
57     
58 }

Additional

Range Sensors

Rotary Encoders for wheels

  • an easily available "obsolete" ball type PS/2 mouse
  • Microsoft "Mouse Port Compatible Mouse 2.0A"
  • using the serial output from the mouse circuitry
  • encoder usage in daylight
  • mounting encoder wheel to axle