Roombaduino – part 14 – Working OLED

The code that I had working on the attiny85 for the OLED didn’t want to work on the ATmega328P even though I made sure that the new pins I’d soldered were fully connected and could light LEDs when sent high.

So, I did some internet searching and found http://blog.oscarliang.net/arduino-oled-display-library/ which does the trick. The Adafruit library seems to be jam-packed with everything and the Arduino IDE complains that there’s a shortage of memory when it’s compiled so any chance to decrease the memory footprint is a good thing. The fact that this OzOled library works is the reason I’m using it. One thing I did notice is that it seems to start the display upside down when compared to the Adafruit and ssd1306 library. I’ll dig into that to see if there’s a simple logic change I can make.

Here’s the obligatory video of the OLED screen working:

 

 

Roombaduino – part 13 – Full Remote Control

With the Roombaduino circuit soldered together, it was time to test the remote control. I found a connection to the left joystick button that had come undone so I re-soldered that. I also move the Roombaduino LED pin and DD connection to different pins on the Nerduino so that I could use the I2C pins for the OLED display at a later time.

With that all done, the software needed some tweaking to allow a joystick button to switch between Passive and Full mode on the Roomba to give me a chance to turn the Roomba off if necessary. Also, the main brush and side brush on the Roomba needed to operate so the other joystick button toggled their movement.

Some improvements to the software, needing some new push buttons on the remote control, will be to allow single-use buttons for each of the functions that are currently being toggled by the joystick buttons. Also, the joystick direction commands should allow the combination of forward + (left or right) and backward + (left or right).

Roombaduino – part 12 – Display

