Plot a Horizontal Bar Graph using MPAndroidChart Library in SUSI.AI Android App

Graphs and charts provide a visual representation of the data. They provide a clearer and quicker understanding of the impact of certain statistics. Thus, SUSI.AI Android app makes use of bar charts to display statistics related to user ratings for SUSI skills. This blog guides through the steps to create a Horizontal Bar Chart, using MPAndroidChart library, that has been used in the SUSI.AI Android app skill details page to display the five star skill rating by the users.

On vertical axis : Labels of the rating shown
On horizontal axis : Percentage of total number
of users who rated the skill with the corresponding
number of stars on the vertical axis

Step – 1 : Add the required dependencies to your build.gradle.

(a) Project level build.gradle

allprojects {
    repositories {
        maven { url 'https://jitpack.io' }
    }
}

(b) App level build.gradle

dependencies {
    implementation 'com.github.PhilJay:MPAndroidChart:v3.0.3'
}

 

Step – 2 : Create an XML layout.

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
   xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
   android:layout_height="match_parent">

    <!-- Add a Horizontal Bar Chart using MPAndroidChart library -->
    <com.github.mikephil.charting.charts.HorizontalBarChart
       android:id="@+id/skill_rating_chart"
       android:layout_width="match_parent"
       android:layout_height="match_parent" />

</android.support.constraint.ConstraintLayout>

 

Step – 3 : Create an Activity and initialize the Horizontal Bar Chart.

class MainActivity : Activity {

   lateinit var skillRatingChart : HorizontalBarChart

   override fun onCreate(savedInstanceState: Bundle?) {
       super.onCreate(savedInstanceState)
       setContentView(R.layout.chart)

       setSkillGraph( )

   }
}

 

Step – 4 : Create a method in your MainActivity to set up the basic properties and the axes.

/**
* Set up the axes along with other necessary details for the horizontal bar chart.
*/
fun setSkillGraph(){
   skillRatingChart = skill_rating_chart              //skill_rating_chart is the id of the XML layout

   skillRatingChart.setDrawBarShadow(false)
   val description = Description()
   description.text = ""
   skillRatingChart.description = description
   skillRatingChart.legend.setEnabled(false)
   skillRatingChart.setPinchZoom(false)
   skillRatingChart.setDrawValueAboveBar(false)

   //Display the axis on the left (contains the labels 1*, 2* and so on)
   val xAxis = skillRatingChart.getXAxis()
   xAxis.setDrawGridLines(false)
   xAxis.setPosition(XAxis.XAxisPosition.BOTTOM)
   xAxis.setEnabled(true)
   xAxis.setDrawAxisLine(false)


   val yLeft = skillRatingChart.axisLeft

//Set the minimum and maximum bar lengths as per the values that they represent
   yLeft.axisMaximum = 100f
   yLeft.axisMinimum = 0f
   yLeft.isEnabled = false

   //Set label count to 5 as we are displaying 5 star rating
   xAxis.setLabelCount(5)

//Now add the labels to be added on the vertical axis
   val values = arrayOf("1 *", "2 *", "3 *", "4 *", "5 *")
   xAxis.valueFormatter = XAxisValueFormatter(values)        

   val yRight = skillRatingChart.axisRight
   yRight.setDrawAxisLine(true)
   yRight.setDrawGridLines(false)
   yRight.isEnabled = false

   //Set bar entries and add necessary formatting
   setGraphData()

   //Add animation to the graph
   skillRatingChart.animateY(2000)
}


Here is the XAxisValueFormatter class that is used to add the custom labels to the vertical axis :

public class XAxisValueFormatter implements IAxisValueFormatter {

   private String[] values;

   public XAxisValueFormatter(String[] values) {
       this.values = values;
   }

   @Override
   public String getFormattedValue(float value, AxisBase axis) {
       // "value" represents the position of the label on the axis (x or y)
       return this.values[(int) value];
   }

}

 

Step – 5 : Set the bar entries.

/**
* Set the bar entries i.e. the percentage of users who rated the skill with
* a certain number of stars.
*
* Set the colors for different bars and the bar width of the bars.
*/
private fun setGraphData() {

   //Add a list of bar entries
   val entries = ArrayList<BarEntry>()
   entries.add(BarEntry(0f, 27f))
   entries.add(BarEntry(1f, 45f))
   entries.add(BarEntry(2f, 65f))
   entries.add(BarEntry(3f, 77f))
   entries.add(BarEntry(4f, 93f))

  //Note : These entries can be replaced by real-time data, say, from an API

  ......

}

 

Step – 6 : Now create a BarDataSet.

To display the data in a bar chart, you need to initialize a
BarDataSet instance. BarDataSet is the Subclass of DataSet class. Now, initialize the BarDataSet and pass the argument as an ArrayList of BarEntry object.

val barDataSet = BarDataSet(entries, "Bar Data Set")

 

Step – 7 : Assign different colors to the bars (as required).

private fun setGraphData() {
    .....

   //Set the colors for bars with first color for 1*, second for 2* and so on
      barDataSet.setColors(
              ContextCompat.getColor(skillRatingChart.context, R.color.md_red_500),
              ContextCompat.getColor(skillRatingChart.context, R.color.md_deep_orange_400),
              ContextCompat.getColor(skillRatingChart.context, R.color.md_yellow_A700),
              ContextCompat.getColor(skillRatingChart.context, R.color.md_green_700),
              ContextCompat.getColor(skillRatingChart.context, R.color.md_indigo_700)

   .....
)


Step – 8 : Populate data into Bar Chart.

To load the data into Bar Chart, you need to initialize a
BarData object  with bardataset. This BarData object is then passed into setData() method to load Bar Chart with data.

//Set bar shadows
   skillRatingChart.setDrawBarShadow(true)
   barDataSet.barShadowColor = Color.argb(40, 150, 150, 150)
   val data = BarData(barDataSet)

   //Set the bar width
   //Note : To increase the spacing between the bars set the value of barWidth to < 1f
   data.barWidth = 0.9f

   //Finally set the data and refresh the graph
   skillRatingChart.data = data
   skillRatingChart.invalidate()
}


Your Horizontal Bar Chart is now ready.
Note: You can format the labels as per your need and requirement with the help of XAxisValueFormatter.

References

Use Timber for Logging in SUSI.AI Android App

As per the official GitHub repository of Timber : “Timber is a logger with a small, extensible API which provides utility on top of Android’s normal Log class”.

It is a flexible logging library for Android which makes logging a lot more convenient.

In this blog you will learn how to use Timber in SUSI.AI Android app.

To begin, add Timber to your build.gradle and refresh your gradle dependencies.

implementation 'com.jakewharton.timber:timber:4.7.0’


Two easy steps to use Timber:

  1. Install any Tree instances that you want in the onCreate() of your application class.
  2. Call Timber’s static methods everywhere throughout the app.

You can add the following code to your application class :

@Override
   public void onCreate() {
       super.onCreate();

       …..
        
       if (BuildConfig.DEBUG) {
           Timber.plant(new Timber.DebugTree() {
               //Add the line number to the tag
               @Override
               protected String createStackElementTag(StackTraceElement element) {
                   return super.createStackElementTag(element) + ": " + element.getLineNumber();
               }
           });
       } else {
           //Release mode
           Timber.plant(new ReleaseLogTree());
       }
   }

   private static class ReleaseLogTree extends Timber.Tree {

       @Override
       protected void log(int priority, String tag, @NonNull String message,  
                                     Throwable throwable) {
           if (priority == Log.DEBUG || priority == Log.VERBOSE || priority == Log.INFO) {                           
               return;
           }

           if (priority == Log.ERROR) {
               if (throwable == null) {
                   Timber.e(message);
               } else {
                   Timber.e(throwable, message);
               }
           }
       }
   }


Timber ships with a ‘Debug Tree’ that provides all the basic facilities that you are very used to in the common Android.log framework. Timber has all the logging levels that are used in the normal Android logging framework which are as follows:

        • Log.e: Use this tag in places like inside a catch statement where you are aware that an error has occurred and therefore you’re logging an error.
        • Log.w: Use this to log stuff you didn’t expect to happen but isn’t necessarily an error.
        • Log.i: Use this to post useful information to the log. For instance, a message that you have successfully connected to a server.
        • Log.d: Use this for debugging purposes. For instance, if you want to print out a bunch of messages so that you can log the exact flow of your program or if you want to keep a log of variable values.
        • Log.v: Use this if, for some reason, you need to log every little thing in a particular part of your app.
        • Log.wtf: Use this when you encounter a terrible failure.

       

    • You can use Timber.e, Timber.w, Timber.i, Timber.d and Timber.v respectively for the logging levels mentioned above. However, there is a small difference. In Android logging framework the exception is passed as the last parameter. But, when using Timber, you need to provide the exception as the first parameter. Interestingly, while using Timber you don’t have to provide a TAG in logging calls because it automatically does that for you. It uses the file name, where you are logging from, as the TAG. To log an exception you can simply write:
    • Timber.e(exception, "Message");
      
    • Or a null message if you want:
    • Timber.e(exception, null);
      
    • A simple message can be logged sent via Crashlytics too:
    • Timber.e("An error message");
      

