It is sometimes difficult to know where to put the different types of waste (metal, plastic, paper, etc.)
This project is to design a smart automatic recycling trash bin, and it is an interesting solution to a before-mentioned inconvenience that comes from recycling metal and other types of waste. By using this, we hope that the convenience of a recycling trash bin that helps users to sort the trash will inspire more people o recycle.
Smart bin offers following conveniences:
- Being able to sort metal waste
- Automatic lid for ease of use
- Assigning credits for correct sorting
Overallflow chart of the system
2.1 Ultrasonic sensor
Motion sensor or ultrasonic sensor plays an important role in this system since this sensor starts the workflow of bin. As soon as some object come close to the lid of bin, the signal comes from the movement of object will give different voltage value that is connected to the ultrasonic sensor. Before turning on to bit more deeper explanation, readers need to understand what ultrasonic sensor is. Ultrasonic sensor provides a very low-cost and easy method of distance measurement. The sensor works by creating a 10 microsecond pulse and then measuring the duration taken by that pulse to reach the object then bounce back. Now since readers have some understanding of this sensor, we are turning to internal logic of this sensor. Sensor will always active and wait for the object in range. The range is from 0 to 90 mm. When object happens to be in the scope of this range, then turn will be given to Inductive sensor, otherwise it will just ignore the object.
2.2 Inductive (metal) sensor
This project sorts the trash depending on whether metal is it or not. To differentiate metal trash from another type of trash decided to use inductive sensor from Heschen. Since it was ready and easy-to use solution to our task. So as usual, let’s have a look of what is inductive sensor and how it works. In a simple inductive sensor an electrical power supply causes an alternating current to flow in a coil. When a conductive or magnetically permeable target, such as a steel disk, approaches the coil, this changes the coil’s impedance. When limit is crossed, the led lights up notifying that the target is near. What happens when the object is in range and is metal? Lid opens and object falls into trash. Otherwise lid simply won’t open.
2.3 Servo motor
In this project, we use simple 9g SG-90 servo motor. It basically works with 2 positions. Either 0 or 180 degree. Servo motor’s only task is to open the lid when there is a metal trash on the lid. We fixed the servo by glue in the bottom of lid and attach the rope to the movable part of servo. The metallic circle is attached to other end of rope and it is fixed on the top of the lid.
2.4NFC Tag
The X-NUCLEO-NFC01A1 is a Dynamic NFC tag evaluation board to allow expansion of the STM32 Nucleo boards. It is compatible with the STM32 connector layout and it is designed around the M24SR64-Y. The M24SR64-Y device is a dynamic NFC/RFID tag IC with a dual interface.
It allows to user get credits from correct sorting via writing particular messages (“Yes” in case of correct sorting & “No” otherwise) by STM32 to NFC Tag.
3. Software ImplementationThe first step, that our smart trash bin does, is to check the presence of an object.
How we can do that?
We use an ultrasonic sensor which constantly sends signal and detect the presence of the object, first we set the distance that we want to start detecting the object, the sensor we are using has
- Theoretical Measuring Distance: 2cm to 450cm.
- Practical Measuring Distance: 2cm to 80cm.
- Accuracy: 3mm.
Now after explaining the logic let’s see the code
First import the following library
#include "ultrasonic.h"
Second define the pins, options and a pointer that points at the address of
ultrasonic mu(D8, D9, .1,1, &dist)
in this code we,
- Set the trigger pin to D8and the echo pin to D9.
- Updates every 0.1 second and a timeout after 1 second.
- Pointer at the address of dist when the distance changes.
now in our main function we start the measuring process
mu.startUpdates();
then we call the checkDistance(), we have to add inside a loop, as this is where the class checks if dist needs to be called
Now our core function dist, we add a condition when the distance is more than 90 mm we just print a statement saying the distance more than 90 mm
voiddist(int distance)
{
if (distance > 90){
pc.printf("Distance> 90 %d mm\r\n", distance);
}
.................
Otherwise, or when the distance is less than 90 mm the second step of our project comes into play.
In the second stage we use the HESCHEN INDUCTIVE PROXIMITY SENSOR to check if the object is metal or not by calling a function called inductiveTest()
else { //if (distance < 90)
pc.printf("Distance<= 90 %d mm\n\r", distance);
if(inductiveTest()) {
myled = !myled;
pc.printf("OBJECTDETECTED - Start Metal sensor\n\r");
}
}
}
inductiveTest()return true if the mySwitch is 1 (which the metal case) otherwise false
boolinductiveTest() {
if (mySwitch == 1) {
return true;
}
else {
return false;
}
}
The third step is to open the lid of the trash bin if the object is metal to do this we utilize a servo motor, first we add the following library
#include "Servo.h"
Then inside the else condition if the distance is less than 90 we add
myservo.write(0);
and to close the lid, we add the following code in the main function to move the servo again
myservo.write(180);
The last step is to connect the stm32 board with the NFC module, in this step when the ultrasonic and the inductive sensor detects a metal object the stm32 board will communicate to the NFC module to write a tag, if it is not a metal the code will send a tag with no value and our app which will be discussed next will tell the user that the object is not a metal To implement this we do the following steps
First, we import the following libraries
#include "X_NUCLEO_NFC01A1.h"
#include "NDefLib/NDefNfcTag.h"
#include "NDefLib/RecordType/RecordURI.h"
#include "NDefLib/RecordType/RecordText.h"
Next, we initialize the board by adding the following code in the main
//use defaultboard pinout
I2Ci2cChannel(X_NUCLEO_NFC01A1::DEFAULT_SDA_PIN,X_NUCLEO_NFC01A1::DEFAULT_SDL_PIN);
X_NUCLEO_NFC01A1 *nfcNucleo =X_NUCLEO_NFC01A1::Instance(i2cChannel, NULL,
X_NUCLEO_NFC01A1::DEFAULT_GPO_PIN,X_NUCLEO_NFC01A1::DEFAULT_RF_DISABLE_PIN,
X_NUCLEO_NFC01A1::DEFAULT_LED1_PIN,X_NUCLEO_NFC01A1::DEFAULT_LED2_PIN,
X_NUCLEO_NFC01A1::DEFAULT_LED3_PIN);
//retrieve the NdefLib interface
NDefLib::NDefNfcTag &tag = nfcNucleo->getM24SR().getNDefTag();
Here we faced an issue that we cannot call the function to write the tag outside of the main, so we added a flag which is always 0, unless the object is metal (we have to update our dist function also full code will be at the end)
We add the following code in the for loop
updateM24SR(nfcNucleo, "YES");
in this part we faced another issue, where the NFC module won’t start unless we press the reset button, to solve this issue we thought about two solutions
1-
Make the end user to press the button every time he/she wants to recycle (or when he/she wants to collect the credit)
2-
Add a software reset, which automatically restart the process.
For our prototype we chose the latter.
for(size_t i = 0;i < 50; i++)
{
mu.checkDistance();
printf("CheckDistance: !\n\r");
if(flag == 1)
{
updateM24SR(nfcNucleo, "YES");
printf("Insidethe write tag condition: !\n\r");
wait(2);
NVIC_SystemReset();
}
}
In all other cases hen the flag is zero, we write another flag, and through the app the end user will get a message saying the object is not metal, please recycle a metal object
// to delete the tag and not give credit
updateM24SR(nfcNucleo, "NO");
printf("not metal: !\n\r");
pc.printf("wait for 4 sec\n\r");
wait(4);
NVIC_SystemReset();
Here is the update function which will write the tag
intupdateM24SR(X_NUCLEO_NFC01A1 *nfcNucleo, char*data)
{
//retrieve the NdefLib interface
NDefLib::NDefNfcTag &tag = nfcNucleo->getM24SR().getNDefTag();
printf("System Init done: !\n\r");
/*SESSION 1*/
//open the i2c session with the nfc chip
if (tag.openSession())
{
printf("Sessionopened\n\r");
nfcNucleo->getLed1() = 1;
NDefLib::Message msg;
NDefLib::RecordText rText(data);
msg.addRecord(&rText);
if(tag.write(msg))
{
printf("Tagwritten\n\r");
nfcNucleo->getLed2() = 1;
}
else
{
printf("Errorwriting \n\r");
} //if-else
//close the i2csession
if(tag.closeSession())
{
printf("Sessionclosed\n\r");
nfcNucleo->getLed3() = 1;
}
else
{
printf("Errorclosing the session\n\r");
} //if-else
}
else
printf("Erroropening the session\n\r");
}
4. The AppFor our project, we built an app to encourage the user to recycle by giving him a credit to use. This functionality is implemented by using NFC module which is mounted on the top of the prototype bin, so the user can easily tap it with his smartphone and earn credits to receive a discount for the next purchase. The app will be composed of two activities:
- the main activity that will contain the user's information and it will wait for a tag discovering by NFC hardware;
- the second activity will consist of a simple button to retrieve the credit.
Reading NDEF data from an NFC tag is handled with the tag dispatch system, which analyzes discovered NFC tags. An application that wants to handle the scanned NFC tag can declare an intent filter and request to handle the data, so before you can access a device's NFC hardware and properly handle NFC intents, you need to declare the permission to access the NFC hardware. Thus, after you have started your Android Studio project, you have to add these items in your AndroidManifest.xml
file:
- NFC <uses-permission> element to access the NFC hardware:
<uses-permission android:name="android.permission.NFC" />
- The minimum SDK version that your application can support:
<uses-sdk android:minSdkVersion="21"/>
- The
uses-feature
element so that your application shows up in Google Play only for devices that have NFC hardware:
<uses-feature android:name="android.hardware.nfc" android:required="true" />
Since we will use MIME type of text/plain
you can declare the intent filter along with the type pf data that you want to filter for. So, you need to add:
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="text/plain" />
</intent-filter>
After this preliminary part, start modifying the main activity. Basically, what do you need to dialogue with your NFC is an NFC Adapter and a handler to manage the tag.
In our application we will be looking for ACTION_NDEF_DISCOVERED
intents, so in onCreate
method you need to add:
Intent intent = getIntent();
String action = intent.getAction();
if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action)){
parseNdefMessage(intent);}
parseNdefMessage
is a method to process the intent incoming from the discovered tag. Since we want to perform an action depending on the content of the tag, this method will parse the NDEF message: it will start a new activity if the NDEF message contains the text "YES" otherwise it will inform the user that he can't retrieve the credit (the message will contain text "NO").
void parseNdefMessage(Intent intent) {
Parcelable[] ndefMessageArray =
intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
NdefMessage ndefMessage = (NdefMessage) ndefMessageArray[0];
String msg = new String(ndefMessage.getRecords()[0].getPayload());
String nuova = msg.substring(3);
if(nuova.equals("YES")){
Intent myIntent = new Intent(MainActivity.this, RetrieveCrActivity.class);
myIntent.putExtra(EXTRA_MESSAGE, credits);
MainActivity.this.startActivity(myIntent);
} else {
Toast.makeText(getApplicationContext(),
"This is not metal!",
Toast.LENGTH_LONG).show();
}
If the text is "YES", the method will start RetrieveCrActivity
that has as its sole purpose to retrieve a credit througt a button. It was also implemented a method in onClickListener
to prevent unwanted clicks:
btnCredits.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(SystemClock.elapsedRealtime() - mLastClickTime < 1000){
return;
}
mLastClickTime = SystemClock.elapsedRealtime();
btnCredits.setEnabled(false);
valueInt++;
tvCredits.setText((String.valueOf(valueInt)));
Toast.makeText(getApplicationContext(),
"Credit Earned!",
Toast.LENGTH_LONG).show();
Intent myIntent = new Intent(RetrieveCrActivity.this,
MainActivity.class);
myIntent.putExtra("credits", valueInt);
RetrieveCrActivity.this.startActivity(myIntent);
finish();
}
5. FirebaseThe app can count on the reliability of Firebase to store user data. Firebase is a mobile development platform that offers a lot of services. For our purpose, only Authentication and Realtime Database services are needed.
Firebase Authentication aims to make building secure authentication systems easy. It provides an end-to-end identity solution, supporting email and password accounts, phone auth, and Google, Twitter, Facebook, and GitHub login, and more. We used only authentication through email and password to provide a simply access to the user to our prototype. Firebase also provide a premade UI to register new user with a check on password.
The first step is to choose what provider to use in order to authenticate (in this case email and password accounts)
List<AuthUI.IdpConfig> providers;
...
providers = Arrays.asList(new AuthUI.IdpConfig.EmailBuilder().build());
Then when the app starts the method showSignInOptions()
is called to display the Firebase UI to authenticate or register the users.
private void showSignInOptions() {
startActivityForResult(AuthUI.getInstance().createSignInIntentBuilder()
.setAvailableProviders(providers)
.setTheme(R.style.MyTheme)
.build(), MY_REQUEST_CODE);}
After the registration gone successfully, the user is registered on Firebase console:
Meanwhile the user is registered, the database is prepared to store user's information. Currently only name and credits of the users are stored on the database but adding more information is pretty simple in fact the information is stored in a Map
type:
Map newPost = new HashMap();
newPost.put("name", name);
newPost.put("credits", credit);current_user_db.setValue(newPost);
Then the information is sent to the database through setValue
method.
After the user is authenticated he can retrieve the credits that he earned from the database in this way:
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
String user_id = user.getUid();
myRef.child("Users").child(user_id).child("credits")
.addValueEventListener(new ValueEventListener(){
@Override public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
Long temp = (Long) dataSnapshot.getValue();
credits = temp.intValue();}
When he recycle and earn credits, the value is stored on the database:
credits = extras.getInt("credits");
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
String user_id = user.getUid();DatabaseReference current_user_db = FirebaseDatabase.getInstance().getReference().child("Users").child(user_id);
HashMap map = new HashMap();
map.put("credits", credits);
current_user_db.updateChildren(map);
Comments