I decided that I needed more visual feedback from the Roombaduino so I can obtain sensor information and display voltage and mode data.
A while ago, I bought a small 128×64 OLED screen from Amazon ( http://www.amazon.com/gp/product/B00O2LLT30) that uses just 4 pins ( 2 for VCC/GND and 2 for I2C [ SDA/SCL ] ). As I’m using the SPI pins for the wireless transceiver and things have been known not to play well with a shared SPI bus, using I2C from the Nerduino seems like a good idea.

Roombaduino – part 11 – Wireless Shield

After proving that the breadboarded circuit worked as expected, I charged up the Roomba battery and soldered up the Roombaduino circuit.
This time, I was using double-sided perfboard which has its pros and cons ( for me ).
The pros are that the perfboard is better quality than the paper single-sided board and that the pads are less likely to melt and detach when I solder.
The con ( for me ) is that because the pads are double-sided, the solder flows through to the other side. So, if I’m not soldering a component and I want to lay down a power rail, the solder forms in a bump on the other side of where I’m soldering the rail.
I’m sure other people are perfectly happy with it but it doesn’t work for me so I’m going back to single-sided.

I soldered up 3 parts to the circuit.
Firstly, the connection from the Roomba to the circuit through a 5v power regulator. This allows the Nerduino to be powered from the Roomba without needing a separate power input.
Secondly, the 5v to 3.3v power regulator to provide power to the wireless transceiver.
Thirdly, the connection from the Nerduino to the wireless transceiver using the SPI pins.

While the circuit looks compact on the front, I’m still not happy with my wiring ( but I don’t want to take it apart again – maybe in the future ). I need to be more methodical about how I wire stuff to make it more tidy.

What I *am* pleased about is the shield-like design so that the connection to the Nerduino is done through pins and the Roombaduino circuit can stack on top.

Roombaduino - part 10 - A moving Roomba !

Roombaduino – part 10 – A moving Roomba !

With working transceivers, the next step was to get the Nerduino talking to the Roomba itself.

I had breadboarded a Nerduino, the transceiver and the 5v voltage regulator to manage the Roomba power and serial connections.

IMG_4012

 

The circuit worked but it was a royal pain to get the Roomba to respond. I verified that the serial cable I made was correctly soldered to the right pins of the 7-pin DIN connector and that none of the connections were bridged with other connections if they weren’t supposed to be. I had already demonstrated that I could power a Nerduino from the Roomba itself there was a possibility that the RX and TX pins were not getting data from the Roomba.

I connected them up to my USB-to-Serial converter and opened up a terminal session. When the Roomba is charging, it sends some plain text data and I could see that being sent correctly. That meant the TX pin was working at least. However, whatever command I sent to the Roomba was ignored.

Serial communication can be tricky when an incorrect baud rate is used. If data is transmitted at a different rate, things get garbled. By default, the Roomba 565 is expecting 115200 8-N-1. That can be reduced to 19200 by powering on the Roomba and holding the Clean button for at least 10 seconds. The Roomba will emit a series of descending tones to confirm.

However, there’s no way to set it back to 115200 other than through serial commands or by removing the battery for a moment.

I chose option B and the Roomba played a tune to indicate it was reset.

Once I had done that, it started responding to commands.

Additionally, I had read older posts that indicated it’s helpful to specify the baud rate at startup. So, I included that in my setup code.

The Roomba Receiver part of the code is below. If anyone reads this, please note that it doesn’t work as well as it can. The Roomba responds and will move in the correct directions but there are a couple of issues:

  1. At some point, it stops responding to commands. I don’t know if this is battery-related. I’ve read that the interface “shuts down” if the battery is below a certain level. At the time of writing, the battery *was* low so I have it on charge overnight. I’ll test it later.
  2. When the Roomba is in Full Mode, it doesn’t respond to button presses. In particular, it doesn’t respond to the power button. Because of point #1, the Roomba can be stuck in a spin or moving forward or backward. There’s no way to reset the Roomba other than to pick it up and unscrew the bottom plate to remove the battery. I tried to implement a fail-safe so that I made a digital pin active HIGH and, if it ever went LOW, the Nerduino should transmit a RESET command to the Roomba. If the Roomba isn’t listening for commands, that approach won’t work. I’m thinking now that I have to monitor the battery level to understand when the interface might stop listening and reset if the battery is just above that level.

The video below shows the Roomba responding to commands for a short while:

 

 

#include <SPI.h>
#include "nRF24L01.h"
#include "RF24.h"
#include "printf.h"

#define RADIO_CSN_PIN 9
#define RADIO_CE_PIN  10

RF24 radio(RADIO_CSN_PIN, RADIO_CE_PIN);

#define DD_PIN 2
#define LED_PIN  A5
#define SAFETY_PIN A1
#define SAFETY_OUTPUT_PIN A4

const uint64_t pipes[2] = { 0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL };

void setup(void)
{
   pinMode( SAFETY_PIN, INPUT );
   pinMode( LED_PIN , OUTPUT );
   pinMode( DD_PIN , OUTPUT );

   Serial.begin( 115200 );

   digitalWrite( LED_PIN, HIGH );

// Wake up Roomba
   digitalWrite( DD_PIN, HIGH );
   delay( 100 );
   digitalWrite( DD_PIN, LOW );
   delay( 500 );
   digitalWrite( DD_PIN, HIGH );
   delay( 2000 );

// Initalise ROI
   Serial.write( 128 ); // START
   delay( 50 );
   fullMode();

// Set baud to 115200
   Serial.write( 129 ); // BAUD
   Serial.write( 11 ) ; // 115200

// Indicate that setup is complete
   int i=0;
   for( i = 0 ; i < 10 ; i++ )
   {
      digitalWrite( LED_PIN, HIGH );
      delay(50);
      digitalWrite( LED_PIN, LOW );
      delay(50);
   }

   radio.begin();

   radio.setRetries(15, 15);
   radio.setPayloadSize(8);
   radio.openWritingPipe( pipes[1] );
   radio.openReadingPipe(1, pipes[0]);

   radio.startListening();
}

void resetRoomba()
{
   Serial.write( 7 );
   delay( 50 );
}

void loop(void)
{
   int command;

// Check the safety pin
   if( digitalRead( SAFETY_PIN ) != HIGH )
   {
      digitalWrite( SAFETY_OUTPUT_PIN, LOW );
      resetRoomba();
   } else {
      digitalWrite( SAFETY_OUTPUT_PIN, HIGH );
   }

   if ( radio.available() )
   {
      digitalWrite(A5, HIGH);

      bool done = false;

      while (!done)
      {

// Fetch the payload, and see if this was the last one.
         done = radio.read( &command, sizeof(int) );
         delay(20);
      }

      digitalWrite(A5, LOW);

      if( command=='F' ) goForward();
      if( command=='B' ) goBackward();
      if( command=='L' ) spinLeft();
      if( command=='R' ) spinRight();
      if( command=='S' ) halt();
      if( command=='1' ) safeMode();
      if( command=='2' ) fullMode();
   }
}

void goForward() 
{
   Serial.write(137);   // DRIVE
   Serial.write((uint8_t)0x00);   // 0x00c8 == 200
   Serial.write(0xc8);
   Serial.write(0x80);
   Serial.write((uint8_t)0x00);
}

void goBackward()
{
   Serial.write(137);   // DRIVE
   Serial.write(0xff);   // 0xff38 == -200
   Serial.write(0x38);
   Serial.write(0x80);
   Serial.write((uint8_t)0x00);
}

void spinLeft()
{
   Serial.write(137);   // DRIVE
   Serial.write((uint8_t)0x00);   // 0x00c8 == 200
   Serial.write(0xc8);
   Serial.write((uint8_t)0x00);
   Serial.write(0x01);   // 0x0001 == spin left
}

void spinRight()
{
   Serial.write(137);   // DRIVE
   Serial.write((uint8_t)0x00);   // 0x00c8 == 200
   Serial.write(0xc8);
   Serial.write(0xff);
   Serial.write(0xff);   // 0xffff == -1 == spin right
}

void halt()
{
   Serial.write(137);   // DRIVE
   Serial.write((uint8_t)0x00);
   Serial.write((uint8_t)0x00);
   Serial.write((uint8_t)0x00);
   Serial.write((uint8_t)0x00);
}

void fullMode()
{
   Serial.write( 132 ); // FULL MODE
   delay( 50 );
}

void safeMode()
{
   Serial.write( 131 ); // FULL MODE
   delay( 50 );
}

Roombaduino – part 8 – Connectors

The idea I had in my head of how to put the modules together was that any module could be daisy-chained from a previous one.  Possibly, stacked modules is an alternative but, if you have the joystick module with LEDs and an input/ouput board stacked on top of each other, one of them is going to be obscured.

A simple daisy chain would mean you get a long line of interconnected modules but that doesn’t work so well if you’re building a case for it.

So, due to poor planning on my part, I’ve ended up with a T shaped set of modules. That’s not the end of the world and each module is interchangeable to a certain extent. The video below demonstrates what I have:

 

Roombaduino part 7 – Working joystick input module

I took a couple of attempts to get a working joystick input module and failed miserably as I was trying to be too clever and my soldering wasn’t as good as it should have been

So, I scrapped it all and started again. This time, I made sure that applied some logic to which connections to solder first.

I decided to build a module that had just 1 shift register which handled both the LED output and the joystick button press input. That gave me some more space on the small perfboard to be able to place the PNP transistors for the joystick buttons and also the LEDs.

The video shows it all working.

Roombaduino part 6 – Inputs and Joysticks

I spent a good few days trying to work out how to get the joystick switch working with my shift register design. I can’t believe I’m the only person to have encountered this problem or maybe I’m using the wrong Google search. Anyway, the problem with the joystick switch is that the pin used to detect the button press goes LOW when the switch is pressed. In traditional switches, the output is HIGH and a HIGH data pin is what is used to trigger the interrupt in the Nerduino to tell it to go and detect which inputs are pressed. So I needed to find a way to turn the LOW into a HIGH. For some reason, the inverter circuits I’ve seen didn’t do what I expected ( not to say they are wrong but my understanding of electron flow is limited ).

What I found was that I could use a PNP transistor. A PNP transistor will only allow current to flow from emitter to collector if the base is LOW. So, I was able to connect the shift register pin to the emitter, the data line to the collector and the switch line to the base. Voila! It works !