MicroDozer Fall 2019
MicroDozer Fall 2019: System Firmware
Author/s: Jesus Rios (Firmware)
Verification:
Approval:
Discussion
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<