Did you notice? There is no TAG parameter. It is automatically assigned as the caller class’ name. Now, you can use Timber for logging in SUSI Android app.

Reference :

 

Implementing Settings for Lux Meter Instrument in PSLab Android App

In PSLab android app, we have included sensor instruments which use either inbuilt sensor of smartphone or external sensor to record sensor data. For example, Lux Meter uses the light sensor to record lux data but the problem is that these instruments doesn’t contain settings option to configure the sensor record-setting like which sensor to use, change the update period etc.

Therefore, we need to create a settings page for the Lux Meter instrument which allows the user to modify the properties of the sensor instrument. For that I will use Android Preference APIs to build a settings interface that is similar to setting activity in any other android app.

The main building block of the settings activity is the Preference object. Each preference appears as a single setting item in an activity and it corresponds to key-value pair which stores the settings in default Shared Preferences file. Every time any setting is changed by the user the Android will store the updated value of the setting in the default shared preferences which we can read in any other activity across the app.

In the following steps I will describe instruction on how to create the setting interface in Android app: 

Step1 Include the dependency

First, we need to include the dependency for v7 Preference Support Library by including the following code:

dependencies { 
compile fileTree(dir: 'libs', include: ['*.jar']) 
compile 'com.android.support:appcompat-v7:23.1.1' 
compile 'com.android.support:design:23.1.1' 
compile 'com.android.support:preference-v7:23.1.1' 
}

 Step 2 Creating the preferences screen in XML

For this step, I have created a preference screen which will be inflated when the settings fragment is being created.

I created a file named  “lux_meter_settings.xml” and place it in the res/xml/ directory.

The root node for the XML file must be a <PreferenceScreen> element. We have to add each Preference within this element. Each child I added within the <PreferenceScreen> element appears as a single item in the list of settings.

The preference which I have used are:

<EdittextPreference> This preference opens up a dialog box with edit text and stores whatever value is written by the user in the edit text. I have used this preference for inputting update period and high limit of data during recording.

<CheckboxPreference> shows an item with a checkbox for a setting that is either enabled or disabled. The saved value is a boolean (true if it’s checked). I have used this preference for enabling or disabling location data with the recorded data.

<ListPreference> opens a dialog with a list of radio buttons. The saved value can be any one of the supported value types. I have used this preference to allow the user to choose between multiple sensor types.

<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
       <EditTextPreference
           android:key="setting_lux_update_period"
           android:title="@string/update_period"
           android:dialogTitle="@string/update_period"
           android:defaultValue="1000"
           android:dialogMessage="Please provide time interval(in ms) at which data will be updated"
           android:summary="Update period is 900ms"/>

       <EditTextPreference
           android:key="setting_lux_high_limit"
           android:title="High Limit"
           android:dialogTitle="High Limit"
           android:defaultValue="2000"
           android:dialogMessage="Please provide maximum limit of LUX value to be recorded"
           android:summary="High Limit is 2000 Lux"/>

       <CheckBoxPreference
           android:defaultValue="false"
           android:key="include_location_sensor_data"
           android:summary="Include the location data in the logged file"
           android:title="Include Location Data" />
</PreferenceScreen>

The above XML file will produce a layout as shown in Figure 1 below:

Figure 1 shows a preview of settings layout in Android Studio

 

Step 3 Implementing the backend of setting interface

As android Documentation clearly states:

As your app’s settings UI is built using Preference objects instead of View objects, you need to use a specialized Activity or Fragment subclass to display the list settings:

  • If your app supports versions of Android older than 3.0 (API level 10 and lower), you must build the activity as an extension of the PreferenceActivity class.
  • On Android 3.0 and later, you should instead use a traditional Activity that hosts a PreferenceFragment that displays your app settings.

Therefore, I first created an Activity named “SettingsActivity” which will act as a host for a Fragment. This gist contains code for SettingsActivity which I defined in the PSLab android app which will show the Setting Fragment.

Now, for setting fragment I have created a new fragment and name it “LuxMeterSettingsFragment” and make that fragment class extends the PreferenceFragmentCompat class and for which I needed to add this import statement.

import android.support.v7.preference.PreferenceFragmentCompat;

And then inside the SettingsFragment, I overridden the following method like this:

@Override
public void onCreatePreferences(Bundle savedInstanceState,
                                String rootKey) {
    setPreferencesFromResource(R.xml.lux_meter_settings, rootKey);
}

This method is called when the Android is creating the Preferences that is when we need to call the method ‘setPreferencesFromResource()’ and pass the resource file in which we have defined our preferences along with the root key which comes as a parameter. Here, the Android will create preferences referred by the key which we have provided and initialize it to the default value in the default SharedPreferences file.

Step 4 Providing setting option to navigate to setting activity

First I included a setting option in the menu file which is getting inflated in the Lux Meter Activity toolbar as shown in below code.

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res-auto">
  
   ...

   <item
       android:id="@+id/settings"
       android:title="@string/lux_meter_settings"
       app:showAsAction="never" />
</menu>

Then, heading over to  Lux Meter Activity in the onOptionItemSelected() method I added below code in which I created intent to open Setting Activity when the setting option is selected.

@Override
public boolean onOptionsItemSelected(MenuItem item) {
case R.id.settings:
   Intent settingIntent = new Intent(this, SettingsActivity.class);
   settingIntent.putExtra("title", "Lux Meter Settings");
   startActivity(settingIntent);
   break;
}

After this step, we can see the settings option in Lux Meter Activity as shown in Figure 2

Figure 2 shows the setting option in the overflow menu

 

To see if its working opens the app -> open Lux Meter Instrument-> Open Overflow Menu -> click on Lux Meter Setting Option to open settings.

Here we can the Lux Meter Setting as shown by the Figure 3.

Figure 3 shows the screenshot of the Lux Meter Setting activity on the actual device

 

Step 5 Implementing listener for change in Preferences item

Now we can also implement a listener by making SettingsFragment class implement SharedPreference.OnSharedPreferenceChangeListener interface and then overriding the onSharedPreferenceChanged() method.

Now, to register this listener with the Preference Screen which we will do it in the onResume() method of the fragment and deregister the listener in the onPause() method to correspond with the lifecycle of the fragment.

@Override
public void onResume() {
   super.onResume();
      
getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
}
@Override
public void onPause() {
   super.onPause();
        getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this);
}

Thus we have successfully implemented settings for the Lux Meter Instrument.

Resources

  1. Adding Settings to an App – Google Developer Fundamental Course Article on how to add settings.
  2. Gist – Setting Activity implementation – The gist used for setting activity in the app

Paypal Integration in Open Event Server

The Open Event Server enables organizers to manage events from concerts to conferences and meetups. It offers features for events with several tracks and venues. This blog post explains how Paypal has been integrated in the Open Event Server in order to accept payments for tickets.

The integration of Paypal in the server involved the following steps:

  1. An endpoint to accept the Paypal token from the client applications.
  2. Using the token to get the approved payment details.
  3. Capturing the payment using the fetched payment details.

Endpoint for Paypal token

The server exposes an endpoint to get the Paypal token in order to accept payments.

api.route(ChargeList, ‘charge_list’, ‘/orders/<identifier>/charge’, ‘/orders/<order_identifier>/charge’)

The above endpoint accepts the Paypal token and uses that to get the payment details from Paypal and then capture the payments.

Getting Approved Payment Details

We use the Paypal Name-Value pair API in the project. First we get the credentials of the event organizer who will be accepting the payments using a call to the get_credentials helper method. It returns the data as the following dictionary:

credentials = {
  'USER': settings['paypal_live_username'],
  'PWD': settings['paypal_live_password'],
  'SIGNATURE': settings['paypal_live_signature'],
  'SERVER': 'https://api-3t.paypal.com/nvp',
  'CHECKOUT_URL': 'https://www.paypal.com/cgi-bin/webscr',
  'EMAIL': '' if not event or not event.paypal_email or event.paypal_email == "" else event.paypal_email
}

Next, we use the credentials to get the approved payment details from paypal using the following code snippet.

@staticmethod
def get_approved_payment_details(order, credentials=None):
   if not credentials:
     credentials = PayPalPaymentsManager.get_credentials(order.event)

   if not credentials:
     raise Exception('PayPal credentials have not been set correctly')

   data = {
            'USER': credentials['USER'],
            'PWD': credentials['PWD'],
            'SIGNATURE': credentials['SIGNATURE'],
            'SUBJECT': credentials['EMAIL'],
            'METHOD': 'GetExpressCheckoutDetails',
            'VERSION': PayPalPaymentsManager.api_version,
            'TOKEN': order.paypal_token
   }

   if current_app.config['TESTING']:
      return data

   response = requests.post(credentials['SERVER'], data=data)
   return json.loads(response.text)

