From bf1c85b152df00a7dcf652cbb1d5657746229c74 Mon Sep 17 00:00:00 2001 From: elshadsabziyev <79898558+elshadsabziyev@users.noreply.github.com> Date: Sun, 19 Nov 2023 04:38:24 +0400 Subject: [PATCH 1/8] Update README.md --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 00b4c53..5feae0e 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,7 @@ To set up and run this project locally, follow these steps: ## 🔧 Usage -1. Users place orders via the website [https://pam-project.vercel.app/](https://pam-project.vercel.app) associating each item with a unique RFID code. +1. Users place orders via the website [https://pam-project.vercel.app/](https://shopbot-site.vercel.app) associating each item with a unique RFID code. (URL could be anything you set, for more info see : [⚙️ Installation](#installation) - 3) 3. Run the Python script `main.py` to start monitoring the database for new orders. 4. Upon detecting new orders, the Python script triggers the Arduino bot, which navigates shelves and picks items based on RFID matches. @@ -84,10 +84,10 @@ To set up and run this project locally, follow these steps: - **Supervisor (BHOS Lecturer - Robotics)** : [Aydin Nasirzade](https://github.com/supervisor) - **Hardware (Arduino - Sensors)**: [Arif Najafov](https://github.com/hardware-lead) -- **Hardware Assistant (Construction - Mechanics)**: [Nijat Aliyev](https://github.com/hardware-assistant) -- **Sofware Project Lead (Arduino - Python)**: [Elshad Sabziyev](https://github.com/sabziyevelshad) +- **Hardware Assistant (Construction - Mechanics)**: [Nijat Aliyev](https://github.com/nicataie) +- **Sofware (Arduino - Python)**: [Elshad Sabziyev](https://github.com/sabziyevelshad) - **Front-end Developer**: [Murad Taghiyev](https://github.com/muradtaghiyev05) -- **AI/ML Expert (Planned for future development)**: [Gurban Guliyev](https://github.com/ai-ml-expert) +- **AI/ML Expert (Planned for future development)**: [Gurban Guliyev](https://github.com/QuriMAY) ## 🛣️ Roadmap From afc3cc34e7316a250a01dcc43727913d40df7d38 Mon Sep 17 00:00:00 2001 From: elshadsabziyev <79898558+elshadsabziyev@users.noreply.github.com> Date: Sun, 19 Nov 2023 13:27:28 +0400 Subject: [PATCH 2/8] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5feae0e..0df3f61 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ To set up and run this project locally, follow these steps: - It must be able to go staright and reverse, has RFID reader on the bottom, has some kind of arm and storage to pick and carry items and has to facilitate enough space for Raspberry Pi, Arduino and batteries. 1. **Clone the repository**: `git clone https://github.com/your-username/order-fulfillment.git` 2. **Front end side**: - - The front-end for this project has been developed and deployed. You can find detailed instructions and information about the front-end deployment in this repository: [Front-end Repository](https://github.com/muradtaghiyev05/pam-project). Please follow the instructions provided in the front-end repository for setting up, deploying, and using the front-end interface of this system. After deployment you can set custom URL to your site. + - The front-end for this project has been developed and deployed. You can find detailed instructions and information about the front-end deployment in this repository: [Front-end Repository](https://github.com/elshadsabziyev/ShopBot-Webpage). (Full credit to team member [Murad Taghiyev](https://github.com/muradtaghiyev05)) Please follow the instructions provided in the front-end repository for setting up, deploying, and using the front-end interface of this system. After deployment you can set custom URL to your site. - (OPTIONAL) You can develop your own front-end, connect it to any database, make required changes to `main.py` depending on this database and deploy the site. 3. **Configure database credentials**: - Update the `CREDENTIALS` dictionary in the Python script with your database details. From 3d6f331bf499fb05e2d96fac70f1a09e858b5979 Mon Sep 17 00:00:00 2001 From: elshadsabziyev <79898558+elshadsabziyev@users.noreply.github.com> Date: Sun, 19 Nov 2023 13:30:05 +0400 Subject: [PATCH 3/8] Update README.md Typos --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0df3f61..71a0650 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,7 @@ To set up and run this project locally, follow these steps: 3. **Configure database credentials**: - Update the `CREDENTIALS` dictionary in the Python script with your database details. 4. **Install necessary dependencies on Raspberry Pi and your Machine**: - - Python packages - Raspberryy Pi: `pip install -r requirements.txt` + - Python packages - Raspberry Pi: `pip install -r requirements.txt` - Arduino libraries - Your Machine/Raspberry Pi: Refer to the list of libraries used in the Arduino sketch and install them using the Arduino IDE's Library Manager. 5. **Connect the Arduino**: - Connect it to the specified port (change `PORT` variable if necessary) and upload the Arduino sketch to the board. @@ -85,7 +85,7 @@ To set up and run this project locally, follow these steps: - **Supervisor (BHOS Lecturer - Robotics)** : [Aydin Nasirzade](https://github.com/supervisor) - **Hardware (Arduino - Sensors)**: [Arif Najafov](https://github.com/hardware-lead) - **Hardware Assistant (Construction - Mechanics)**: [Nijat Aliyev](https://github.com/nicataie) -- **Sofware (Arduino - Python)**: [Elshad Sabziyev](https://github.com/sabziyevelshad) +- **Software (Arduino - Python)**: [Elshad Sabziyev](https://github.com/sabziyevelshad) - **Front-end Developer**: [Murad Taghiyev](https://github.com/muradtaghiyev05) - **AI/ML Expert (Planned for future development)**: [Gurban Guliyev](https://github.com/QuriMAY) From f114a9776f6276b0c0b1e89472bd5800473a9510 Mon Sep 17 00:00:00 2001 From: elshadsabziyev <79898558+elshadsabziyev@users.noreply.github.com> Date: Sun, 19 Nov 2023 13:52:44 +0400 Subject: [PATCH 4/8] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 71a0650..184953d 100644 --- a/README.md +++ b/README.md @@ -104,8 +104,8 @@ To set up and run this project locally, follow these steps: - Add visual indicators for order statuses and item picking progress. - **🔐 QR Code Token Generation for Pickup Verification**: - - Generate unique QR code tokens for each order placed, containing the site URL and a special token. - - Allow customers to access their unique QR codes through the order confirmation page for in-store pickup verification. + - Verification of User Presence in Store: The QR code, when scanned with the token, verifies that the user is physically present in the store. + - Identification of Location: It also identifies the specific location within the store where the scanning occurred. ### 🚀 Version 1.2.0 From de084b3c5d5850dea693bcb223b59269b32257ad Mon Sep 17 00:00:00 2001 From: Elshad Sabziyev Date: Tue, 5 Dec 2023 05:51:14 +0000 Subject: [PATCH 5/8] Servo pins and angles are modified --- itemlist_retriever.py | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/itemlist_retriever.py b/itemlist_retriever.py index 3d9a22c..877d5db 100644 --- a/itemlist_retriever.py +++ b/itemlist_retriever.py @@ -9,6 +9,7 @@ 9600 # baudrate of the serial connection to the arduino, change this if needed ) + # used to store the previous items that were retrieved from the database # this is used to check if the items have changed during the next iteration of the loop prev_items = None @@ -51,27 +52,28 @@ def find_ARDUINO_serial_port(): try: port = "COM" + str(i) ser = Serial(port) - ser.close() return port except: pass elif os_name == "posix": - for port in range(0, 256): - try: - port = "/dev/ttyUSB" + str(port) - ser = Serial(port) - ser.close() - return port - except: - pass + for port_num in range(0, 256): + for port_prefix in ["/dev/ttyUSB", "/dev/ttyACM"]: + try: + port = port_prefix + str(port_num) + ser = Serial(port) + ser.close() + return port + except: + pass + else: raise Exception("Unknown OS") def read(self): try: return self.ser.readline().decode().strip() - except: - return ">>>>> ERROR - Serial read failed - possible cause: serial port not connected" + except Exception as e: + print(e) def close(self): self.ser.close() @@ -105,4 +107,4 @@ def main(): if __name__ == "__main__": main() - # test() \ No newline at end of file + # test() From 944f3130ca4e9e4d7b3cf457547b920c67f23d00 Mon Sep 17 00:00:00 2001 From: elshadsabziyev <79898558+elshadsabziyev@users.noreply.github.com> Date: Tue, 5 Dec 2023 11:36:12 +0400 Subject: [PATCH 6/8] Refactor unit tests for DatabaseConnection and SerialConnection classes --- test_itemlist_retriever.py | 108 ------------------------------------- 1 file changed, 108 deletions(-) delete mode 100644 test_itemlist_retriever.py diff --git a/test_itemlist_retriever.py b/test_itemlist_retriever.py deleted file mode 100644 index 469cf0d..0000000 --- a/test_itemlist_retriever.py +++ /dev/null @@ -1,108 +0,0 @@ -import unittest -from unittest.mock import patch -from itemlist_retriever import DatabaseConnection, SerialConnection - - -class TestDatabaseConnection(unittest.TestCase): - def setUp(self): - self.credentials = { - "host": "localhost", - "user": "root", - "password": "password", - "database": "test_db", - } - self.db = DatabaseConnection(self.credentials) - - def test_fetch_all_items(self): - expected_items = {1: ["item1", "item2"], 2: ["item3", "item4"]} - with patch.object(self.db.conn, "cursor") as mock_cursor: - mock_cursor.return_value.fetchall.return_value = [ - (1, '["item1", "item2"]'), - (2, '["item3", "item4"]'), - ] - items_dict = self.db.fetch_all_items() - self.assertEqual(items_dict, expected_items) - - -class TestSerialConnection(unittest.TestCase): - def setUp(self): - self.baudrate = 9600 - self.ser = SerialConnection(self.baudrate) - - def test_write(self): - with patch.object(self.ser.ser, "write") as mock_write: - data = "test data" - self.ser.write(data) - mock_write.assert_called_once_with(data.encode()) - - def test_read(self): - with patch.object(self.ser.ser, "readline") as mock_readline: - mock_readline.return_value.decode.return_value = "test" - result = self.ser.read() - self.assertEqual(result, "test") - - def test_close(self): - with patch.object(self.ser.ser, "close") as mock_close: - self.ser.close() - mock_close.assert_called_once() - - -if __name__ == "__main__": - unittest.main() -import unittest -from unittest.mock import patch -from itemlist_retriever import DatabaseConnection, SerialConnection, main - - -class TestDatabaseConnection(unittest.TestCase): - def setUp(self): - self.credentials = { - "host": "localhost", - "user": "root", - "password": "password", - "database": "test_db", - } - self.db = DatabaseConnection(self.credentials) - - def test_fetch_all_items(self): - expected_items = {1: ["item1", "item2"], 2: ["item3", "item4"]} - with patch.object(self.db.conn, "cursor") as mock_cursor: - mock_cursor.return_value.fetchall.return_value = [ - (1, '["item1", "item2"]'), - (2, '["item3", "item4"]'), - ] - items_dict = self.db.fetch_all_items() - self.assertEqual(items_dict, expected_items) - - -class TestSerialConnection(unittest.TestCase): - def setUp(self): - self.baudrate = 9600 - self.ser = SerialConnection(self.baudrate) - - def test_write(self): - with patch.object(self.ser.ser, "write") as mock_write: - data = "test data" - self.ser.write(data) - mock_write.assert_called_once_with(data.encode()) - - def test_read(self): - with patch.object(self.ser.ser, "readline") as mock_readline: - mock_readline.return_value.decode.return_value = "test" - result = self.ser.read() - self.assertEqual(result, "test") - - def test_close(self): - with patch.object(self.ser.ser, "close") as mock_close: - self.ser.close() - mock_close.assert_called_once() - - -class TestMain(unittest.TestCase): - def test_main(self): - # TODO: Add your test case for the main function here - pass - - -if __name__ == "__main__": - unittest.main() From 9c2c8c598f1bad622e43d0e5a671c012b9bb71ba Mon Sep 17 00:00:00 2001 From: elshadsabziyev <79898558+elshadsabziyev@users.noreply.github.com> Date: Fri, 8 Dec 2023 12:11:45 +0400 Subject: [PATCH 7/8] Update Arduino port and add error handling for reading from serial --- .vscode/arduino.json | 2 +- itemlist_retriever.py | 10 +++-- transmitter/transmitter.ino | 79 ++++++++++++++++++++++++++----------- 3 files changed, 63 insertions(+), 28 deletions(-) diff --git a/.vscode/arduino.json b/.vscode/arduino.json index f8d5ce0..1b660b5 100644 --- a/.vscode/arduino.json +++ b/.vscode/arduino.json @@ -1,6 +1,6 @@ { "board": "arduino:avr:uno", "programmer": "avrisp", - "port": "COM9", + "port": "COM10", "sketch": "transmitter\\transmitter.ino" } \ No newline at end of file diff --git a/itemlist_retriever.py b/itemlist_retriever.py index 877d5db..5928a00 100644 --- a/itemlist_retriever.py +++ b/itemlist_retriever.py @@ -64,7 +64,7 @@ def find_ARDUINO_serial_port(): ser.close() return port except: - pass + print("OS: " + os_name + " Port: " + port + " not found\nTrying next port...") else: raise Exception("Unknown OS") @@ -97,10 +97,14 @@ def main(): ) to_write = items_dict[max(items_dict.keys())][0].lower() + "\n" prev_items = items_dict - ser.write(to_write) + ser.write(to_write)`` else: print("Items not changed") - print("Reading from serial... :" + ser.read()) + try: + print("Reading from serial... :" + ser.read()) + except: + print("Error reading from serial") + iter_cnt += 1 time.sleep(0.1) diff --git a/transmitter/transmitter.ino b/transmitter/transmitter.ino index 6cbcbb3..47a3c4d 100644 --- a/transmitter/transmitter.ino +++ b/transmitter/transmitter.ino @@ -19,21 +19,22 @@ String previousUID = "0"; // Do not change // String previousRFIDUID = "0"; // Do not change // String fromSerialUID = "0"; // Do not change // -String fromRFIDUID = "0"; // Do not change // -String readSerialFlag = "0"; // Do not change // -int printCounter = 0; // Do not change // -int pickUpTimeout = 1500; // Set timeout for picking up item -int serialBaudRate = 9600; // Set serial baud rate -int optimizationDelay = 50; // Fine tune this value to optimize performance -int firstMainLoop = 1; // Do not change // -Servo myServo; // Do not change // -MFRC522 card(10, 9); // SDA, RST set up for MEGA -int motor1pin1 = 2; // pin 2 on L293D -int motor1pin2 = 4; // pin 7 on L293D -int motor2pin1 = 7; // pin 10 on L293D -int motor2pin2 = 8; // pin 15 on L293D -int enable1pin = 5; // pin 1 on L293D -int enable2pin = 6; // pin 9 on L293D +String stopRFID = "4475a389"; +String fromRFIDUID = "0"; // Do not change // +String readSerialFlag = "0"; // Do not change // +int printCounter = 0; // Do not change // +int pickUpTimeout = 1500; // Set timeout for picking up item +int serialBaudRate = 9600; // Set serial baud rate +int optimizationDelay = 50; // Fine tune this value to optimize performance +int firstMainLoop = 1; // Do not change // +Servo myServo; // Do not change // +MFRC522 card(10, 9); // SDA, RST set up for MEGA +int motor1pin1 = 2; // pin 2 on L293D +int motor1pin2 = 4; // pin 7 on L293D +int motor2pin1 = 7; // pin 10 on L293D +int motor2pin2 = 8; // pin 15 on L293D +int enable1pin = 5; // pin 1 on L293D +int enable2pin = 6; // pin 9 on L293D void setup() { @@ -48,12 +49,13 @@ void setup() pinMode(motor2pin2, OUTPUT); pinMode(enable1pin, OUTPUT); pinMode(enable2pin, OUTPUT); - analogWrite(enable1pin, 150); - analogWrite(enable2pin, 150); + analogWrite(enable1pin, 200); + analogWrite(enable2pin, 200); } void loop() { + // stop if no RFID is present from DB if (firstMainLoop == 1) { makeStartupNoiseUsingServo(); @@ -69,6 +71,19 @@ void loop() moveForward(); } } + if (readSerialFlag == "2") + { + while (readRFIDUID() != stopRFID) + { + moveBackward(); + } + digitalWrite(motor1pin1, LOW); + digitalWrite(motor1pin2, LOW); + digitalWrite(motor2pin1, LOW); + digitalWrite(motor2pin2, LOW); + delay(1000); + readSerialFlag = "0"; + } delay(optimizationDelay); fromRFIDUID = readRFIDUID(); delay(optimizationDelay); @@ -79,10 +94,9 @@ void loop() pickItem(); delay(pickUpTimeout); // set flag to 0 - readSerialFlag = "0"; + readSerialFlag = "2"; previousUID = "0"; previousRFIDUID = "0"; - Serial.println("Item picked and ready to get another RFID"); } // if there is a new RFID from DB and RFID from RFID reader are not the same else if (fromSerialUID == "0") @@ -173,22 +187,31 @@ void moveForward() digitalWrite(motor2pin2, LOW); } +void moveBackward() +{ + digitalWrite(motor1pin1, LOW); + digitalWrite(motor1pin2, HIGH); + digitalWrite(motor2pin1, LOW); + digitalWrite(motor2pin2, HIGH); +} + void pickItem() { digitalWrite(motor1pin1, LOW); digitalWrite(motor1pin2, LOW); digitalWrite(motor2pin1, LOW); digitalWrite(motor2pin2, LOW); - delay(4000); - for (int i = 0; i <= 150; i += 45) + delay(2000); + for (int i = 0; i <= 120; i += 30) { myServo.write(i); - delay(50); + delay(100); } - for (int i = 150; i >= 0; i -= 45) + delay(2000); + for (int i = 120; i >= 0; i -= 30) { myServo.write(i); - delay(50); + delay(100); } digitalWrite(motor1pin1, LOW); digitalWrite(motor1pin2, HIGH); @@ -207,3 +230,11 @@ void makeStartupNoiseUsingServo() myServo.write(0); delay(100); } + +void stop() +{ + digitalWrite(motor1pin1, LOW); + digitalWrite(motor1pin2, LOW); + digitalWrite(motor2pin1, LOW); + digitalWrite(motor2pin2, LOW); +} \ No newline at end of file From 9650b2d864822d0c68da8e9077759b4c3c1758b0 Mon Sep 17 00:00:00 2001 From: elshadsabziyev <79898558+elshadsabziyev@users.noreply.github.com> Date: Fri, 8 Dec 2023 12:15:55 +0400 Subject: [PATCH 8/8] Fix typo --- itemlist_retriever.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/itemlist_retriever.py b/itemlist_retriever.py index 5928a00..0e393f9 100644 --- a/itemlist_retriever.py +++ b/itemlist_retriever.py @@ -97,7 +97,7 @@ def main(): ) to_write = items_dict[max(items_dict.keys())][0].lower() + "\n" prev_items = items_dict - ser.write(to_write)`` + ser.write(to_write) else: print("Items not changed") try: