Friday, 29 January 2016

Trying hard, eventually got R_PI to do something

So I thought, let's try a simple Python program on the R_PI. I know, build some traffic lights. I found a solution on the web, but getting it going was another matter.

1. I ran the desktop environment over VNC to my iMac, this means connecting by "ssh", running the server R_PI "vncserver :0" then starting the VNC Viewer program on my iMac pointing to "raspberrypi.local" and entering the password. (I had already installed the R_PI app "tightvncserver" to enable this... and the bonjour system to avoid the need to enter IP addresses)

2. On the desktop environment I opened Programming > Python3 and File >New

3. I typed in the code for the program:

#pin definitions
GPIO_SWITCH = 17
GPIO_RED = 22
GPIO_AMBER = 23
GPIO_GREEN = 24

# timings
TIME_CHANGE = 1
TIME_RED = 5
TIME_GREEN = 5

# libraries
import RPi.GPIO as GPIO
import time

# system settings
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)

# pin setups
GPIO.setup(GPIO_RED, GPIO.OUT)
GPIO.setup(GPIO_AMBER, GPIO.OUT)
GPIO.setup(GPIO_GREEN, GPIO.OUT)
GPIO.setup(GPIO_SWITCH, GPIO.IN, pull_up_down=GPIO.PUD_UP)

# initial state
GPIO.output(GPIO_RED, True)
GPIO.output(GPIO_AMBER, False)
GPIO.output(GPIO_GREEN, False)

# loop
while 1:
        time.sleep(TIME_RED)

        GPIO.output(GPIO_AMBER, True)

        time.sleep(TIME_CHANGE)

        GPIO.output(GPIO_RED, False)
        GPIO.output(GPIO_AMBER, False)
        GPIO.output(GPIO_GREEN, True)

        while GPIO.input(GPIO_SWITCH):
                time.sleep(0.25)

        GPIO.output(GPIO_AMBER, True)
        GPIO.output(GPIO_GREEN, False)

        time.sleep(TIME_CHANGE)

        GPIO.output(GPIO_RED, True)
        GPIO.output(GPIO_AMBER, False)
and saved it as "traffic.py" in my "PGM" folder.

4. I then chose Run from the Python menu, PROBLEM! The GPIO stuff can only access the board pins if run as super user. So you can't run the program from the desktop python environment!!! How stupid can you get??? Or maybe no one has explained this to me yet... the documentation for the R_PI is a disaster...

5. So I closed the desktop python3 environment and connected to the R_PI from my Terminal program on the iMac and changed to the folder where I keep my programs "PGM", the program is called "traffic.py".
ssh pi@raspberrypi.local
pi@raspberrypi ~  $
pi@raspberrypi ~  $ cd PGM
pi@raspberrypi ~/PGM  $
Now I ran the program with
pi@raspberrypi ~/PGM  $ sudo python3 traffic.py
and off we go. it works. It also works fine if I start it the same way from a terminal window on the R_PI desktop (using LXTerminal).

6 BUT WHAT STUPIDITY that you cannot run the RPi.GPIO program from the desktop Python3 IDE!!!

Saturday, 2 January 2016

Back to Arduino Robots

I have been looking to make a very low cost robot car, you know the type that wanders about, but avoids walls and objects in its way.

As a basis I chose an Arduino Uno from dx.com. This kit can be used for experiments with its breadboard, but this won't be used for the robot. Then I added a mounting board from Amazon.

Next I added these parts:

- Small Motor Drive shield
- Two Motors and wheels

- A caster bearing for the front

- A set of IR detectors (3 of the 5 used)

- Double side sticky pads

Lastly I bought a battery holder for 5 AA cells - to give a supply of 7.5V. This powers the motors shield and the Arduino Uno via the Vin connection.

Altogether this is what is needed to make an obstacle detecting robot, the cost is about £30 + p&p. The Arduino Uno is fixed onto the mounting Platform. The motors and detectors are fixed to the bottom and top of the platform using the sticky pads. The detectors face forwards and left and right at the front of the platform.