Capturing the payments

After successfully fetching the payment details, the final step is to capture the payment. We set the amount to be charged to the amount of the order and the payer_id to be the payer id received from step 2. Then we simply make a POST request to the Paypal nvp server and capture the payments. The below method is responsible for executing this task:

@staticmethod
def capture_payment(order, payer_id, currency=None, credentials=None):
  if not credentials:
    credentials = PayPalPaymentsManager.get_credentials(order.event)

  if not credentials:
    raise Exception('PayPal credentials have not be set correctly')

  if not currency:
    currency = order.event.payment_currency

  if not currency or currency == "":
    currency = "USD"

   data = {
            'USER': credentials['USER'],
            'PWD': credentials['PWD'],
            'SIGNATURE': credentials['SIGNATURE'],
            'SUBJECT': credentials['EMAIL'],
            'METHOD': 'DoExpressCheckoutPayment',
            'VERSION': PayPalPaymentsManager.api_version,
            'TOKEN': order.paypal_token,
            'PAYERID': payer_id,
            'PAYMENTREQUEST_0_PAYMENTACTION': 'SALE',
            'PAYMENTREQUEST_0_AMT': order.amount,
            'PAYMENTREQUEST_0_CURRENCYCODE': currency,
   }

   response = requests.post(credentials['SERVER'], data=data)
   return json.loads(response.text)

References

Charges Layer in Open Event Server

The Open Event Server enables organizers to manage events from concerts to conferences and meetups. It offers features for events with several tracks and venues. This blog post explains how the charge layer has been implemented in the Open Event Server in order to charge the user for tickets of an event.

Schema

We currently support payments via Stripe and Paypal. As a result the schema for Charges layer consists of fields for providing the token for stripe or paypal. It also contains a read only id field.

class ChargeSchema(Schema):
    """
    ChargeSchema
    """

    class Meta:
        """
        Meta class for ChargeSchema
        """
        type_ = 'charge'
        inflect = dasherize
        self_view = 'v1.charge_list'
        self_view_kwargs = {'id': '<id>'}

    id = fields.Str(dump_only=True)
    stripe = fields.Str(allow_none=True)
    paypal = fields.Str(allow_none=True)

Resource

The ChargeList resource only supports POST requests since there is no need for other type of requests. We simply declare the schema, supported methods and the data layer. We also check for required permissions by declaring the decorators.

class ChargeList(ResourceList):
    """
    ChargeList ResourceList for ChargesLayer class
    """
    methods = ['POST', ]
    schema = ChargeSchema

    data_layer = {
        'class': ChargesLayer,
        'session': db.session
    }

    decorators = (jwt_required,)

Layer

The data layer contains a single method create_object which does all the heavy lifting of charging the user according to the payment medium and the related order. It first loads the related order from the database using the identifier.

We first check if the order contains one or more paid tickets or not. If not, then ConflictException is raised since it doesn’t make sense to charge a user without any paid ticket in the order. Next, it checks the payment mode of the order. If the payment mode is Stripe then it checks if the stripe_token is provided with the request or not. If not, an UnprocessableEntity exception is raised otherwise relevant methods are called in order to charge the user accordingly. A similar procedure is followed for payments via Paypal. Below is the full code for reference.

class ChargesLayer(BaseDataLayer):

    def create_object(self, data, view_kwargs):
        """
        create_object method for the Charges layer
        charge the user using paypal or stripe
        :param data:
        :param view_kwargs:
        :return:
        """
        order = Order.query.filter_by(id=view_kwargs['id']).first()
        if not order:
            raise ObjectNotFound({'parameter': 'id'},
                                 "Order with id: {} not found".format(view_kwargs['id']))
        elif order.status == 'cancelled' or order.status == 'expired':
            raise ConflictException({'parameter': 'id'},
                                    "You cannot charge payments on a cancelled or expired order")
        elif (not order.amount) or order.amount == 0:
            raise ConflictException({'parameter': 'id'},
                                    "You cannot charge payments on a free order")

        # charge through stripe
        if order.payment_mode == 'stripe':
            if not data.get('stripe'):
                raise UnprocessableEntity({'source': ''}, "stripe token is missing")
            success, response = TicketingManager.charge_stripe_order_payment(order, data['stripe'])
            if not success:
                raise UnprocessableEntity({'source': 'stripe_token_id'}, response)

        # charge through paypal
        elif order.payment_mode == 'paypal':
            if not data.get('paypal'):
                raise UnprocessableEntity({'source': ''}, "paypal token is missing")
            success, response = TicketingManager.charge_paypal_order_payment(order, data['paypal'])
            if not success:
                raise UnprocessableEntity({'source': 'paypal'}, response)
        return order

The charge_stripe_order_payment and charge_paypal_order_payment are helper methods defined to abstract away the complications of the procedure from the layer.

References

Connecting to a Raspberry Pi through a SSH connection Wirelessly

The tech stack of the SUSI.AI smart speaker project is mainly Python/Bash scripts. Every smart speaker has an essential feature that allows the user’s mobile device to connect and give instructions to the speaker wirelessly. To make this connection possible, we are trying to implement this using an SSH connection.

Why SSH?

SSH(a.k.a Secure Shell) is a cryptographic connection which allows secure transfer of data even over an unsecured connection.SSH connection even allows TCP as well as X11 forwarding which are an added bonus.

Step 1: Initial Setup

  • Both the raspberry Pi with raspbian installed and the mobile device should be on a same wireless network
  • One should have an SSH viewer like JuiceSSH(Android) and iTerminal(IOS) installed on their mobile devices
  • Now we must enable SSH on our raspberry Pi

Step 2: Enabling SSH on Raspberry PI

  • To enable SSH on your Pi , follow the steps mentioned below:
Menu > Preferences > Raspberry Pi Configuration.

Choose the interfaces tab and enable SSH

Step 3:Setting Up the client

 

  • Login to your raspberry pi as the root user (pi by default)
  • Type the following command to know the broadcasting ip address
[email protected]:hostname -I

 

  • Now , open the client on your mobile device and add the configurations

By default the username of the system is ‘pi’ and the password is ‘raspberry’

Step 4: Changing the default SSH password

Since the default password of every RaspberryPi is the same. So , the pi can be accessed by any device that has access to the local network which is not a secure way of accessing the device

  • In the SSH window type ‘passwd’
  • Type the current password
  • Type the new password
  • Re-enter the new password

Now you will be able to login to your raspberry through an SSH connection

Resources


Tags

Fossasia, gsoc, gsoc’18, susi, susi.ai, hardware,susi_linux

Producing Waveforms using Wave Generator module in the PSLab Android App

This blog will demonstrate how to produce different waveforms using the Wave Generator module in the PSLab android app and view them on the Oscilloscope.

The Wave Generator in PSLab android app is simple to use and has a UI which is similar to physical commodity wave generators. It is capable of producing different waveforms like sine, sawtooth and square wave.

Apparatus Required

Before getting started with the wave generator we require the following items:

  1. PSLab device
  2. An android phone with PSLab app installed in it.
  3. USB cable (Mini B)
  4. OTG(On the Go) wire
  5. Some connecting wires having pins at both ends

Understanding the Wave Generator Pins

Figure 1 shows the pin diagram of the PSLab device

Let me briefly explain the use of the pins that are going to be used in the Wave generator module:

S1 and S2 pins

The PSLab device contains two pins (S1, S2) which are capable of producing two independent analog waveforms (sine,  sawtooth) having different frequencies and phase offset. The frequency range is from 10Hz to 5Khz.

SQR1, SQR2, SQR3 and SQR4 pin

The SQR1 pin is used for producing the square waveform and all the SQ pins can be used together to produce four different PWM signal having the same frequency. These PWM signal can have a different duty cycle and phase.

CH1, CH2 and CH3 pin

The CH pins are used by the oscilloscope in the  PSLab android app to monitor waveform signals produced by the wave generator pins. They can be used together to simultaneously monitor multiple waveforms.

Setting up the Device

We need to connect the PSLab device with the mobile phone as shown in Figure 2 which can be done by following steps:

  1. Connect a micro USB(Mini B) to the PSLab device.
  2. Connect the other end of the micro USB cable to the OTG.
  3. Connect the OTG to the phone.
Figure 2 shows the connection of the PSLab device with the smartphone

Producing Waveforms

Now, once the device has been properly connected to the device (which is shown at the top right corner of the app), then in the instruments page scroll down to the Wave Generator card and click on it to open the WaveGenerator activity.

Figure 3 shows the instruments containing card view to all the instruments and icon to show device status

Here you will see a screen like shown in Figure 4 containing two monitors and a controlling panel with lots of buttons. Here the Waveform panel is used to control the S1 and S2 pins whose properties are shown on the left monitor screen and the Digital panel is used to control the SQR pins whose properties are shown on the right monitor screen.

Figure 4 shows the UI of the Wave Generator Activity

For sine/sawtooth wave:

