*********NOTE************
This is by far the most ambitious project that I have attempted so far.
When I discovered that my iRobot was damaged from rain I opened it up and cleaned the corrosion out of it and managed to repair the charging part of the board and then left it intact.
I metered out the motors and found out where the positive and negative parts of the drive motors were. Then I soldered wires onto the posts and the positive and negative of the battery.
Going to the drawing board and designing a shield to mount to the top of the iRobot Body. The Particle is powered from the iRobot so power is not an issue.,. The main problem is designing a forward and reverse into the shield as the (negative and positive ) need to be reversed for the motors to go backwards and it is also how the machine will steer. The design schematics are attached.
The project will be in multiple steps.
1. iRobot Motor Control and Programming
a. Board Design and Soldering
b. Particle Programming and Node Red
2. Programming with AdaCore for Automation Control
a. Integration with Particle for Machine Learning
b. Programming with Adacore for Machine Learning
c. Program Running
3. Video
- Now the Project
To reverse a DC motors direction you need to reverse the negative and the positive of the motor at he same time. And you need to break before you make the connection to prevent short circuits and big sparks.
As you can see by the above diagram D1 and D3 aren’t required as the activation circuit is separate from the control circuit and NPN transistors isolate the contactors from the controller.
1a. Board Design and Soldering
I am using 2 relays each for driving the forward reverse of each wheel (The relays I have are only single NO and NC with commons) and another relay as a activation relay which will be SW2 which drives the brush and starts the motors. The diodes and capacitors in the circuit prevent sparks of the brushes in the motors and shorts.
The Relay Board
To finalize the board I added a +5VDC USB out to charge the Electron's batteries on the joystick board.
I am using the example from the particle documentation regarding publish and subscribe as well as particle function on the Sensor Board.
This is the raw board from PCBway.com
This is the finished board.
Soldering & Testing the Main Board
The remote controller is as follows. I designed the remote controller to use another particle and a joystick but an iPhone or iPad would work as well using an app. (Possibly to follow).
Sensor Board
This is the raw board from pcbway.com
This is is the Finished board
This is the Control Wiring completed.
1b. Particle Programming and Node Red
I am not only programming in automation but I am also adding remote control capability. This will aid in the automation and machine learning.
The most difficult part of the project I think will be the programming part of it. I intend on using a joystick and another particle to drive the device remotely.
I am using the example from the particle documentation regarding publish and subscribe as well as Particle function.
I am using this example which will be heavily modified
I am going to post this as I build it as I go. So there may be some changes in the programming and design as I go.
iRobot Particle Code (Final Code attached as a download)
#include <Particle-GPS.h>
#include "DS18.h"
#include <math.h>
#include <MPU6050.h>
#include <I2Cdev.h>
#include <Particle.h>
#include "Adafruit_MPL3115A2.h"
#include "Particle.h"
#define LTCADDR1 0x69//Table 1 both LOW (7bit address)Feed
#define LTCADDR2 0x67//Table 1 both LOW (7bit address)Circuit1
#define LTCADDR3 0x6f//Table 1 both LOW (7bit address)Circuit2
#define sda D0
#define scl D1
#define Relay1 D2
#define Relay2 D3
#define Relay3 D4
int d2=2;
//-----------------------------------
#define trigPin1 A5
#define echoPin1 A4
#define LEDR A1
//#define led2 10
#define trigPin2 A3
#define echoPin2 A2
#define LEDG A0
#define LEDB 7
//-----------------------------------
int Left;
int Right;
//----------------------------------
byte ADCvinMSB, ADCvinLSB, curSenseMSB, curSenseLSB, AinVMSB, AinVLSB;
unsigned int ADCvin, ADCcur, AinV;
//float inputVoltage1, current0p01;
float inputVoltage2, current0p02;
float inputVoltage3, ADCvoltage, current103, current3, current0p3, current0p03;
float inputVoltage1, current10, current1, current0p1, current0p01;
int set_port = 1;
int incomingByte = 0;
Adafruit_MPL3115A2 baro = Adafruit_MPL3115A2();
//========================================
SYSTEM_THREAD(ENABLED);
// Global
const long interval = 10000; // interval at which to Read Sensors ( in milliseconds)
unsigned long previousMillis = 0; // Stores the time of last reading
DS18 sensor(D5);
Gps _gps = Gps(&Serial1);
Timer _timer = Timer(1, onSerialData);
void setup() {
Serial.begin(9600);
baro.begin();
//Particle.function("Solar", Reset);
//Particle.function("Fan", Fan);
//Particle.function("Radio", Radio);
Particle.function("ON", MotorOn);
Particle.function("Left", MotorLeft);
Particle.function("Right", MotorRight);
Particle.function("Forward", MotorOn);
Particle.function("Back", MotorBack);
pinMode(D6, OUTPUT);
pinMode(D2, OUTPUT);
pinMode(D3, OUTPUT);
pinMode(D4, OUTPUT);
digitalWrite(D2 ,LOW);
digitalWrite(D3 ,LOW);
digitalWrite(D4 ,LOW);
Wire.begin();
delay(1000);
//baro.begin();
byte error, address;
int nDevices;
Serial.println("Initializing...");
_gps.begin(9600);
_timer.start();
//-----------------------------------
pinMode(trigPin1, OUTPUT);
pinMode(echoPin1, INPUT);
pinMode(LEDG, OUTPUT);
pinMode(trigPin2, OUTPUT);
pinMode(echoPin2, INPUT);
pinMode(LEDR, OUTPUT);
pinMode(LEDB, OUTPUT);
//-----------------------------------
}
void onSerialData() {
_gps.onSerialData();
}
void loop() {
char message[120];
char data1[256];
size_t data_used;
int sensorValue;
int status;
int8_t result;
char message1[120];
if (millis() - previousMillis >= (interval )) {
Wire.beginTransmission(LTCADDR1);//first get Input Voltage - 80V max
Wire.write(0x1E);
Wire.endTransmission(false);
Wire.requestFrom(LTCADDR1, 2, true);
delay(1);
ADCvinMSB = Wire.read();
ADCvinLSB = Wire.read();
ADCvin = ((unsigned int)(ADCvinMSB) << 4) + ((ADCvinLSB >> 4) & 0x0F);//formats into 12bit integer
inputVoltage1 = ADCvin * 0.025; //25mV resolution
Wire.beginTransmission(LTCADDR3);//get ADC Input 2V max
Wire.write(0x28);
Wire.endTransmission(false);
Wire.requestFrom(LTCADDR3, 2, true);
delay(1);
AinVMSB = Wire.read();
AinVLSB = Wire.read();
AinV = ((unsigned int)(AinVMSB) << 4) + ((AinVLSB >> 4) & 0x0F);//12 bit format
ADCvoltage = AinV * 0.5E-3; //500uV resolution
Wire.beginTransmission(LTCADDR3);//get sense current
Wire.write(0x14);
Wire.endTransmission(false);
Wire.requestFrom(LTCADDR1, 2, true);
delay(1);
curSenseMSB = Wire.read();
curSenseLSB = Wire.read();
ADCcur = ((unsigned int)(curSenseMSB) << 4) + ((curSenseLSB >> 4) & 0x0F);//12 bit format
//gets voltage across, 25uV resolution, then this converts to voltage for each sense resistor
current10 = ADCcur * (25E-3) / 10.0; //10mA max, unit is mA
current1 = ADCcur * (25E-3) / 1.0; //100mA max, unit is mA
current0p1 = ADCcur * (25E-3) / 0.1; //1A max, unit is mA
current0p01 = ADCcur * (25E-6) / 0.01;//10A max, unit is A
//===========================================================================================
Wire.beginTransmission(LTCADDR2);//first get Input Voltage - 80V max
Wire.write(0x1E);
Wire.endTransmission(false);
Wire.requestFrom(LTCADDR2, 2, true);
delay(1);
ADCvinMSB = Wire.read();
ADCvinLSB = Wire.read();
ADCvin = ((unsigned int)(ADCvinMSB) << 4) + ((ADCvinLSB >> 4) & 0x0F);//formats into 12bit integer
inputVoltage2 = ADCvin * 0.025; //25mV resolution
Wire.beginTransmission(LTCADDR2);//get ADC Input 2V max
Wire.write(0x28);
Wire.endTransmission(false);
Wire.requestFrom(LTCADDR2, 2, true);
delay(1);
AinVMSB = Wire.read();
AinVLSB = Wire.read();
AinV = ((unsigned int)(AinVMSB) << 4) + ((AinVLSB >> 4) & 0x0F);//12 bit format
ADCvoltage = AinV * 0.5E-3; //500uV resolution
Wire.beginTransmission(LTCADDR2);//get sense current
Wire.write(0x14);
Wire.endTransmission(false);
Wire.requestFrom(LTCADDR1, 2, true);
delay(1);
curSenseMSB = Wire.read();
curSenseLSB = Wire.read();
ADCcur = ((unsigned int)(curSenseMSB) << 4) + ((curSenseLSB >> 4) & 0x0F);//12 bit format
//gets voltage across, 25uV resolution, then this converts to voltage for each sense resistor
current10 = ADCcur * (25E-3) / 10.0; //10mA max, unit is mA
current1 = ADCcur * (25E-3) / 1.0; //100mA max, unit is mA
current0p1 = ADCcur * (25E-3) / 0.1; //1A max, unit is mA
current0p02 = ADCcur * (25E-6) / 0.01;//10A max, unit is A
//============================================================================================
Wire.beginTransmission(LTCADDR3);//first get Input Voltage - 80V max
Wire.write(0x1E);
Wire.endTransmission(false);
Wire.requestFrom(LTCADDR3, 2, true);
delay(1);
ADCvinMSB = Wire.read();
ADCvinLSB = Wire.read();
ADCvin = ((unsigned int)(ADCvinMSB) << 4) + ((ADCvinLSB >> 4) & 0x0F);//formats into 12bit integer
inputVoltage3 = ADCvin * 0.025; //25mV resolution
Wire.beginTransmission(LTCADDR3);//get ADC Input 2V max
Wire.write(0x28);
Wire.endTransmission(false);
Wire.requestFrom(LTCADDR3, 2, true);
delay(1);
AinVMSB = Wire.read();
AinVLSB = Wire.read();
AinV = ((unsigned int)(AinVMSB) << 4) + ((AinVLSB >> 4) & 0x0F);//12 bit format
ADCvoltage = AinV * 0.5E-3; //500uV resolution
Wire.beginTransmission(LTCADDR3);//get sense current
Wire.write(0x14);
Wire.endTransmission(false);
Wire.requestFrom(LTCADDR3, 2, true);
delay(1);
curSenseMSB = Wire.read();
curSenseLSB = Wire.read();
ADCcur = ((unsigned int)(curSenseMSB) << 4) + ((curSenseLSB >> 4) & 0x0F);//12 bit format
current103 = ADCcur * (25E-3) / 10.0; //10mA max, unit is mA
current3 = ADCcur * (25E-3) / 1.0; //100mA max, unit is mA
current0p3 = ADCcur * (25E-3) / 0.1; //1A max, unit is mA
current0p03 = ADCcur * (25E-6) / 0.01;//10A max, unit is A
//=====================================Temp sensor
sensor.read();
Serial.printf("Temperature %.2f C %.2f F ", sensor.celsius(), sensor.fahrenheit());
delay(1000);
sprintf(message, "RC %f : RV %f : BL %f : BC %f : SLR %f : SCR %f : Temp %f",current0p03 ,inputVoltage3 ,inputVoltage2 ,current0p02 ,inputVoltage1 ,current0p01, sensor.celsius());
Particle.publish("String", message, PRIVATE);
//===================================
Pgtop pgtop = Pgtop(_gps);
if (pgtop.parse())
{
Serial.println("1) Antenna Status ($PGTOP)");
Serial.println("======================================================");
Serial.print("Command ID: "); Serial.println(pgtop.commandId);
Serial.print("Antenna Status: "); Serial.println(pgtop.reference);
Serial.println("");
}
Gga gga = Gga(_gps);
if (gga.parse())
{
Serial.println("2) Global Positioning System Fixed Data ($GPGGA)");
Serial.println("======================================================");
Serial.print("UTC Time: "); Serial.println(gga.utcTime);
Serial.print("Latitude: "); Serial.println(gga.latitude);
Serial.print("North/SouthIndicator: "); Serial.println(gga.northSouthIndicator);
Serial.print("Longitude: "); Serial.println(gga.longitude);
Serial.print("East/WestIndicator: "); Serial.println(gga.eastWestIndicator);
Serial.print("Position Fix Indicator: "); Serial.println(gga.positionFixIndicator);
Serial.print("Satellites Used: "); Serial.println(gga.satellitesUsed);
Serial.print("Horizontal Dilution of Precision: "); Serial.println(gga.hdop);
Serial.print("Altitude: "); Serial.print(gga.altitude); Serial.print(" "); Serial.println(gga.altitudeUnit);
Serial.print("Geoidal Separation: "); Serial.print(gga.geoidalSeparation); Serial.print(" "); Serial.println(gga.geoidalSeparationUnit);
Serial.print("Age of Diff. Corr.: "); Serial.println(gga.ageOfDiffCorr);
Serial.println("");
const char* Latitude = (gga.latitude);
// Particle.publish(("Latitude: "),Latitude, PRIVATE);
// Particle.publish(("Longitude: "),(gga.longitude), PRIVATE);
}
Rmc rmc = Rmc(_gps);
if (rmc.parse())
{
Serial.println("3) Recommended Minimum Navigation Information ($GPRMC)");
Serial.println("======================================================");
Serial.print("UTC Time: "); Serial.println(rmc.utcTime);
Serial.print("Latitude: "); Serial.println(rmc.latitude);
Serial.print("North/SouthIndicator: "); Serial.println(rmc.northSouthIndicator);
Serial.print("Longitude: "); Serial.println(rmc.longitude);
Serial.print("East/WestIndicator: "); Serial.println(rmc.eastWestIndicator);
Serial.print("Speed Over Ground: "); Serial.println(rmc.speedOverGround);
Serial.print("Course Over Ground: "); Serial.println(rmc.courseOverGround);
Serial.print("Date: "); Serial.println(rmc.date);
Serial.print("Magnetic Variation: "); Serial.print(rmc.magneticVariation); Serial.print(" "); Serial.println(rmc.magneticVariationDirection);
Serial.print("Mode: "); Serial.println(rmc.mode);
Serial.println("");
}
sprintf(message1, " SOG %f : COG %f : ALT_Meters %f",rmc.speedOverGround ,rmc.courseOverGround ,gga.altitude);
// Particle.publish("String2", message1, PRIVATE);
previousMillis = millis();
}
//-----------------------------------------------------------
long duration, distance;
digitalWrite(trigPin1, LOW); // Added this line
delayMicroseconds(2); // Added this line
digitalWrite(trigPin1, HIGH);
// delayMicroseconds(1000); - Removed this line
delayMicroseconds(10); // Added this line
digitalWrite(trigPin1, LOW);
duration = pulseIn(echoPin1, HIGH);
distance = (duration/2) / 29.1;
if (distance < 4) { // This is where the LED On/Off happens
digitalWrite(LEDR,HIGH); // When the Red condition is met, the Green LED should turn off
digitalWrite(D2,LOW);
}
else {
digitalWrite(LEDG,LOW);
digitalWrite(LEDB,HIGH);
}
if (distance >= 200 || distance <= 0){
Serial.println("Out of range");
}
else {
Serial.print(distance);
Serial.println(" cm");
}
delay(500);
digitalWrite(trigPin2, LOW); // Added this line
delayMicroseconds(2); // Added this line
digitalWrite(trigPin2, HIGH);
// delayMicroseconds(1000); - Removed this line
delayMicroseconds(10); // Added this line
digitalWrite(trigPin2, LOW);
duration = pulseIn(echoPin2, HIGH);
distance = (duration/2) / 29.1;
if (distance < 4) { // This is where the LED On/Off happens
digitalWrite(LEDR,HIGH); // When the Red condition is met, the Green LED should turn off
digitalWrite(D2,LOW);
}
else {
digitalWrite(LEDG,LOW);
digitalWrite(LEDB,HIGH);
}
if (distance >= 200 || distance <= 0){
Serial.println("Out of range");
}
else {
Serial.print(distance);
Serial.println(" cm");
}
delay(500);
//-------------------------------------------------------------
/*
}
int Reset(String command) {
if(command =="1") {
digitalWrite(D2 ,HIGH);
Particle.publish("D2_On", "1",PRIVATE);
delay(10000);
digitalWrite(D2 ,LOW);
Particle.publish("D2_Reset", "0",PRIVATE);
}
return 1 ;
}
int Fan(String command) {
if(command =="2") {
digitalWrite(D4,HIGH);
Particle.publish("D3_On", "1",PRIVATE);
}
else if(command =="3") {
digitalWrite(D4 ,LOW);
Particle.publish("D3_Off", "1",PRIVATE);
}
return 1 ;
}
int Radio(String command) {
if(command =="4") {
digitalWrite(D3 ,HIGH);
Particle.publish("D4_On", "1",PRIVATE);
}
else if(command =="5") {
digitalWrite(D3,LOW);
Particle.publish("D4_Reset", "0",PRIVATE);
*/
}
int MotorLeft(String command) {
if(command =="1") {
digitalWrite(D4,HIGH);
Particle.publish("Left","1",PRIVATE);
}
else if(command =="5") {
digitalWrite(D4 ,LOW);
Particle.publish("off","1",PRIVATE);
}
return 1 ;
}
int MotorRight(String command) {
if(command =="2") {
digitalWrite(D3 ,HIGH);
Particle.publish("Right","1",PRIVATE);
}
else if(command =="5") {
digitalWrite(D3,LOW);
Particle.publish("off","1",PRIVATE);
}
return 1 ;
}
int MotorOn(String command) {
if(command =="4") {
digitalWrite(D2 ,HIGH);
Particle.publish("Motor_On", "1",PRIVATE);
}
else if(command =="5") {
digitalWrite(D2,LOW);
Particle.publish("Motor_Off", "0",PRIVATE);
}
return 1 ;
}
int MotorBack(String command) {
if(command =="3") {
digitalWrite(D2 ,HIGH);
digitalWrite(D3 ,HIGH);
digitalWrite(D4 ,HIGH);
Particle.publish("Back", "1",PRIVATE);
}
else if(command =="5") {
digitalWrite(D2,LOW);
digitalWrite(D3 ,LOW);
digitalWrite(D4 ,LOW);
Particle.publish("Motor_Off", "0",PRIVATE);
}
return 1 ;
}
Controller Code (Final Code attached as a download)
const int SW_pin = 6; // digital pin connected to switch output
const int X_pin = A1; // analog pin connected to X output
const int Y_pin = A0; // analog pin connected to Y output
const int Up = D5;
const int Down = D4;
const int Left = D6;
const int Right = D3;
const int LEDPower = 7;
int Switch ;
int xaxis ;
int yaxis ;
void setup() {
pinMode(SW_pin, INPUT);
digitalWrite(SW_pin, LOW);
Serial.begin(9600);
pinMode(LEDPower, OUTPUT);
digitalWrite(LEDPower, HIGH);
pinMode(Down, OUTPUT);
pinMode(Left, OUTPUT);
pinMode(Right, OUTPUT);
pinMode(Up, OUTPUT);
}
void loop() {
Serial.print("Switch: ");
Serial.print(digitalRead(SW_pin));
Serial.println("\n");
Serial.print("X-axis: ");
Serial.print(analogRead(X_pin));
Serial.println("\n");
Serial.print("Y-axis: ");
Serial.println(analogRead(Y_pin));
Serial.print("\n\n");
delay(100);
if (analogRead(SW_pin) == 1) {
Particle.publish("MotorOn","6");
}
if (analogRead(X_pin) == 2128) {
Particle.publish("MotorOff","5");
delay(500);
}
if (analogRead(X_pin) <= 200) {
Particle.publish("Left","1");
Particle.publish("MotorOn","6");
}
if (analogRead(X_pin) >= 4000) {
Particle.publish("Right","2");
Particle.publish("MotorOn","6");
}
if (analogRead(Y_pin) == 2128) {
Particle.publish("MotorOff","5");
Particle.publish("MotorOn","6");
}
if (analogRead(Y_pin) <= 200) {
Particle.publish("Back","3");
Particle.publish("MotorOn","6");
}
if (analogRead(Y_pin) >= 4000) {
Particle.publish("Forward","4");
Particle.publish("MotorOn","6");
}
delay(50);
}
I am using Node Red installed on my Raspberry pi to act as an intermediary for the Activation of the relays between the two Particles..The debug nodes are to watch what happens and are optional.
I made a Dashboard with Node Red..Instructions to follow
String Splitting Code(for Function)
var OutPutMsgs =[ ];
var words =msg.payload.split(":");
for (var w in words) {
OutPutMsgs.push({payload:words[w]});
}
return [OutPutMsgs];
Integration with the STM32-H407 and the Particle
I incorporated the STM32 by using the USB Out on my particle board for power and the TX RX serial connection to read what was being sensed by the Particle and GPS Unit. connections below
What is Artificial Intelligence?Artificial intelligence (AI) is the ability of a digital computer or computer-controlled robot to perform tasks commonly associated with intelligent beings.
Comments