MicroDozer Fall 2019

MicroDozer Fall 2019: System Firmware

Author/s: Jesus Rios (Firmware)
Verification:
Approval:

Discussion

Fig. 1 System flow diagram

The MicroDozer uses LED lights as an external light source to use as a flashlight underneath cramped spaces. Alongside, the LED lights, extra features that were intended to be used were the Ultrasonic sensors, IR sensors, and an LDR photoresistor. Because of the extra-added features, not enough output pins were available, therefore an i2c I/O expander, MCP23008SO, was used. Communication to the i2c proved to be very challenging due to having analog inputs having to be converted to digital inputs and outputs. In the case of the Ultrasonic sensors, data had to be sent to the Ultrasonics and data had to be received as well. This was a common issue with the LED and LDR photoresistor. The i2c can only do a read and write operation one at a time making it difficult to determine when to use specific addresses. For future generations, we recommend using a different i2c for simplicity and a ToF range finder sensor as it includes multiple features to reduce ports used.

Software Code: MoveCommand

<
#include 
#include 
#include      // instantiated as Robot3DoT at end of class header
#include 
#include 
ArxRobot Robot3DoT;       // instantiated as Robot3DoT at end of class header
//*********************************************************************************************

#define SERVO       0x41
#define MOVE        0x01
#define ESCAPE      0x42

Motor motorA;
Motor motorB;
Servo servo1;

const uint8_t CMD_LIST_SIZE = 3;   // we are adding 2 commands (MOVE,SERVO,ESCAPE)
void moveHandler (uint8_t cmd, uint8_t param[], uint8_t n);
void servoHandler (uint8_t cmd, uint8_t param[]);
void escape (uint8_t cmd, uint8_t param[], uint8_t n);
ArxRobot::cmdFunc_t onCommand[CMD_LIST_SIZE] = {{MOVE,moveHandler}, {SERVO,servoHandler}}, {ESCAPE,escape}};
Packet motorPWM(MOTOR2_CURRENT_ID);  // initialize the packet properties to default values
//*****************************************SETUP STARTS HERE*****************************************************

void setup()
{
  Wire.begin();
  Wire.beginTransmission(0x2F);
  Wire.write(53);
  Wire.endTransmission();

  Serial.begin(9600);       // connects to the HM11 module
  Robot3DoT.begin();
  Robot3DoT.setOnCommand(onCommand, CMD_LIST_SIZE);
  motorPWM.setAccuracy(1);          // change sensor accuracy from +/-2 DN to +/-1 DN    (-- this line is optional --)
  motorPWM.setSamplePeriod(500);    // change sample period from 1 second to 0.5 seconds (-- this line is optional --)
  motorA.begin(AIN1,AIN2,PWMA);
  motorB.begin(BIN1,BIN2,PWMB);
  servo1.attach(11); //attaches the servo pin
}

// ****************************************LOOP STARTS HERE******************************************************

void loop()
{
  Robot3DoT.loop();
  #if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega16U4__)
    uint16_t pwm_reading = (uint16_t) OCR4D;  // read 8-bit Output Compare Register Timer 4D and cast to 16-bit signed word
    motorPWM.sendSensor(pwm_reading);
  #else
    uint16_t pwm_reading = (uint16_t) OCR0B;
    motorPWM.sendSensor(pwm_reading);
  #endif 

  Wire.beginTransmission(0x20);
  Wire.write(0x09);
  Wire.write(0x01);
  Wire.endTransmission();

}

// ***************************************ESCAPE STARTS HERE****************************************************
/* Escape Starts Here */

/* Task 1 - download ultrasonic library
 *          1. copy cpp file to a new ino file ####
 *          2. delete 3 pin elements (opt.)  ###
 *          add a function which is called in place of the Arduino pin number ###
 *          This function uses the wire library to call MCP2300850, set as ###
 *          output or input as needed by library and read/return bit ###
 *
 *          i2c_ultrasonic_read(int bit)  // bit 2 or 3
 *
 */

bool ldr_val;       // light detection photo resistor
uint16_t ir_val;       // IR sensor

#define ir_pin     A4  //
#define ping1_bit  3   // MCP2300850 i2c digital input bit 1
#define ping2_bit  2   //
#define ldr_bit    1   // light detector analog output - to - i2c digital input bit 1

void escape (int ldr_pin, int ir_pin, int ping1_pin, int pin2_pin, uint8_t param[], uint8_t n)
{
  ldr_val = i2C_bit_read(GPIO, 1);
  ir_val = digital.read(A4);
  // turn clockwise
  if (ldr_val) {
    motorA.go(0x01, 0x80);
    motorB.go(0x01, 0x80);   // move forward
    if (ir_val < min_ir_dist) {
      motorA.go(0x01, 0x80);
      motorB.go(0x02, 0x80); // turn clockwise }
    }
  }
} 