Connect the S1 pin to the CH1 pin using a connecting wire, then in the Waveform panel select the Wave1 button, choose the type of waveform(either sine or sawtooth), then click on the Freq button to change the frequency of the wave, then use the Seek bar or the up/down arrow buttons to change the value of frequency and then press the set button to set the frequency for the S1 pin as shown below:

Figure 5 The GIF shows the setting of the properties of the W1 pin in the UI

Now, click the view button at bottom right corner, this will directly open the Oscilloscope provided by the PSLab android app .

Once the oscilloscope is open, check the CH1 pin from the panel in the bottom and we can see the sine wave in the monitor shown by the screen in Figure 6 and Figure 7

Figure 6 shows the screenshot of oscilloscope showing the sine wave
Figure 7 shows the screenshot of the oscilloscope showing sawtooth wave

Similarly, if you want to see two sine waves connect the S1 pin to the CH1 and connect the S2 pin to the CH2 channel , choose the wave-type for both pin, set the frequencies for both of the waves, here you can also set the phase difference between the two waves, for setting phase difference first click on Wave2 button it will enable the phase button, then click on the Phase button and set the value of phase with the help of the Seek bar.

For Square Wave

Connect the CH1 pin to the SQ1 pin, after making the connection head over to the Digital panel in the Wave Generator, ensure that the mode is selected to square, now click on the Freq button in the digital panel and set the frequency of the square wave with the help of Seek bar, then click on the Duty button and set the value of duty cycle for the square wave as shown below:

Figure 8 The GIF shows the setting of properties for producing square wave from SQ1 pin

Now, once the square wave has been set click on the view button, the oscilloscope will open then select the CH1 pin and you can see the square wave on the monitor as shown by the screen in Figure 9.

Figure 9 shows the screenshot of the square wave as shown in the oscilloscope

Thus we have produced different waveforms using PSLab wave generator module.

Resources

PSLab device pin diagram  – https://github.com/fossasia/pslab-artwork/blob/master/Sticker/pslabdesign.png

Generating a Stripe token in the Open Event Android App

To implement the payment functionality in the Open Event Android App using credit cards we are using Stripe. Let’s see how this is being done.

We are taking the sensitive information about the user like the card details and sending it to Stripe’s servers which will return a token encrypting users information which we will use to send it to the Open Event Server to complete the payment.

We need to add the library in the build.gradle file in the dependency block.

//Stripe
implementation 'com.stripe:stripe-android:6.1.2'

 

Next we add Stripe’s Card Input Widget in our layout file. This widget is used to input card details like the card number, expiry date and CVC. It automatically validates the card details. It has a minimum width of 320 px. By default we are setting it’s visibility to gone that is it won’t be visible unless the user selects the payment option.

<com.stripe.android.view.CardInputWidget
android:id="@+id/cardInputWidget"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone" />

 

The visibility of the input field for card details is determined here. We want to show the Input widget only when the user selects Stripe as the mode of payment.

override fun onItemSelected(p0: AdapterView<*>?, p1: View?, p2: Int, p3: Long) {
selectedPaymentOption = paymentOptions[p2]
if (selectedPaymentOption == "Stripe")
rootView.cardInputWidget.visibility = View.VISIBLE
else
rootView.cardInputWidget.visibility = View.GONE
}

 

Next we store the user’s card details in a variable. If any of the details be it card number, expiry date or CVC isn’t correct, the value of the variable becomes null and then we show a message to the user.

val cardDetails: Card? = cardInputWidget.card

if (cardDetails == null)
Toast.makeText(context, "Invalid card data", Toast.LENGTH_LONG).show()

 

This is the most important part where we receive the Stripe token. We are sending a request in a background thread to the Stripe servers using the Stripe API_KEY. In the onSuccess method we receive the token if everything went successfully while in the onError method we display the errors to the user.

cardDetails?.let {
context?.let { contextIt ->
Stripe(contextIt).createToken(
it,
API_KEY,
object : TokenCallback {
override fun onSuccess(token: Token) {
//Send this token to server
Toast.makeText(context, "Token received from Stripe", Toast.LENGTH_LONG).show()
}

override fun onError(error: Exception) {
Toast.makeText(context, error.localizedMessage.toString(), Toast.LENGTH_LONG).show()
}
})
}
}

 

Resources

  1. Stripe Android documentation: https://stripe.com/docs/mobile/android  
  2. Stripe Documentation: https://stripe.com/docs/quickstart
  3. Stripe Android Github: https://github.com/stripe/stripe-android

Stepper Motors Experiment with PSLab

PSLab device is capable of building up a complete science lab almost anywhere. While the privilege is mostly taken by high school students and teachers to perform scientific experiments, electronic hobbyists can greatly be influenced from the device. One of the usages is to test and debug sensors and other electronic components before actually using them in their projects. This blog will explain how steppers motors can be used with PSLab.

A stepper motor is an electromechanical device which converts electrical power into mechanical power. Also it is a brushless, synchronous electric motor that can divide a full rotation into an expansive number of steps. The stepper motor uses the theory of operation for magnets to make the motor shaft turn a precise distance when a pulse of electricity is provided. Stepper motors are similar to switched reluctance motors. [1]


Figure 1: Showing the working of a stepper motor [4]                                                      

Figure 1 shows the animation of a simplified stepper motor. Unlike a brushless DC motor which rotates continuously when a fixed DC voltage is applied to it, a step motor rotates in discrete step angles as shown in the above figure.

How Stepper Motors Work?

  • Stepper Motor works on the principle of electromagnetism.
  • Stepper motors consist of a permanent magnetic rotating shaft, called the     rotor, and electromagnets on the stationary portion that surrounds     the motor, called the stator.
  • Figure 1 illustrates one complete rotation of a stepper motor. At position 1, we can see that the rotor is beginning at the upper     electromagnet, which is currently active (has voltage applied to it).
  • To move the rotor clockwise (CW), the upper electromagnet is deactivated and the right electromagnet is activated, causing the rotor to move 90 degrees CW, aligning itself with the active magnet.
  • This process is repeated in the same manner at the south and west     electromagnets until we once again reach the starting position.

           Figure  (2): Showing different stages of stepper motors’ working cycle [3]

What are the most common reasons to choose stepper motors over other types? [2]

  1. Positioning     Since steppers move in precise repeatable steps, they excel in applications requiring precise positioning such as 3D printers, CNC, Camera platforms and X,Y Plotters. Some disk drives also use stepper motors to position the read/write head.
  2. Speed Control – Precise increments of movement also allow for excellent control of rotational speed for process automation and robotics.
  3. Low Speed Torque – Normal DC motors don’t have very much torque at low speeds. A Stepper motor has maximum torque at low     speeds, so they are a good choice for applications requiring low speed with high precision.

Applications of Stepper Motors [2]

  1. Industrial Machines – Stepper motors are used in automotive gauges and machine tooling automated production equipments.
  2. Office Equipments – Stepper motors are incorporated inside PC based scanning equipment, data storage tape drives, optical disk drive head driving mechanism, printers, bar-code printers, scanners
  3. Medical – Stepper motors are used inside medical scanners, samplers, and also found inside digital dental photography, fluid pumps, respirators and blood analysis machinery.
  4. Consumer Electronics – Stepper motors in cameras for automatic digital camera focus and zoom functions.

       

Figure  (3) :Figure showing stepper motors being used in robo -arms [5]

Implementation of Stepper Motor in PSLab

Figure  (4) :A screenshot of Stepper Motor Experiment using PSLab Android App.

  • In the PSLab the stepper motor experiment is implemented to tell the user what a stepper motor is  and how to use it.
  • There is one field to enter the number of steps i.e the breaks in one one rotation which the stepper motor will have.
  • Using PSLab device experiment “Stepper Motor”, a user can acquire any number of steps just by entering the step value in the text box.
  • The following code is implemented for executing the function.
private void setSteps() {
         int stepCount = Integer.parseInt(steps.getText().toString());
         if (stepCount > 0) {
               stepForward(stepCount);
         } else {
               stepBackward(stepCount);
         }
}
  • The other two buttons are designed for choosing the direction in which the motor  will rotate.
  • The following code is for the backward function.
private void stepBackward(final int steps) {
    java.lang.Runnable runnable = new java.lang.Runnable() {
        @java.lang.Override
        public void run() {
            scienceLab.stepBackward(steps, 100);
        }
    };
    new java.lang.Thread(runnable).start();
}
  • Thus when the stepper motor  is connected to the PSLab device and the android application experiment is made to run, the stepper motor will rotate accordingly.

Resources

  1. https://learn.adafruit.com/all-about-stepper-motors/what-is-a-stepper-motor
  2. https://www.elprocus.com/stepper-motor-types-advantages-applications/
  3. https://www.imagesco.com/articles/picstepper/02.html
  4. https://en.wikipedia.org/wiki/Stepper_motor
  5. https://www.instructables.com/id/Robot-Arm-MK2-Plus-Stepper-Motor-Used/