The Motor drive shield is plugged in to the Arduino Uno and connected to the motors, the IR detectors are wired to 5V and GND and the inputs to pins 11, 12, 13 of the Arduino.

The code for the robot is below, it will need tuning for your robot, to get the speed right and the delays to getit to turn at the right angle. You can also change the wander direction change setting.:

// OliverRobot. Wanders about, reacts if detects obstacle
// IR detectors at L, F & R. Two motors M1 (L) & M2 (R)

// =====================================================
// IR detector inputs
#define LDET 11
#define FDET 12
#define RDET 13

// DRV8835 Dual Motor Driver shield
#define M1DIR 7
#define M1PWM 9
#define M2DIR 8
#define M2PWM 10

// directions
#define FWD 1
#define REV 2
#define LEFT 3
#define RIGHT 4


// time to next wander direction change
#define WTIME 1000

// wander times
unsigned long wt, prevwt;

// =====================================================
void setup() {
  pinMode(LDET, INPUT); // IR detectors
  pinMode(FDET, INPUT);
  pinMode(RDET, INPUT);
  pinMode(M1DIR, OUTPUT); // motor direction
  pinMode(M2DIR, OUTPUT);
}

// =====================================================
// d = dir, s = speed, t = time
void loop() {
  switch(event()) {
    
    case 1: // right a bit
      action(RIGHT, 50); // right (d, s)
      delay(200); // (t)
      break;
      
    case 2:  // left a bit
      action(LEFT, 50); // left (d, s)
      delay(200); // (t)
      break;
      
    case 3:  // forward slow
      action(FWD, 30); // fwd (d, s)
      break;
      
    case 4:  // stop, back a bit, random L or R
      action(FWD, 0); // stop (d, s)
      delay(500);
      action(REV, 20); // rev (d, s)
      delay(500);
      if(random(0,2)) {
        action(LEFT, 50); // left a bit (d, s)
        delay(200); // (t)
      }
      else {
        action(RIGHT, 50); // right a bit (d, s)
        delay(200); // (t)
      }
      break;
      
    case 5:  // right 90deg
        action(RIGHT, 50); // right (d, s)
        delay(400); // (t)
      break;
      
    case 6:  // left 90 deg (s, t)
        action(LEFT, 50); // left (d, s)
        delay(400); // (t)
      break;
      
    case 7:  // stuck, 180deg spin R on the spot
      action(RIGHT, 30); // right (d, s)
      delay(800); // (t)
      break;
      
    default: // wander forewards
      wander(50); // (s)
      break;
  }
  delay(50); // loop stablise ?needed?
}

// =====================================================
// Event map
// L   F   R
//     4
//  5  7  6
// 1   3   2

// get event, none = 0
byte event(){
  byte event;
  
  event = 0;
  if(digitalRead(LDET)) event += 1;
  if(digitalRead(FDET)) event += 4;
  if(digitalRead(RDET)) event += 2;

  return event;
}

// action dir d, speed s
void action(byte d, byte s) {
  switch(d) {
    
    case 1: // FWD
      digitalWrite(M1DIR, HIGH);
      digitalWrite(M2DIR, HIGH);
      break;
      
    case 2: // REV
      digitalWrite(M1DIR, LOW);
      digitalWrite(M2DIR, LOW);
      break;
      
    case 3: // LEFT
      digitalWrite(M1DIR, HIGH);
      digitalWrite(M2DIR, LOW);
      break;
      
    case 4: // RIGHT
      digitalWrite(M1DIR, LOW);
      digitalWrite(M2DIR, HIGH);
      break;
  }
  // speed
  analogWrite(M1DIR, s);
  analogWrite(M2DIR, s);
}

void wander(byte s) {
  action(FWD, 50);
  wt = millis();
  if(wt > prevwt + WTIME) {
    if(random(0, 2)) {
      action(LEFT, 50); // left (d, s)
      delay(200); // (t)
    }
    else {
      action(RIGHT, 50);
      delay(200);
    }
  }
  prevwt = wt;
}