//********************************MOVE STARTS HERE**********************************************************
/*
 * Move handler and servo handler starts here
 */

void moveHandler (uint8_t cmd, uint8_t param[], uint8_t n)
{
  Serial.write(0x01);             // move command = 0x01
  Serial.write(n);               // number of param = 4
  for (int i=0;i
  {
    Serial.write (param[i]);
  }
  motorA.go(param[0],param[1]);
  motorB.go(param[2],param[3]);
}  // moveHandler

void servoHandler (uint8_t cmd, uint8_t param[])
{
  int n = param[1];
  for (int i = 0; i<=n; i++){ servo1.write(n); servoHandler; } } // servoHandler>

Software Code: i2c Ultrasonic

#include 
#define CM 28
#define INC 71
#define IODIR 0
#define GPIO 0x09
uint8_t und = CM;
unsigned long timeOut = 20000UL;

/*
 * If the unit of measure is not passed as a parameter,
 * by default, it will return the distance in centimeters.
 * To change the default, replace CM by INC.
 * input argument
 * pingBit = 3 or 2
 * timeOut =  20000UL
 * und = 28
 */

unsigned int i2c_ultrasonic_read(uint8_t pingBit){
  i2C_bit_dir(pingBit, 1);   // 1 = output

  i2C_bit_write(pingBit, LOW);
  delayMicroseconds(2);
  i2C_bit_write(pingBit, HIGH);
  delayMicroseconds(10);
  i2C_bit_write(pingBit, LOW);

  i2C_bit_dir(pingBit, 0);  // 0 = input

  previousMicros = micros();
  while(!i2C_bit_read(pingBit) && (micros() - previousMicros) <= timeout); // wait for the echo pin HIGH or timeout
  previousMicros = micros();
  while(i2C_bit_read(pingBit) && (micros() - previousMicros) <= timeout); // wait for the echo pin LOW or timeout

  return ((micros() - previousMicros) / und / 2);  //distance by divisor
}

void i2C_bit_dir(int pingBit, int dir)
{
  Wire.begin();
  Wire.beginTransmission(0x20);// configure I2C direction register bit
  uint8_t IO = wire.read(IODIR);
  Wire.endTransmission();
  Serial.println(IO);

  switch(pingBit)
    case 0:

      if ( dir == 0) // Input
        {IO = IO & 0xFE
        Wire.beginTransmission(0x20); //Address of MCP23008
        Wire.write(IODIR);
        Wire.write(IO);
        Wire.endTransmission();}

      if ( dir == 1) // Output
        {IO = IO | 0x01;
        Wire.beginTransmission(0x20);
        Wire.write(IODIR);
        Wire.write(IO);
        Wire.endTransmission();}
      break

    case 1:

      if ( dir == 0) // Input
        {IO = IO & 0xFD;
        Wire.beginTransmission(0x20);
        Wire.write(IODIR);
        Wire.write(IO);
        Wire.endTransmission();}

      if ( dir == 1) //Output
        {IO = IO | 0x02;
        Wire.beginTransmission(0x20);
        Wire.write(IODIR);
        Wire.write(IO);
        Wire.endTransmission();}
      break

    case 2:

      if ( dir == 0) // Input
        {IO = IO & 0xFB;
        Wire.beginTransmission(0x20);
        Wire.write(IODIR);
        Wire.write(IO);
        Wire.endTransmission();}

      if ( dir == 1) // Output
        {IO = IO | 0x04;
        Wire.beginTransmission(0x20);
        Wire.write(IODIR);
        Wire.write(IO);
        Wire.endTransmission();}
      break

    case 3:

      if ( dir == 0) // Input
        {IO = IO & 0xF7;
        Wire.beginTransmission(0x20);
        Wire.write(IODIR);
        Wire.write(IO);
        Wire.endTransmission();}

      if ( dir == 1) // Output
        {IO = IO | 0x08;
        Wire.beginTransmission(0x20);
        Wire.write(IODIR);
        Wire.write(IO);
        Wire.endTransmission();}
      break;
    // use i2C_bit_write
}
// ************************************************************************

// returns FALSE if 0 otherwise returns a non-zero value TRUE
bool i2C_bit_read(int reg_addr, int theBit)
{
  // read I2C register bit
  // something like this
  Wire.beginTransmission(0x20);
  int reg = Wire.read(reg_addr);
  Wire.endTransmission();
  return bool(reg & (1<< theBit);
}

// ************************************************************************
/* pingBit is bit number 7..0
 * val = 1 or 0
 */

void i2C_bit_write(int reg_addr, int theBit, int val)
{
  // read I2C register bit
  // something like this
  Wire.beginTransmission(0x20);
  uint8_t reg = Wire.read(reg_addr);
  Wire.endTransmission();
  Serial.print(reg);
  reg &= !(1<

References/Resources