Introduction: Smart IOT Cart for Internal Logistics (Intel IoT)
The project titled the "Smart IOT Cart for Internal Logistics". Nowdays shopping if not in its entirety,but in increasing majority is done online. It is the most convent form of shopping,as it can be done within the comfort of our home. But not everything can be bought online and there is always the issue of the time of delivery . Our entire project is based on the concept to save the consumers time. Our project is customized to be implemented in any level of shopping establishment.
The main technology used behind our implementation is concept of the Internet of things. How this works is that there is paired mobile app that you can download and that app will have the inventory of the entire shop. After the consumer selects the items,he can either choose to pay the bill via an online portal or can pay it at the shopping counter in person. The bill is transferred in real time to oour smart robo cart,which identifies each item and picks it out into the cart via the robotic arm.after all the items are gathered it proceeds to the check point. Explaining it in a real life scenario,a couple entering a mall can pick out the groceries on the app and by the time they finish their rest of the shopping,their items are ready at the counter either packed (if payment is already done) or waiting for payment.this is especially helpful for a physically disabled person or senior citizens in making their lives much easier. In this age of fast and time saving 21st century man,this implementation is a natural choice for an even faster future.
Step 1: Hardware Assembly Part 1
1. Robotic Arm
Why Need Robotic Arm ?
Idea is simple . In order to pick the items from the shop, we merge this robotic arm module to the Robot. Grocery Items are picked using the gripper that attached to the robotic Arm.
How to Assemble ?
You have to purchase a robotic arm or make it by your own. We here used is a purchased one and that is a 3D printed arm from ebay. Here is the Ebay Link if you want to purchase the same . http://www.ebay.in/itm/Robotic-Arm-/182061698367?...
Note : Here used 4 DOF Robotic Arm. i.e. 4 servo motors are needed.
Then Assemble that robotic arm according to the instructions in the link : https://www.instructables.com/id/EEZYbotARM/
Step 2: Hardware Assembly Part 2
2. Robotic Chasis
You can buy a DIY robot chasis kit from Amazon
Link for purchase : Amazon.in -Robotic Chassis DIY Kit
The chassis kit consist of 1 x Acrylic Robotic Base, 1 x Acrylic Platform, 2 x BO Motor, 2 x BO Motor Wheel, 2 x BO Motor Clamp, 1 x Castor Wheel, 4 x Sleeve (40mm), 6 x Sleeve (15mm), 7 x Screw + Nuts (M3 x 50mm), 8 x Screw + Nuts (M3 x 25mm), 2 x Pointed Screw (M2 x 10mm).
Assemble that chassis kit and that can be used as a movable trolley cum cart. Then place the robotic arm on the top of it. Refer the picture.
Then place a box infront of robotic arm, which is used as a cart. It is for carrying the items that are picked by robotic arm.
Step 3: Hardware Assembly Part 3
Get ready these components
1. Intel Edison Arduino breakout board
- Refer Intel Edison Docummentation and configure your board.
2. i2c Motor shield
- For controlling the dc motors in robotic chassis
3. RFID Reader and tag
- RFID Reader will be attached in the moving trolley and the RFID Card is attached to Products in the shop. This module is for the Identification of Items. Also we can use Intel real sense camera for better accuracy if needed. Here we use RFID-RC522 Module. You can also use 125khz Module
4. Seed base shield
- Refer seed studio kit documentation for more.
5. Ultrasonic sensor (If necessary)
- We can use this sensor for avoiding the obstacles in front of moving trolley and can make the movement easy.
Step 4: MQTT Configuration
MQTT is a machine-to-machine (M2M)/"Internet of Things" connectivity protocol. Its a lightweight messaging protocol for small sensors and mobile devices, optimized for high-latency or unreliable networks.
You need to configure the MQTT server in your Desktop or Laptop (for local connectivity), Using Mosquito (MQTT Broker).
Here is the arduino source code . When it is connected and everything is okay, the board will print the message ''Publication and Subscription are done".
if (!client.connected()) { Serial.println("client.connected Passed"); if (!client.connect("Arduino")) // Fails everytime right here Serial.println("client.connect FAILED"); if (!client.publish("outTopic", "hello world")) Serial.println("client.publish FAILED"); if (!client.subscribe("inTopic")) Serial.println("client.subscribe FAILED"); Serial.println("Publication and Subscription are done"); } else Serial.println("Connection Failed"); }
Step 5: MQTT Subscription and Item Purchase Using Robotic Arm
Customers have the option to select the items using the Android App and after the selection, the app will publish an MQTT message and it will be subscribed in edison. When edison gets the product info , it will move to the products and using the RFID , it will identify the product and when it identifies, the robot will stop there and then the Robotic arm will pick the item and put it in the cart.
if (res == 'a') { // Getting the product id 'a' from the Android App using MQTT. i.e. Customer selected the Items to purchase through App rfidon(); // Call the function for Tracking the product using RFID motor1.run(FORWARD); // Trolley is moving to find the item } // Function rfidon()<br><br>void rfidon()</p><p>{ Serial.println("RFID is working Now"); uchar i, tmp; uchar status; uchar str[MAX_LEN]; uchar RC_size; uchar blockAddr; //选择操作的块地址0~63 String mynum = ""; //runFunction(); //寻卡,返回卡类型 status = MFRC522_Request(PICC_REQIDL, str); Serial.println(status); Serial.println(MI_OK); while (status != MI_OK) { status = MFRC522_Request(PICC_REQIDL, str); Serial.println(status); Serial.println(MI_OK); if (status == MI_OK) { Serial.println("Card detected"); status = MFRC522_Anticoll(str); memcpy(serNum, str, 5); if (status == MI_OK) { do{ Serial.println("The card's number is : "); Serial.print(serNum[0]); Serial.print(" , "); Serial.print(serNum[1], BIN); Serial.print(" , "); Serial.print(serNum[2], BIN); Serial.print(" , "); Serial.print(serNum[3], BIN); Serial.print(" , "); Serial.print(serNum[4], BIN); status = MFRC522_Request(PICC_REQIDL, str); status = MFRC522_Anticoll(str); memcpy(serNum, str, 5); //Serial.println(" "); // Should really check all pairs, but for now we'll just use the first } while (serNum[0] != 225); if (serNum[0] == 225) { Serial.println("RFID Detected"); // Product is Identified Serial.print(serNum[0]); MotorSpeedSetAB(0,0); // Stopping the Vehicle / Trolley servo_4.attach(9); for(servo4_pos =175; servo4_pos >= 30; servo4_pos--) { servo_4.write(servo4_pos); delay(20); //Serial.println("inside servo 4 "); } servo_4.detach(); delay(1000); servo_1.attach(3); for(servo1_pos =5; servo1_pos <= 100; servo1_pos++) { servo_1.write(servo1_pos); delay(20); } servo_1.detach(); delay(1000);</p><p> delay(1000); servo_1.attach(3); for(servo1_pos =100; servo1_pos >= 5; servo1_pos--) { servo_1.write(servo1_pos); delay(20); } delay(1000);</p><p> servo_4.attach(9); for(servo4_pos =30; servo4_pos <= 175; servo4_pos++) { servo_4.write(servo4_pos); delay(20); Serial.println("inside servo 4 "); } servo_4.detach(); //break; delay(1000); servo_1.attach(3); for(servo1_pos =5; servo1_pos <= 100; servo1_pos++) { servo_1.write(servo1_pos); delay(20); } for(servo1_pos =100; servo1_pos >= 5; servo1_pos--) { servo_1.write(servo1_pos); delay(20); } servo_1.detach(); delay(1000); } } // Serial.print(str[0],BIN); // Serial.print(" , "); // Serial.print(str[1],BIN); // Serial.println(" "); } } //Serial.println(" "); MFRC522_Halt();
Step 6: Access WiFi in Intel Edison [Connectivity]
We need to access the wifi in Intel edison . Here is the Source Code
#include<WiFi.h> char ssid[] = "Intel_Hackathon"; // your network SSID (name) char pass[] = "Intelhack"; // your network password int status = WL_IDLE_STATUS; // the Wifi radio's status byte server[] = {192, 168, 21, 96}; // Replace your MQTT Server IP WiFiClient wifiClient; PubSubClient client(server, 1883, callback, wifiClient); void printWifiData() { // print your WiFi shield's IP address: IPAddress ip = WiFi.localIP(); Serial.print("IP Address: "); Serial.println(ip); Serial.println(ip); // print your MAC address: byte mac[6]; WiFi.macAddress(mac); Serial.print("MAC address: "); Serial.print(mac[5], HEX); Serial.print(":"); Serial.print(mac[4], HEX); Serial.print(":"); Serial.print(mac[3], HEX); Serial.print(":"); Serial.print(mac[2], HEX); Serial.print(":"); Serial.print(mac[1], HEX); Serial.print(":"); Serial.println(mac[0], HEX);</p><p>}</p><p>void printCurrentNet() { // print the SSID of the network you're attached to: Serial.print("SSID: "); Serial.println(WiFi.SSID());</p><p> // print the MAC address of the router you're attached to: byte bssid[6]; WiFi.BSSID(bssid); Serial.print("BSSID: "); Serial.print(bssid[5], HEX); Serial.print(":"); Serial.print(bssid[4], HEX); Serial.print(":"); Serial.print(bssid[3], HEX); Serial.print(":"); Serial.print(bssid[2], HEX); Serial.print(":"); Serial.print(bssid[1], HEX); Serial.print(":"); Serial.println(bssid[0], HEX);// print the received signal strength: long rssi = WiFi.RSSI(); Serial.print("signal strength (RSSI):"); Serial.println(rssi);</p><p> // print the encryption type: byte encryption = WiFi.encryptionType(); Serial.print("Encryption Type:"); Serial.println(encryption, HEX); Serial.println(); }</p>
Step 7: Movement of Trolley Robot
Source code For the movement of Trolley robot
void runFunction()
{ Wire.begin(); // join i2c bus (address optional for master) Serial.println("sent DC speed 100"); MotorDirectionSet(0b0101); //"0b1010" defines the output polarity, "10" means the M+ is "positive" while the M- is "negtive" // make sure M+ and M- is different polatity when driving DC motors. MotorSpeedSetAB(100,100);//defines the speed of motor 1 and motor 2;//0b0101 Rotating in the opposite direction }
//Function to set the 2 DC motor speed //motorSpeedA : the DC motor A speed; should be 0~100; //motorSpeedB: the DC motor B speed; should be 0~100;
void MotorSpeedSetAB(unsigned char MotorSpeedA , unsigned char MotorSpeedB) { MotorSpeedA=map(MotorSpeedA,0,100,0,255); MotorSpeedB=map(MotorSpeedB,0,100,0,255); Wire.beginTransmission(I2CMotorDriverAdd); // transmit to device I2CMotorDriverAdd Wire.write(MotorSpeedSet); // set pwm header Wire.write(MotorSpeedA); // send pwma Wire.write(MotorSpeedB); // send pwmb Wire.endTransmission(); // stop transmitting } //set the prescale frequency of PWM, 0x03 default; void MotorPWMFrequenceSet(unsigned char Frequence) { Wire.beginTransmission(I2CMotorDriverAdd); // transmit to device I2CMotorDriverAdd Wire.write(PWMFrequenceSet); // set frequence header Wire.write(Frequence); // send frequence Wire.write(Nothing); // need to send this byte as the third byte(no meaning) Wire.endTransmission(); // stop transmitting } //set the direction of DC motor. void MotorDirectionSet(unsigned char Direction) { // Adjust the direction of the motors 0b0000 I4 I3 I2 I1 Wire.beginTransmission(I2CMotorDriverAdd); // transmit to device I2CMotorDriverAdd Wire.write(DirectionSet); // Direction control header Wire.write(Direction); // send direction control information Wire.write(Nothing); // need to send this byte as the third byte(no meaning) Wire.endTransmission(); // stop transmitting }
void MotorDriectionAndSpeedSet(unsigned char Direction,unsigned char MotorSpeedA,unsigned char MotorSpeedB) { //you can adjust the driection and speed together MotorDirectionSet(Direction); MotorSpeedSetAB(MotorSpeedA,MotorSpeedB); }
Step 8: Robotic Arm Movement
Arduino source code for the movement of Robotic Arm / Servo Motor
#include<Servo.h>
Servo servo_1; Servo servo_2; Servo servo_3; Servo servo_4; Servo servo_5; int servo1_pos = 0; int servo2_pos = 0; int servo3_pos = 0; int servo4_pos = 0;
servo_4.attach(9);
for(servo4_pos =175; servo4_pos >= 30; servo4_pos--) { servo_4.write(servo4_pos); delay(20); //Serial.println("inside servo 4 "); } servo_4.detach(); delay(1000); servo_1.attach(3); for(servo1_pos =5; servo1_pos <= 100; servo1_pos++) { servo_1.write(servo1_pos); delay(20); } servo_1.detach(); delay(1000);
delay(1000); servo_1.attach(3); for(servo1_pos =100; servo1_pos >= 5; servo1_pos--) { servo_1.write(servo1_pos); delay(20); } delay(1000);
servo_4.attach(9);
for(servo4_pos =30; servo4_pos <= 175; servo4_pos++) { servo_4.write(servo4_pos); delay(20); Serial.println("inside servo 4 "); } servo_4.detach(); //break; delay(1000); servo_1.attach(3); for(servo1_pos =5; servo1_pos <= 100; servo1_pos++) { servo_1.write(servo1_pos); delay(20); } for(servo1_pos =100; servo1_pos >= 5; servo1_pos--) { servo_1.write(servo1_pos); delay(20); } servo_1.detach(); delay(1000);
Step 9: Android Application
Android Application is for shops. In that App, all the groceries in the shop are listed and users can select it through the App. After confirmation of product selection, the shopping robot will move and find the products and after picking all the items, the cart will send the information to the customer (not included now) and send the billing info to the customer and billing desk (not included now). In the technical perspective, the app will publish the message via MQTT to the edison. Edison will subscribe the data and works according to the instruction.
Source Code :- MQTT Message Publish in Android
private void addPublishButtonListener() { buy=(FancyButton)findViewById(R.id.buy); buy.setOnClickListener(new OnClickListener() { //InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); @Override public void onClick(View arg0) { // EditText t = (EditText) findViewById(R.id.EditTextTopic); // EditText m = (EditText) findViewById(R.id.editTextMessage); // TextView result = (TextView) findViewById(R.id.textResultStatus); // inputMethodManager.hideSoftInputFromWindow(result.getWindowToken(), 0); String topic = "inTopic"; String message = "a"; if (topic != null && topic.isEmpty() == false && message != null && message.isEmpty() == false) { //result.setText(""); Bundle data = new Bundle(); data.putCharSequence(MQTTservice.TOPIC, topic); data.putCharSequence(MQTTservice.MESSAGE, message); Message msg = Message.obtain(null, MQTTservice.PUBLISH); msg.setData(data); msg.replyTo = serviceHandler; try { service.send(msg); } catch (RemoteException e) { e.printStackTrace(); // result.setText("Publish failed with exception:" + e.getMessage()); } } else { // result.setText("Topic and message required."); } } }); }</p>
Attachments
Step 10: Final Intel Edison Arduino Code
This is the Final Arduino Source code. You can also use cloud connectivity instead of this local connectivity. To do cloud integration, you have to choose IBM Bluemix or any other source.
Hope you enjoyed. Don't forget to mention your valuable comment !!! and Follow me for future updates.
<br><p>#define uchar unsigned char #define uint unsigned int Servo servo_1; Servo servo_2; Servo servo_3; Servo servo_4; Servo servo_5; int servo1_pos = 0; int servo2_pos = 0; int servo3_pos = 0; int servo4_pos = 0; //数组最大长度 #define MAX_LEN 16</p><p>///////////////////////////////////////////////////////////////////// //set the pin ///////////////////////////////////////////////////////////////////// const int chipSelectPin = 10; const int NRSTPD = 5;</p><p>//MF522命令字 #define PCD_IDLE 0x00 //NO action;取消当前命令 #define PCD_AUTHENT 0x0E //验证密钥 #define PCD_RECEIVE 0x08 //接收数据 #define PCD_TRANSMIT 0x04 //发送数据 #define PCD_TRANSCEIVE 0x0C //发送并接收数据 #define PCD_RESETPHASE 0x0F //复位 #define PCD_CALCCRC 0x03 //CRC计算</p><p>//Mifare_One卡片命令字 #define PICC_REQIDL 0x26 //寻天线区内未进入休眠状态 #define PICC_REQALL 0x52 //寻天线区内全部卡 #define PICC_ANTICOLL 0x93 //防冲撞 #define PICC_SElECTTAG 0x93 //选卡 #define PICC_AUTHENT1A 0x60 //验证A密钥 #define PICC_AUTHENT1B 0x61 //验证B密钥 #define PICC_READ 0x30 //读块 #define PICC_WRITE 0xA0 //写块 #define PICC_DECREMENT 0xC0 //扣款 #define PICC_INCREMENT 0xC1 //充值 #define PICC_RESTORE 0xC2 //调块数据到缓冲区 #define PICC_TRANSFER 0xB0 //保存缓冲区中数据 #define PICC_HALT 0x50 //休眠</p><p>//和MF522通讯时返回的错误代码 #define MI_OK 0 #define MI_NOTAGERR 1 #define MI_ERR 2</p><p>//------------------MFRC522寄存器--------------- //Page 0:Command and Status #define Reserved00 0x00 #define CommandReg 0x01 #define CommIEnReg 0x02 #define DivlEnReg 0x03 #define CommIrqReg 0x04 #define DivIrqReg 0x05 #define ErrorReg 0x06 #define Status1Reg 0x07 #define Status2Reg 0x08 #define FIFODataReg 0x09 #define FIFOLevelReg 0x0A #define WaterLevelReg 0x0B #define ControlReg 0x0C #define BitFramingReg 0x0D #define CollReg 0x0E #define Reserved01 0x0F //Page 1:Command #define Reserved10 0x10 #define ModeReg 0x11 #define TxModeReg 0x12 #define RxModeReg 0x13 #define TxControlReg 0x14 #define TxAutoReg 0x15 #define TxSelReg 0x16 #define RxSelReg 0x17 #define RxThresholdReg 0x18 #define DemodReg 0x19 #define Reserved11 0x1A #define Reserved12 0x1B #define MifareReg 0x1C #define Reserved13 0x1D #define Reserved14 0x1E #define SerialSpeedReg 0x1F //Page 2:CFG #define Reserved20 0x20 #define CRCResultRegM 0x21 #define CRCResultRegL 0x22 #define Reserved21 0x23 #define ModWidthReg 0x24 #define Reserved22 0x25 #define RFCfgReg 0x26 #define GsNReg 0x27 #define CWGsPReg 0x28 #define ModGsPReg 0x29 #define TModeReg 0x2A #define TPrescalerReg 0x2B #define TReloadRegH 0x2C #define TReloadRegL 0x2D #define TCounterValueRegH 0x2E #define TCounterValueRegL 0x2F //Page 3:TestRegister #define Reserved30 0x30 #define TestSel1Reg 0x31 #define TestSel2Reg 0x32 #define TestPinEnReg 0x33 #define TestPinValueReg 0x34 #define TestBusReg 0x35 #define AutoTestReg 0x36 #define VersionReg 0x37 #define AnalogTestReg 0x38 #define TestDAC1Reg 0x39 #define TestDAC2Reg 0x3A #define TestADCReg 0x3B #define Reserved31 0x3C #define Reserved32 0x3D #define Reserved33 0x3E #define Reserved34 0x3F //-----------------------------------------------</p><p>//---------------Servo motor ------------------- #include </p><p>#define MotorSpeedSet 0x82 #define PWMFrequenceSet 0x84 #define DirectionSet 0xaa #define MotorSetA 0xa1 #define MotorSetB 0xa5 #define Nothing 0x01</p><p>#define I2CMotorDriverAdd 0x0f // Set the address of the I2CMotorDriver</p><p>/////////////////////////////////////////////////////////////////////////////// // Enanble the i2c motor driver to drive a 4-wire stepper. the i2c motor driver will //driver a 4-wire with 8 polarity . //Direction: stepper direction ; 1/0 //motor speed: defines the time interval the i2C motor driver change it output to drive the stepper //the actul interval time is : motorspeed * 4ms. that is , when motor speed is 10, the interval time //would be 40 ms ////////////////////////////////////////////////////////////////////////////////// void StepperMotorEnable(unsigned char Direction, unsigned char motorspeed) { Wire.beginTransmission(I2CMotorDriverAdd); // transmit to device I2CMotorDriverAdd // set pwm header Wire.write(Direction); // send pwma Wire.write(motorspeed); // send pwmb Wire.endTransmission(); // stop transmitting }</p><p>////////////////////////////////////////////////////////////////////// //Function to set the 2 DC motor speed //motorSpeedA : the DC motor A speed; should be 0~100; //motorSpeedB: the DC motor B speed; should be 0~100;</p><p>void MotorSpeedSetAB(unsigned char MotorSpeedA , unsigned char MotorSpeedB) { MotorSpeedA=map(MotorSpeedA,0,100,0,255); MotorSpeedB=map(MotorSpeedB,0,100,0,255); Wire.beginTransmission(I2CMotorDriverAdd); // transmit to device I2CMotorDriverAdd Wire.write(MotorSpeedSet); // set pwm header Wire.write(MotorSpeedA); // send pwma Wire.write(MotorSpeedB); // send pwmb Wire.endTransmission(); // stop transmitting } //set the prescale frequency of PWM, 0x03 default; void MotorPWMFrequenceSet(unsigned char Frequence) { Wire.beginTransmission(I2CMotorDriverAdd); // transmit to device I2CMotorDriverAdd Wire.write(PWMFrequenceSet); // set frequence header Wire.write(Frequence); // send frequence Wire.write(Nothing); // need to send this byte as the third byte(no meaning) Wire.endTransmission(); // stop transmitting } //set the direction of DC motor. void MotorDirectionSet(unsigned char Direction) { // Adjust the direction of the motors 0b0000 I4 I3 I2 I1 Wire.beginTransmission(I2CMotorDriverAdd); // transmit to device I2CMotorDriverAdd Wire.write(DirectionSet); // Direction control header Wire.write(Direction); // send direction control information Wire.write(Nothing); // need to send this byte as the third byte(no meaning) Wire.endTransmission(); // stop transmitting }</p><p>void MotorDriectionAndSpeedSet(unsigned char Direction,unsigned char MotorSpeedA,unsigned char MotorSpeedB) { //you can adjust the driection and speed together MotorDirectionSet(Direction); MotorSpeedSetAB(MotorSpeedA,MotorSpeedB); }</p><p>//---------------Servo motor-------------------</p><p>//4字节卡序列号,第5字节为校验字节 uchar serNum[5];</p><p>uchar writeData[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100}; //初始化 100元钱 uchar moneyConsume = 18 ; //消费18元 uchar moneyAdd = 10 ; //充值10元 //扇区A密码,16个扇区,每个扇区密码6Byte uchar sectorKeyA[16][16] = {{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, //{0x19, 0x84, 0x07, 0x15, 0x76, 0x14}, {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, }; uchar sectorNewKeyA[16][16] = {{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xff, 0x07, 0x80, 0x69, 0x19, 0x84, 0x07, 0x15, 0x76, 0x14}, //you can set another ket , such as " 0x19, 0x84, 0x07, 0x15, 0x76, 0x14 " //{0x19, 0x84, 0x07, 0x15, 0x76, 0x14, 0xff,0x07,0x80,0x69, 0x19,0x84,0x07,0x15,0x76,0x14}, // but when loop, please set the sectorKeyA, the same key, so that RFID module can read the card {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xff, 0x07, 0x80, 0x69, 0x19, 0x33, 0x07, 0x15, 0x34, 0x14}, };</p><p>#include #include </p><p>// Update these with values suitable for your network. char ssid[] = "Intel_Hackathon"; // your network SSID (name) char pass[] = "Intelhack"; // your network password int status = WL_IDLE_STATUS; // the Wifi radio's status</p><p>byte server[] = {192, 168, 21, 96}; char res;</p><p>void callback(char* topic, byte* payload, unsigned int length) { // handle message arrived</p><p> Serial.print("Message arrived ["); Serial.print(topic); Serial.print("] "); for (int i = 0; i < length; i++) { Serial.print((char)payload[i]); res = (char)payload[i];</p><p> }</p><p> if (res == 'a') { // digitalWrite(3, HIGH); // turn the LED on (HIGH is the voltage level) // delay(1000);</p><p> rfidon(); // motor1.run(FORWARD); }</p><p> if (res == 'b') { // wait for a second // digitalWrite(3, LOW); Serial.print("OFF");// turn the LED off by making the voltage LOW // delay(1000); // wait for a second</p><p> //motor1.setSpeed(0); } //</p><p>}</p><p>WiFiClient wifiClient; PubSubClient client(server, 1883, callback, wifiClient); void runFunction() { Wire.begin(); // join i2c bus (address optional for master) Serial.println("sent DC speed 100"); MotorDirectionSet(0b0101); //"0b1010" defines the output polarity, "10" means the M+ is "positive" while the M- is "negtive" // // make sure M+ and M- is different polatity when driving DC motors. MotorSpeedSetAB(100,100);//defines the speed of motor 1 and motor 2; // delay(10); //this delay needed //delay(5000);</p><p> //MotorDirectionSet(0b0101); //0b0101 Rotating in the opposite direction } void setup() {</p><p> Serial.begin(9600); // RFID reader SOUT pin connected to Serial RX pin at 2400bps // start the SPI library: SPI.begin();</p><p> pinMode(chipSelectPin, OUTPUT); // Set digital pin 10 as OUTPUT to connect it to the RFID /ENABLE pin digitalWrite(chipSelectPin, LOW); // Activate the RFID reader pinMode(NRSTPD, OUTPUT); // Set digital pin 10 , Not Reset and Power-down digitalWrite(NRSTPD, HIGH);</p><p> MFRC522_Init(); //Initialize serial and wait for port to open: //Serial.begin(9600); while (!Serial) { ; // wait for serial port to connect. Needed for Leonardo only }</p><p> // check for the presence of the shield: if (WiFi.status() == WL_NO_SHIELD) { Serial.println("WiFi shield not present"); // don't continue: while (true); }</p><p> String fv = WiFi.firmwareVersion(); if ( fv != "1.1.0" ) Serial.println("Please upgrade the firmware");</p><p> // attempt to connect to Wifi network: while ( status != WL_CONNECTED) { Serial.print("Attempting to connect to WPA SSID: "); Serial.println(ssid); // Connect to WPA/WPA2 network: status = WiFi.begin(ssid, pass);</p><p> // wait 10 seconds for connection: delay(10000); }</p><p> // you're connected now, so print out the data: Serial.print("You're connected to the network"); printCurrentNet(); printWifiData();</p><p> //delay(1000);</p><p> if (!client.connected()) { Serial.println("client.connected Passed");</p><p> if (!client.connect("Arduino")) // Fails everytime right here Serial.println("client.connect FAILED");</p><p> if (!client.publish("outTopic", "hello world")) Serial.println("client.publish FAILED");</p><p> if (!client.subscribe("inTopic")) Serial.println("client.subscribe FAILED");</p><p> Serial.println("Publication and Subscription are done"); } else Serial.println("Connection Failed"); }</p><p>void loop() {</p><p> client.loop();</p><p>}</p><p>void printWifiData() { // print your WiFi shield's IP address: IPAddress ip = WiFi.localIP(); Serial.print("IP Address: "); Serial.println(ip); Serial.println(ip);</p><p> // print your MAC address: byte mac[6]; WiFi.macAddress(mac); Serial.print("MAC address: "); Serial.print(mac[5], HEX); Serial.print(":"); Serial.print(mac[4], HEX); Serial.print(":"); Serial.print(mac[3], HEX); Serial.print(":"); Serial.print(mac[2], HEX); Serial.print(":"); Serial.print(mac[1], HEX); Serial.print(":"); Serial.println(mac[0], HEX);</p><p>}</p><p>void printCurrentNet() { // print the SSID of the network you're attached to: Serial.print("SSID: "); Serial.println(WiFi.SSID());</p><p> // print the MAC address of the router you're attached to: byte bssid[6]; WiFi.BSSID(bssid); Serial.print("BSSID: "); Serial.print(bssid[5], HEX); Serial.print(":"); Serial.print(bssid[4], HEX); Serial.print(":"); Serial.print(bssid[3], HEX); Serial.print(":"); Serial.print(bssid[2], HEX); Serial.print(":"); Serial.print(bssid[1], HEX); Serial.print(":"); Serial.println(bssid[0], HEX);</p><p> // print the received signal strength: long rssi = WiFi.RSSI(); Serial.print("signal strength (RSSI):"); Serial.println(rssi);</p><p> // print the encryption type: byte encryption = WiFi.encryptionType(); Serial.print("Encryption Type:"); Serial.println(encryption, HEX); Serial.println(); }</p><p>void rfidon()</p><p>{ Serial.println("RFID is working Now");</p><p> uchar i, tmp; uchar status; uchar str[MAX_LEN]; uchar RC_size; uchar blockAddr; //选择操作的块地址0~63 String mynum = "";</p><p> //runFunction(); //寻卡,返回卡类型 status = MFRC522_Request(PICC_REQIDL, str); Serial.println(status); Serial.println(MI_OK); while (status != MI_OK) { status = MFRC522_Request(PICC_REQIDL, str); Serial.println(status); Serial.println(MI_OK); if (status == MI_OK) { Serial.println("Card detected");</p><p> status = MFRC522_Anticoll(str); memcpy(serNum, str, 5); if (status == MI_OK) { do{ Serial.println("The card's number is : "); Serial.print(serNum[0]); Serial.print(" , "); Serial.print(serNum[1], BIN); Serial.print(" , "); Serial.print(serNum[2], BIN); Serial.print(" , "); Serial.print(serNum[3], BIN); Serial.print(" , "); Serial.print(serNum[4], BIN); status = MFRC522_Request(PICC_REQIDL, str); status = MFRC522_Anticoll(str); memcpy(serNum, str, 5); //Serial.println(" ");</p><p> // Should really check all pairs, but for now we'll just use the first } while (serNum[0] != 225); if (serNum[0] == 225) { Serial.println("RFID Detected"); Serial.print(serNum[0]); MotorSpeedSetAB(0,0); servo_4.attach(9);</p><p>for(servo4_pos =175; servo4_pos >= 30; servo4_pos--) { servo_4.write(servo4_pos); delay(20); //Serial.println("inside servo 4 "); } servo_4.detach(); delay(1000); servo_1.attach(3); for(servo1_pos =5; servo1_pos <= 100; servo1_pos++) { servo_1.write(servo1_pos); delay(20); } servo_1.detach(); delay(1000);</p><p> delay(1000); servo_1.attach(3); for(servo1_pos =100; servo1_pos >= 5; servo1_pos--) { servo_1.write(servo1_pos); delay(20); } delay(1000);</p><p> servo_4.attach(9);</p><p>for(servo4_pos =30; servo4_pos <= 175; servo4_pos++) { servo_4.write(servo4_pos); delay(20); Serial.println("inside servo 4 "); } servo_4.detach(); //break; delay(1000); servo_1.attach(3); for(servo1_pos =5; servo1_pos <= 100; servo1_pos++) { servo_1.write(servo1_pos); delay(20); } for(servo1_pos =100; servo1_pos >= 5; servo1_pos--) { servo_1.write(servo1_pos); delay(20); } servo_1.detach(); delay(1000); } } // Serial.print(str[0],BIN); // Serial.print(" , "); // Serial.print(str[1],BIN); // Serial.println(" "); }</p><p> //防冲撞,返回卡的序列号 4字节</p><p> } //Serial.println(" "); MFRC522_Halt(); //命令卡片进入休眠状态</p><p>}</p><p>void Write_MFRC522(uchar addr, uchar val) { digitalWrite(chipSelectPin, LOW);</p><p> //地址格式:0XXXXXX0 SPI.transfer((addr << 1) & 0x7E); SPI.transfer(val);</p><p> digitalWrite(chipSelectPin, HIGH); }</p><p>/* * 函 数 名:Read_MFRC522 * 功能描述:从MFRC522的某一寄存器读一个字节数据 * 输入参数:addr--寄存器地址 * 返 回 值:返回读取到的一个字节数据 */ uchar Read_MFRC522(uchar addr) { uchar val;</p><p> digitalWrite(chipSelectPin, LOW);</p><p> //地址格式:1XXXXXX0 SPI.transfer(((addr << 1) & 0x7E) | 0x80); val = SPI.transfer(0x00);</p><p> digitalWrite(chipSelectPin, HIGH);</p><p> return val; }</p><p>/* * 函 数 名:SetBitMask * 功能描述:置RC522寄存器位 * 输入参数:reg--寄存器地址;mask--置位值 * 返 回 值:无 */ void SetBitMask(uchar reg, uchar mask) { uchar tmp; tmp = Read_MFRC522(reg); Write_MFRC522(reg, tmp | mask); // set bit mask }</p><p>/* * 函 数 名:ClearBitMask * 功能描述:清RC522寄存器位 * 输入参数:reg--寄存器地址;mask--清位值 * 返 回 值:无 */ void ClearBitMask(uchar reg, uchar mask) { uchar tmp; tmp = Read_MFRC522(reg); Write_MFRC522(reg, tmp & (~mask)); // clear bit mask }</p><p>/* * 函 数 名:AntennaOn * 功能描述:开启天线,每次启动或关闭天险发射之间应至少有1ms的间隔 * 输入参数:无 * 返 回 值:无 */ void AntennaOn(void) { uchar temp;</p><p> temp = Read_MFRC522(TxControlReg); if (!(temp & 0x03)) { SetBitMask(TxControlReg, 0x03); } }</p><p>/* * 函 数 名:AntennaOff * 功能描述:关闭天线,每次启动或关闭天险发射之间应至少有1ms的间隔 * 输入参数:无 * 返 回 值:无 */ void AntennaOff(void) { ClearBitMask(TxControlReg, 0x03); }</p><p>/* * 函 数 名:ResetMFRC522 * 功能描述:复位RC522 * 输入参数:无 * 返 回 值:无 */ void MFRC522_Reset(void) { Write_MFRC522(CommandReg, PCD_RESETPHASE); }</p><p>/* * 函 数 名:InitMFRC522 * 功能描述:初始化RC522 * 输入参数:无 * 返 回 值:无 */ void MFRC522_Init(void) { digitalWrite(NRSTPD, HIGH);</p><p> MFRC522_Reset();</p><p> //Timer: TPrescaler*TreloadVal/6.78MHz = 24ms Write_MFRC522(TModeReg, 0x8D); //Tauto=1; f(Timer) = 6.78MHz/TPreScaler Write_MFRC522(TPrescalerReg, 0x3E); //TModeReg[3..0] + TPrescalerReg Write_MFRC522(TReloadRegL, 30); Write_MFRC522(TReloadRegH, 0);</p><p> Write_MFRC522(TxAutoReg, 0x40); //100%ASK Write_MFRC522(ModeReg, 0x3D); //CRC初始值0x6363 ???</p><p> //ClearBitMask(Status2Reg, 0x08); //MFCrypto1On=0 //Write_MFRC522(RxSelReg, 0x86); //RxWait = RxSelReg[5..0] //Write_MFRC522(RFCfgReg, 0x7F); //RxGain = 48dB</p><p> AntennaOn(); //打开天线 }</p><p>/* * 函 数 名:MFRC522_Request * 功能描述:寻卡,读取卡类型号 * 输入参数:reqMode--寻卡方式, * TagType--返回卡片类型 * 0x4400 = Mifare_UltraLight * 0x0400 = Mifare_One(S50) * 0x0200 = Mifare_One(S70) * 0x0800 = Mifare_Pro(X) * 0x4403 = Mifare_DESFire * 返 回 值:成功返回MI_OK */ uchar MFRC522_Request(uchar reqMode, uchar *TagType) { uchar status; uint backBits; //接收到的数据位数</p><p> Write_MFRC522(BitFramingReg, 0x07); //TxLastBists = BitFramingReg[2..0] ???</p><p> TagType[0] = reqMode; status = MFRC522_ToCard(PCD_TRANSCEIVE, TagType, 1, TagType, &backBits);</p><p> if ((status != MI_OK) || (backBits != 0x10)) { status = MI_ERR; }</p><p> return status; }</p><p>/* * 函 数 名:MFRC522_ToCard * 功能描述:RC522和ISO14443卡通讯 * 输入参数:command--MF522命令字, * sendData--通过RC522发送到卡片的数据, * sendLen--发送的数据长度 * backData--接收到的卡片返回数据, * backLen--返回数据的位长度 * 返 回 值:成功返回MI_OK */ uchar MFRC522_ToCard(uchar command, uchar *sendData, uchar sendLen, uchar *backData, uint *backLen) { uchar status = MI_ERR; uchar irqEn = 0x00; uchar waitIRq = 0x00; uchar lastBits; uchar n; uint i;</p><p> switch (command) { case PCD_AUTHENT: //认证卡密 { irqEn = 0x12; waitIRq = 0x10; break; } case PCD_TRANSCEIVE: //发送FIFO中数据 { irqEn = 0x77; waitIRq = 0x30; break; } default: break; }</p><p> Write_MFRC522(CommIEnReg, irqEn | 0x80); //允许中断请求 ClearBitMask(CommIrqReg, 0x80); //清除所有中断请求位 SetBitMask(FIFOLevelReg, 0x80); //FlushBuffer=1, FIFO初始化</p><p> Write_MFRC522(CommandReg, PCD_IDLE); //NO action;取消当前命令 ???</p><p> //向FIFO中写入数据 for (i = 0; i < sendLen; i++) { Write_MFRC522(FIFODataReg, sendData[i]); }</p><p> //执行命令 Write_MFRC522(CommandReg, command); if (command == PCD_TRANSCEIVE) { SetBitMask(BitFramingReg, 0x80); //StartSend=1,transmission of data starts }</p><p> //等待接收数据完成 i = 2000; //i根据时钟频率调整,操作M1卡最大等待时间25ms ??? do { //CommIrqReg[7..0] //Set1 TxIRq RxIRq IdleIRq HiAlerIRq LoAlertIRq ErrIRq TimerIRq n = Read_MFRC522(CommIrqReg); i--; } while ((i != 0) && !(n & 0x01) && !(n & waitIRq));</p><p> ClearBitMask(BitFramingReg, 0x80); //StartSend=0</p><p> if (i != 0) { if (!(Read_MFRC522(ErrorReg) & 0x1B)) //BufferOvfl Collerr CRCErr ProtecolErr { status = MI_OK; if (n & irqEn & 0x01) { status = MI_NOTAGERR; //?? }</p><p> if (command == PCD_TRANSCEIVE) { n = Read_MFRC522(FIFOLevelReg); lastBits = Read_MFRC522(ControlReg) & 0x07; if (lastBits) { *backLen = (n - 1) * 8 + lastBits; } else { *backLen = n * 8; }</p><p> if (n == 0) { n = 1; } if (n > MAX_LEN) { n = MAX_LEN; }</p><p> //读取FIFO中接收到的数据 for (i = 0; i < n; i++) { backData[i] = Read_MFRC522(FIFODataReg); } } } else { status = MI_ERR; }</p><p> }</p><p> //SetBitMask(ControlReg,0x80); //timer stops //Write_MFRC522(CommandReg, PCD_IDLE);</p><p> return status; }</p><p>/* * 函 数 名:MFRC522_Anticoll * 功能描述:防冲突检测,读取选中卡片的卡序列号 * 输入参数:serNum--返回4字节卡序列号,第5字节为校验字节 * 返 回 值:成功返回MI_OK */ uchar MFRC522_Anticoll(uchar *serNum) { uchar status; uchar i; uchar serNumCheck = 0; uint unLen;</p><p> //ClearBitMask(Status2Reg, 0x08); //TempSensclear //ClearBitMask(CollReg,0x80); //ValuesAfterColl Write_MFRC522(BitFramingReg, 0x00); //TxLastBists = BitFramingReg[2..0]</p><p> serNum[0] = PICC_ANTICOLL; serNum[1] = 0x20; status = MFRC522_ToCard(PCD_TRANSCEIVE, serNum, 2, serNum, &unLen);</p><p> if (status == MI_OK) { //校验卡序列号 for (i = 0; i < 4; i++) { serNumCheck ^= serNum[i]; } if (serNumCheck != serNum[i]) { status = MI_ERR; } }</p><p> //SetBitMask(CollReg, 0x80); //ValuesAfterColl=1</p><p> return status; }</p><p>/* * 函 数 名:CalulateCRC * 功能描述:用MF522计算CRC * 输入参数:pIndata--要读数CRC的数据,len--数据长度,pOutData--计算的CRC结果 * 返 回 值:无 */ void CalulateCRC(uchar *pIndata, uchar len, uchar *pOutData) { uchar i, n;</p><p> ClearBitMask(DivIrqReg, 0x04); //CRCIrq = 0 SetBitMask(FIFOLevelReg, 0x80); //清FIFO指针 //Write_MFRC522(CommandReg, PCD_IDLE);</p><p> //向FIFO中写入数据 for (i = 0; i < len; i++) { Write_MFRC522(FIFODataReg, *(pIndata + i)); } Write_MFRC522(CommandReg, PCD_CALCCRC);</p><p> //等待CRC计算完成 i = 0xFF; do { n = Read_MFRC522(DivIrqReg); i--; } while ((i != 0) && !(n & 0x04)); //CRCIrq = 1</p><p> //读取CRC计算结果 pOutData[0] = Read_MFRC522(CRCResultRegL); pOutData[1] = Read_MFRC522(CRCResultRegM); }</p><p>/* * 函 数 名:MFRC522_SelectTag * 功能描述:选卡,读取卡存储器容量 * 输入参数:serNum--传入卡序列号 * 返 回 值:成功返回卡容量 */ uchar MFRC522_SelectTag(uchar *serNum) { uchar i; uchar status; uchar size; uint recvBits; uchar buffer[9];</p><p> //ClearBitMask(Status2Reg, 0x08); //MFCrypto1On=0</p><p> buffer[0] = PICC_SElECTTAG; buffer[1] = 0x70; for (i = 0; i < 5; i++) { buffer[i + 2] = *(serNum + i); } CalulateCRC(buffer, 7, &buffer[7]); //?? status = MFRC522_ToCard(PCD_TRANSCEIVE, buffer, 9, buffer, &recvBits);</p><p> if ((status == MI_OK) && (recvBits == 0x18)) { size = buffer[0]; } else { size = 0; }</p><p> return size; }</p><p>/* * 函 数 名:MFRC522_Auth * 功能描述:验证卡片密码 * 输入参数:authMode--密码验证模式 0x60 = 验证A密钥 0x61 = 验证B密钥 BlockAddr--块地址 Sectorkey--扇区密码 serNum--卡片序列号,4字节 * 返 回 值:成功返回MI_OK */ uchar MFRC522_Auth(uchar authMode, uchar BlockAddr, uchar *Sectorkey, uchar *serNum) { uchar status; uint recvBits; uchar i; uchar buff[12];</p><p> //验证指令+块地址+扇区密码+卡序列号 buff[0] = authMode; buff[1] = BlockAddr; for (i = 0; i < 6; i++) { buff[i + 2] = *(Sectorkey + i); } for (i = 0; i < 4; i++) { buff[i + 8] = *(serNum + i); } status = MFRC522_ToCard(PCD_AUTHENT, buff, 12, buff, &recvBits);</p><p> if ((status != MI_OK) || (!(Read_MFRC522(Status2Reg) & 0x08))) { status = MI_ERR; }</p><p> return status; }</p><p>/* * 函 数 名:MFRC522_Read * 功能描述:读块数据 * 输入参数:blockAddr--块地址;recvData--读出的块数据 * 返 回 值:成功返回MI_OK */ uchar MFRC522_Read(uchar blockAddr, uchar *recvData) { uchar status; uint unLen;</p><p> recvData[0] = PICC_READ; recvData[1] = blockAddr; CalulateCRC(recvData, 2, &recvData[2]); status = MFRC522_ToCard(PCD_TRANSCEIVE, recvData, 4, recvData, &unLen);</p><p> if ((status != MI_OK) || (unLen != 0x90)) { status = MI_ERR; }</p><p> return status; }</p><p>/* * 函 数 名:MFRC522_Write * 功能描述:写块数据 * 输入参数:blockAddr--块地址;writeData--向块写16字节数据 * 返 回 值:成功返回MI_OK */ uchar MFRC522_Write(uchar blockAddr, uchar *writeData) { uchar status; uint recvBits; uchar i; uchar buff[18];</p><p> buff[0] = PICC_WRITE; buff[1] = blockAddr; CalulateCRC(buff, 2, &buff[2]); status = MFRC522_ToCard(PCD_TRANSCEIVE, buff, 4, buff, &recvBits);</p><p> if ((status != MI_OK) || (recvBits != 4) || ((buff[0] & 0x0F) != 0x0A)) { status = MI_ERR; }</p><p> if (status == MI_OK) { for (i = 0; i < 16; i++) //向FIFO写16Byte数据 { buff[i] = *(writeData + i); } CalulateCRC(buff, 16, &buff[16]); status = MFRC522_ToCard(PCD_TRANSCEIVE, buff, 18, buff, &recvBits);</p><p> if ((status != MI_OK) || (recvBits != 4) || ((buff[0] & 0x0F) != 0x0A)) { status = MI_ERR; } }</p><p> return status; }</p><p>/* * 函 数 名:MFRC522_Halt * 功能描述:命令卡片进入休眠状态 * 输入参数:无 * 返 回 值:无 */ void MFRC522_Halt(void) { uchar status; uint unLen; uchar buff[4];</p><p> buff[0] = PICC_HALT; buff[1] = 0; CalulateCRC(buff, 2, &buff[2]);</p><p> status = MFRC522_ToCard(PCD_TRANSCEIVE, buff, 4, buff, &unLen); }</p>