/*
A "Blink Bot" is a robot controlled by the blinking of areas on an LCD screen,
e.g. the screen of a cheap old cell phone. After years of looking, that seems to
be the best way to interface the amazing power per cost of those devices to robotics.
https://hackaday.io/project/184720-web-smart-phone-screen-blink-bot
seriously, read that page before you scream? 

The idea here is to use a simple RasPi Pico to interface a cell phone to a roomba
making a telepresense robot out of scrap. The phone can load a web page (or cashe it)
for autonomous control (with help from web apis) 
or connect to a video meeting service so a human can drive the robot around with a
set of black and white cards held up to the camera. 

Another (probably better) option is to use this project:
https://github.com/pkyanam/ArduRoomba
and add the light sensing to that. 
*/

#include <Adafruit_NeoPixel.h>
#define LED 4
/* Roomba interface. 
https://cdn.hackaday.io/files/1747287475562752/Roomba_SCI_manual.pdf
Pin   Name  Description
 1    Vpwr  Roomba battery + (unregulated)
 2    Vpwr  Roomba battery + (unregulated)
 3    RXD   0 – 5V Serial input to Roomba from Pico pin 1 GP0 UART0 Serial1
 4    TXD   0 – 5V Serial output from Roomba to Pico pin 2 GP1 UART0 Serial1
 5    DD    Device Detect input: Active low 500ms to wake up Roomba
 6    GND   Roomba battery ground
 7    GND   Roomba battery ground
*/
#define ROOMBA_DD 3 //DIN pin 4 io pin for Device Detect output
// https://datasheets.raspberrypi.com/pico/Pico-2-Pinout.pdf

//Modes: off, passive, safe, full. Wait 20ms after a mode change
#define ROOMBA_CMD_START 128 //moves from off to passive mode
#define ROOMBA_CMD_CTRL 130 //move from passive to safe: cliff and wheel-drop safety
#define ROOMBA_CMD_FULL 132 //moves from safe to full mode: NO cliff or wheel-drop safety
#define ROOMBA_CMD_SAFE 131 //moves from full to safe mode
#define ROOMBA_CMD_POWER 133 //moves from safe or full to passive, goes to sleep
#define ROOMBA_CMD_DRIVE 137 //plus 2 byte speed and 2 byte turn radius. Safe or full mode only
#define ROOMBA_CMD_DOCK 143 //find the power dock and re-charge. Any mode

void roomba_drive(char * seq, int16_t vel, int16_t rad) {
/*
Serial sequence: [137] [Velhi] [Vello] [Radhi] [Radlo]
Drive data bytes 1 and 2: Velocity (-500 – 500 mm/s)
Drive data bytes 3 and 4: Radius (-2000 – 2000 mm)
Special cases: Straight = 32768 = hex 8000
Turn in place clockwise = -1
Turn in place counter-clockwise = 1
Example:
To drive in reverse at a velocity of -200 mm/s while turning at
a radius of 500mm, you would send the serial byte sequence
[137] [255] [56] [1] [244].
Velocity = -200 = hex FF38 = [hex FF] [hex 38] = [255] [56]
Radius = 500 = hex 01F4 = [hex 01] [hex F4] = [1] [244]
*/
  constrain(vel, -500, 500); //def max and min velocity in mm/s
  constrain(rad, -2000, 2000); //def max and min radius in mm
  if (0==rad) rad = 0x8000; //special case for straight
  seq[0] = ROOMBA_CMD_DRIVE;
  seq[1] = vel >> 8;
  seq[2] = vel & 0xFF;
  seq[3] = rad >> 8;
  seq[4] = rad & 0xFF;
}

//https://www.instructables.com/Controlling-a-Roomba-Robot-With-Arduino-and-Androi/

void roomba_init() {
  pinMode(ROOMBA_DD, OUTPUT);
  digitalWrite(ROOMBA_DD, LOW);
  delay(500+100); //wakey, wakey!

}
char buf[5];
//Adafruit_NeoPixel pixels(1, 25, NEO_GRB + NEO_KHZ800);

void setup() {
  //pixels.begin();
  //pixels.clear();
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, HIGH);
  pinMode(LED, OUTPUT);
  digitalWrite(LED, HIGH);
  Serial.begin(115200);
  while (!Serial) {
    delay(10); // wait for serial port to connect. Needed for native USB
  }
  Serial.println("Ready");
  //Serial1.setRX(ROOMBA_TXD); Only on Earl Powell 
  //Serial1.setTX(ROOMBA_RXD);
  Serial1.begin(57600); //default speed for roomba serial
  roomba_init();
}


#define DEAD_ZONE 100 //don't move if we are close to not moving
#define LITE_MID 250 //ADC reading with lite midrange

void loop() {
  //the ADC reading goes down as lite level goes up
  int lite_right = 1024 - analogRead(A0);
  int lite_left = 1024 - analogRead(A1);

  int left_track = lite_left - LITE_MID;
  if (left_track < DEAD_ZONE) left_track = 0;
  int right_track = lite_right - LITE_MID;
  if (right_track < DEAD_ZONE) right_track = 0;
  int vel = left_track + right_track;
  int rad = left_track - right_track;

  roomba_drive(buf, vel, rad);
  Serial1.write(buf,5);

  Serial.print(lite_right);
  Serial.print(",");
  Serial.print(lite_left);
  Serial.print(",");
  Serial.print(buf[1]*256+buf[2]);
  Serial.print(",");
  Serial.print(buf[3]*256+buf[4]);
  Serial.print("\n");

  delay(500); 
  digitalWrite(LED, HIGH);
  digitalWrite(LED_BUILTIN, LOW);
  //pixels.setPixelColor( 0, pixels.Color(150, 150, 150));
  //pixels.show();
  delay(500); 
  digitalWrite(LED, LOW);
  digitalWrite(LED_BUILTIN, HIGH);
  //pixels.setPixelColor( 0, pixels.Color(0, 0, 0));
  //pixels.show();

}
BOOTSELLED1239USBRaspberryPiPico©2020RP2-8020/21P64M15.00TTT