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 !

Roombaduino – part 5 – Soldered Shift Registers

Once I’d verified that I understood the concept of using the shift register for both input and output, I designed a board to have 8 LED outputs and 8 button inputs. Again, I made this modular so that I can plug and unplug it into the Nerduino.

IMG_3911

 

The image above shows the board with 1 shift register installed. This is for the output, the second one will be for the input and that’s still to be soldered.

The wiring leaves a lot to be desired. I’ll think about v2.0 at a later time, I’d just like to get it working first.

IMG_3912

Here’s a video of it working:

Roombaduino part 4 – Shift Registers

Because the number of inputs I want to put on the remote control exceeds the number of pins on the micro controller, there needs to be some creative electronics. I claim no ownership of this idea but I picked up some very useful information from Kevin Darrah’s YouTube video ( https://www.youtube.com/watch?v=6fVbJbNPrEU ).

Here’s the video of me reproducing the circuit to make sure I understand how it all works ( I do 🙂 )

 

Roombaduino part 3 – Soldering the Nerduino

Once again, I’m soldering Nerduinos to act as the micro controller for the remote control.

This time, I’ve added generic connector so that I can reuse this when I need to. It has 15 pins plus GND and VCC which should be just enough to have 2 joysticks, the wireless transceiver and a shift register-based button panel (see the next video for the first step of that ). To prove that I soldered it all correctly, here’s the obligatory video: