Detecting Barometer sensor in PSLab Android App

The Pocket Science Lab Android app has Barometer Instrument implemented in it. Although the instrument  is currently working through the mobile sensors and not the PSLab i2c library as there were some issues in the i2c communication with PSLab device.

Thus as the barometer was completely working on through the mobile sensors, there was a major problem coming up. Majority of the mobiles don’t have the barometer sensor which was required, only a  few of the latest devices have the sensors in them.

This issues created problem as now anyone who would have used the barometer instrument would have made an impression that the App was itself not working.

Figure(1) : Showing the stagnant barometer Instrument

Thus this created a bad impression for both the app and it’s developers.

Solving the issue

To solve this major bug, it required to first detect the barometer instrument and then implementing an alert dialog-box showing that barometer sensor is not present in his device.

  • Detecting the Barometer Sensor[2]

The barometer sensor was detected using the sensorManager class of Java

sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
sensor = sensorManager != null ? sensorManager.getDefaultSensor(Sensor.TYPE_PRESSURE) : null;

Thus using this code the barometer sensor is detected, if sensor was not present the  sensorManger would be null.

  • Implementing the alert-box[1]

Thus if the sensorManger variable was null it notified that the sensor was not present in           the device and corresponding to which an alert-box was implemeneted

if (sensor == null) {
    runOnUiThread(new Runnable() {
        @Override
        public void run() {
            if (!isFinishing()) {
                new AlertDialog.Builder(BarometerActivity.this)
                    .setTitle(R.string.barometer_alert_title)
                    .setMessage(R.string.barometer_alert_description)
                    .setCancelable(false)
                    .setPositiveButton("ok", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            dialog.dismiss();
                        }
                    }).show();
            }
        }
    });

Thus as we can see in the code snippet the alert dialog-box will appear if  sensor is not present as shown in figure (2).

Figure(2) : Screenshot showing alert-box

Resources

  1. Android Alert-box Example, Mkyong.com:
    https://www.mkyong.com/android/android-alert-dialog-example/
  2. Creating a Barometer Application for Android, medium.com:
    https://medium.com/@ssaurel/creating-a-barometer-application-for-android-1c0a5c10b20e

Continue Reading

Implementing Custom Rotary Knobs and Circular Positioning in the Multimeter in the PSLab Android App

In my previous blog [2I have discussed about how to implement  normal rotary knob using an open source library, this blog will be about the new user interface (UI) of multimeter in the PSLab Android app, how a custom rotary knob is implemented in it and how how the text views are positioned circular in them.

Implementation of Custom Rotary Knob

In the PSLab device  the rotary knob is implemented using the BeppiMenozzi Knob library[1] as by doing this we don’t have to manually create the extra class for the knob and we don’t have to write the code from scratch.

Figure 1: A basic rotary knob

Figure 1 shows a basic knob implemented using the BeppiMenozzi library whereas figure 2 shows the implementation of a custom knob using the basic knob.

Figure 2: A custom Knob

Steps of making a Custom-Knob using a simple Knob

  1. Implement the the basic knob using the steps given in my previous knobs explained in my previous blogs.
  2. Download the images of the knob which has to be implemented.
android:layout_weight="1"
android:rotation="15"
app:kDefaultState="2"
app:kIndicatorWidth="@dimen/multimeter_length_0"
app:kKnobCenterColor="@color/colorPrimaryDark"
app:kKnobColor="@color/white"
app:kKnobDrawable="@drawable/knob"
  1. Using the above code amend the knob as per the requirement. The advantage of using the beppiMonzi library is that the knob is fully amenable  , we can even define the minimum and maximum angle and many more stuffs can be done using the library.

                 

 

 

 

 

Figure 3: Showing the implementation of other custom knobs

The above figure shows the example of custom knobs implemented using the simple knob and by following the steps.

Implementation Circular positioning

One of the other major issues while making the new UI of the multimeter is the positioning of text-view around the circular knob. The issue was made overcome by implementing a circular positioning constraints in the text-views.

Steps of implementing circular positioning

  1. Use the constraint layout version 1.1.0 or above as the previous versions do not support the circular positioning feature.
  2. Add the circular constraint individually to every text-view.
app:layout_constraintCircle="@id/knobs"
app:layout_constraintCircleAngle="105"
app:layout_constraintCircleRadius="@dimen/multimeter_knobcircle_radius_1"

The above code snippets shows the addition od circular constraints added to a text-view. Using these constraint it decides positions the views relative to another views at a particular angle which thus makes up circular positioning.

Thus, this is how we can implement circular positioning in the views.

Resources

  1. BeppiMenozzi Knob Library
    https://github.com/BeppiMenozzi/Knob
  2. Rotary knob Blog
    https://docs.google.com/document/d/1IU_lpdt4sHI4euM543bBlHwYpv8vwwjxoB76sW1i5HA/edit?usp=sharing

Continue Reading

Channel Communications Error of PSLab

The Pocket Science Lab multimeter has got three channels namely CH1,CH2 and CH3 with different ranges for measuring the voltages, but there was a channel communication error occuring at CH1 and CH2 pins of PSLab. This blogs will give a brief description of the channel communication error and how was it solved by me.

In the previous blog I have discussed about the channel communication of PSLab and how it works. In this blog i will be discussing about the channel communication error which was occuring while using CH1 and CH2 pins of PSLab android.

Communication between PSLab device and Android App

As discussed in the previous blog the communication between the PSLab and the android occurs with the help of the USBManger class of android.

One of the major function which makes it possible is the bulk transfer function of the android

amtWritten = mConnection.bulkTransfer(mWriteEndpoint, src, written, writeLength, timeoutMillis);

As shown in the above code, there is a timeout that some time required for this function to be executed, and otherwise this function will return a negative value which will mean that the communication is not successful.

Voltage Measuring Functions

The main function which gets called while pressing the button for measuring voltage is the getVoltage function which simultaneously calls the volmeterAutoRange function as well as the getAverage voltage function. The voltageAutoRnge function also calls the getAverage function inside of it.

public double getVoltage(String channelName, Integer sample) {
    this.voltmeterAutoRange(channelName);
    double Voltage = this.getAverageVoltage(channelName, sample);
    if (channelName.equals("CH3")) {
        return Voltage;
    } else {
        return 2 * Voltage;
    }
}

Calling both these functions simultaneously results in calling of the bulktranfer method

VoltmeterAutoRange function:-

private double voltmeterAutoRange(String channelName) {
    if (this.analogInputSources.get(channelName).gainPGA == 0)
        return 0;
    this.setGain(channelName, 0, true);
    double V = this.getAverageVoltage(channelName, null);
    return this.autoSelectRange(channelName, V);
}

The getAverage voltage function calls the getRawableVoltage function which thus calls the USBManger class functions of read and write, thus calling the bulkTranfer function.

Thus as the bulk transfer function is called simultaneously it caused problem in communication.

Solving the issue

The communication related  issues were finally solved when these bugs were spotted, the solution to this issue is that the voltageAutoRange function’s return value was never used in the codes and was thus not required.[2]The voltageAutoRange function was calling the getAverageVoltage function just to get a return value. Thus I formatted the function and now it looks like this-

private void voltmeterAutoRange(String channelName) {
    if (this.analogInputSources.get(channelName).gainPGA != 0) {
        this.setGain(channelName, 0, true);
    }
}

And thus finally the issue was solved and all things were working fine in channel communication.

Resources

Continue Reading

Using RealmRecyclerView Adapter to show list of recorded sensor data from Realm Database

In previous blog Storing Recorded Sensor Data in Realm Database we have stored the data fetched from sensors into the Realm Database by defining model classes.

In this blog, we will use the data stored in the Realm to display a list of recorded experiments in the form of well defining card view items so that it is easier for the user to understand.

For showing the list we will make use of RecyclerView  widget provided by Android which is a more advanced version of the List view and is used to display large data sets in a vertical list, horizontal list, grid, staggered grid etc.

RecyclerView  works in accordance with RecyclerView Adapter which is core engine that is responsible of inflating the layout of list items, populating the items with data, recycling of list item views when they go out of viewing screen and much more.

For this blog, we are going to use a special RecyclerView Adapter provided by Realm itself because it integrates properly with the Realm Database and handles modifying, addition, deletion or updating of Realm data automatically and efficiently.   

Step 1 Adding the dependencies

As always first we need to add the following code in our build.gradle file to add the dependency of Realm database and RealmRecyclerViewAdapter.

dependencies {
   implementation"com.android.support:recyclerview-v7:27.1.1 "
   implementation 'io.realm:android-adapters:2.1.1'
}

Step 2 Adding RecyclerView widget in our Activity layout file

First, we need to create an activity and name it as “DataLoggerActivity”, inside the layout of the Activity add the <RecyclerView> widget. This RecyclerView will act as a container of our list item.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    tools:context=".activity.DataLoggerActivity">

    <android.support.v7.widget.RecyclerView
        android:layout_below="@id/top_app_bar_layout"
        android:id="@+id/recycler_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
</RelativeLayout>

Step 3 Creating the layout and View holder for the list item

We have to create the layout of the list item which will be inflated by the Adapter. So for this create an XML file in res folder and name it “data_list_item.xml”. For the list of the experiments, we want to show Name of the experiment, recording time, recording date for every list item. For this we will make use of <CardView> and <TextView>. This gist shows the code of xml file.

The layout of the list item created is shown in Figure 2

Figure 1 Layout of list item showing mock information

Now we need to create a view holder for this layout which we need to pass to the Adapter, the following code shows the implementation of View Holder for above list item layout.

public class ViewHolder extends RecyclerView.ViewHolder {
   private TextView sensor, dateTime;
   ImageView deleteIcon;
   private CardView cardView;

   public ViewHolder(View itemView) {
       super(itemView);
       dateTime = itemView.findViewById(R.id.date_time);
       sensor = itemView.findViewById(R.id.sensor_name);
       deleteIcon = itemView.findViewById(R.id.delete_item);
       cardView = itemView.findViewById(R.id.data_item_card);
   }
}

Step 4 Creating the adapter for RecyclerView  

In this step, we will start by creating a class called “SensorLoggedListAdpater” and for using use the RecyclerView adapter provided by Realm we need to make this class extend the RealmRecyclerViewAdpater class.

But for that we need to pass two generic parameter:

  1. Model Class : This is class which define a Realm model, for this, we will pass a reference of “SensorLogged.class” which is defined in the previous blog as we want to show the list experiments which are stored using “SensorLogged” model class.
  2. ViewHolder : For this, we will pass the ViewHolder that we have created in Step 3.

As every RecyclerView Adapter needs a arraylist which contains the list of object containing information which we have to populate on the list item, the RealmRecyclerViewAdpater needs data in form of RealmResult to operate on, so we will create a constructor and pass in the RealmResult list in the super() method which we need to provide when we initialize this adapter in our “DataLoggerActivity” class.

public SensorLoggerListAdapter(RealmResults<SensorLogged> list, Activity context) {
   super(list, true, true);
   this.context = context;
   realm = Realm.getDefaultInstance();
}

Now we need to override two methods provided by RealmRecyclerViewAdapter class that are:

  1. public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType): In which we will inflate the layout of list item “dta_list_tem.xml” which we have created in Step 3.
  2. public void onBindViewHolder(@NonNull final ViewHolder holder, int position): In which we will populate the list item view using references stored in the ViewHolder with the data which we have provided while initializing the adapter.
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
   View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.logger_data_item, parent, false);
   return new ViewHolder(itemView);
}

@Override
public void onBindViewHolder(@NonNull final ViewHolder holder, int position) {
   SensorLogged temp = getItem(position);
   holder.sensor.setText(temp.getSensor());
   Date date = new Date(temp.getDateTimeStart());
   holder.dateTime.setText(String.valueOf(sdf.format(date)));
}

Step 5 Initializing the Adapter in Data Logger Activity and connecting with RecyclerView

Now we head to our Data Logger Activity, here in OnCreate() method first we will create a object of RecyclerView, then we will initialize our adapter by passing the RealmResult<SensorLogged> list which we have queried from the Realm Database.

Then we will set the LinearLayoutManager and finally, we will connect the the Adapter with the RecyclerView.

@Override
protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   setContentView(R.layout.activity_data_logger);
   ButterKnife.bind(this);

   Realm realm = Realm.getDefaultInstance();

   RealmResults<SensorLogged> results;
   String title;
  
   results = realm.where(SensorLogged.class)
           .findAll()
           .sort("dateTimeStart", Sort.DESCENDING);

   SensorLoggerListAdapter adapter = new SensorLoggerListAdapter(results, this);
   LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);

   recyclerView.setLayoutManager(linearLayoutManager);

   recyclerView.setAdapter(adapter);
}

After following all the above steps we have finally a activity as shown in Figure 4.

Figure 2 showing a list of recorded experiments with the instrument
name and date time of an experiment

Thus we have successfully displayed a list of the experiments from the data stored in the Realm Database using RealmRecyclerViewAdapter.

Resources

  1. https://academy.realm.io/posts/android-realm-listview/ – Blog on creating a To-do list on Realm official website
  2. https://gist.github.com/Avjeet/2f350feeafff17ec855a39891d8c2d66  Gist of layout of list item used
Continue Reading

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
Continue Reading

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

Youtube Video Screencast for Wave Generator – https://www.youtube.com/watch?v=NC2T5kElWbE&t=1s

Continue Reading

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/

Continue Reading

Implementing the discrete Seekbar for Wave Generator

The Wave Generator instrument in PSLab Android app allows us to produce waveforms having different values of properties like frequency, duty, phase etc.

The range of these properties allowed by PSLab Device are :

Table showing the range of properties that can be set for waves by PSLab device
Wave Property Range
Min Max Step Size
Frequency 10 Hz 5000 Hz 1 Hz
Phase 360°
Duty 10% 100% 10%

We can set these values using the up/down arrow buttons provided by the wave generator but the problem is that the range of values is very high and least counts are small so it is convenient to set the values using only the up and down arrow buttons.

Therefore we need something that could allow us to directly set any value of our choice while keeping the UI interactive.

The solution to this problem – “Discrete Seekbar”. It contains a slider having points at equal intervals and whose length represents the range of the values and a head that slides over the slider and is used to select a specific value from a range of values.

I have included the discrete Seekbar in Wave Generator by using a third-party library if you want to add Seekbar directly you can do that by directly using the default Seekbar widget provided by Android SDK and setting the following attribute in as shown below.

android:theme = “@style/Widget.AppCompat.SeekBar.Discrete”

Refer to this post[2] for implementing Seekbar directly without an external library.

The reason I chose this library is that:-

  • It offers various implementation of different types of Seekbar like discrete and continuous.
  • Implementation of Seekbar is simpler and it offers various customizations like thumb color, track color, tick text etc.  

In following steps I will implement the discrete Seekbar:

Step 1 Adding the dependency

For this project, I will be using an external library “IndicatorSeekbarLibrary” by Warkiz[1], for adding the dependency we need to include the following code in our build.gradle file.

dependencies{
implementation 'com.github.warkiz.widget:indicatorseekbar:2.0.9'
}

Step 2 Including the Seekbar in layout

For this step, we need to add the Seekbar widget using <com.warkiz.widget.IndicatorSeekBar> XML tag in our wave generator layout file to include the Seekbar in our layout as shown in the code below:

<com.warkiz.widget.IndicatorSeekBar
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:isb_max="5000"
    app:isb_min="0"
    app:isb_ticks_count="5"
    app:isb_thumb_color="@color/color_green"
    app:isb_thumb_size="20dp"
    app:isb_track_background_color="@color/color_gray"
    app:isb_track_background_size="2dp"
    app:isb_track_progress_color="@color/color_blue"
    app:isb_track_progress_size="4dp" />

Some important attributes used above:

app:isb_max : defines the max value that can be achieved by the Seekbar.

app:isb_min :  defines the min value that can be achieved by the Seekbar

app:isb_ticks_count: no. of ticks(interval) that has to be shown on the slider

We can see different components of Seekbar like track, indicator, thumb, tick of SeekBar in the following diagram[2].

Figure 1 depicts the different attributes of the slider
(Source – https://github.com/warkiz/IndicatorSeekBar/blob/master/README.md)

Step 3 Attaching the listener to the Seekbar in Java file

In this step we need to attach the listener to the Seekbar to record changes in the Seekbar made by the user, for this we will create a new listener with the help of onSeekBarChangeListener interface and attach it with the Seekbar as shown in following code

IndicatorSeekBar seekbar = (IndicatorSeekBar) findViewbyId(R.id.seekbar);

seekBar.setOnSeekChangeListener(new OnSeekChangeListener() {
            @Override
            public void onSeeking(SeekParams seekParams) {
                /* called when the user is sliding the thumb */
            }

            @Override
            public void onStartTrackingTouch(IndicatorSeekBar seekBar) {
                /* called when the sliding of thumb is started */
            }

            @Override
            public void onStopTrackingTouch(IndicatorSeekBar seekBar) {
                /* called when the sliding of thumb stops */
            }
        });

After following all the above steps, I  implemented the Seekbar shown in Figure 2 below in my wave generator and now it becomes really easy to set different values of properties for without having to continually press the up/down button.

Figure 2 shows the Seekbar included in wave generator beside up/down arrow button

Resources

  1. warkiz/IndicatorSeekBar library  – Github Repo of the Indicator SeekBar library
  2. http://nileshsenta.blogspot.com/2016/10/discrete-seekbar-without-third-party.html – Blog by Nilesh Shenta on how to implement discrete without third party library

 

Continue Reading

Making Bottomsheet responsive using Custom Gesture Detector in PSLab Android App

In the previous blog Creating Instruction Guide using Bottomsheet, I have created the Bottom Sheet guide in instrument activities in PSLab Android app. But simply adding the Bottom Sheet in the layout is not enough as it could lead to some UI issues like no proper way to show or hide the Bottom Sheet, therefore, he/she will find it difficult to work with Bottom Sheet that could degrade User Experience.

We need to make the Bottom Sheet responsive and interactive which we can do by capturing swipe gestures done by the user and overriding their functionality i.e. when the user slides up with the finger then the Bottom Sheet will reveal itself and when the user slides the finger down the Bottom Sheet will hide.

For this Android provides a class GestureDetector which is used with another class SimpleOnGestureListener which acts as a listener to capture Gesture events like swipe, pinch, scroll, long press etc.

In this blog, I will create a custom gesture listener that will listen to the swipe events and according to the gestures it will show/hide the Bottom Sheet.

I will start by creating a gesture listener class called “SwipeGestureListener” extending the class ‘GestureDetector.SimpleOnGestureListener’ and also as I need swipe gestures to control the Bottom Sheet, so I will pass the reference of the Bottom Sheet as a parameter in the constructor.

public class SwipeGestureListener extends GestureDetector.SimpleOnGestureListener{
   private  BottomSheetBehavior bottomSheet;

   public SwipeGestureDetector(BottomSheetBehavior bt) {
       bottomSheet = bt;
   }  
}

Now in this listener class as we are concerned with the swipe events so will only override the below method provided by ‘GestureDetector.SimpleOnGestureListener’ interface

public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY)

This method is called whenever the user swipes its finger in any direction.

In the above code, we can see that the method provides with object e1 and e2 of type MotionEventThe MotionEvent class is used to report movements in terms of Action Codes like ACTION_DOWN, ACTION_UP and also contains other information about the touch like the pressure of the touch, x and y coordinate, orientation of the contact area etc. 

The e1 object will have the attribute values relating to the point when the swipe started and the e2 object will have attribute values relating to the point when the swipe has ended.

Now, the main thing we need to determine if the direction of the swipe which is not directly available using the MotionEvent object.

So, to determine the direction of the swipe I will fetch the coordinates of the initial point and terminal point of the swipe using the objects initial and final point i.e., e1 and e2.

//Initial Point
float x1 = e1.getX(), y1 = e1.getY();

//Final Point
float x2 = e2.getX(), y2 = e2.getY();

Then, using these coordinates to calculate the angle of the swipe and based on the angle I will return the direction of the swipe as shown in the code below

private Direction getDirection(float x1, float y1, float x2, float y2) {

       Double angle = Math.toDegrees(Math.atan2(y1 - y2, x2 - x1));

       if (angle > 45 && angle <= 135)
           return Direction.TOP;
       if (angle >= 135 && angle < 180 || angle < -135 && angle > -180)
           return Direction.LEFT;
       if (angle < -45 && angle>= -135)
           return Direction.DOWN;
       if (angle > -45 && angle <= 45)
           return Direction.RIGHT;

       return null;     // required by java to avoid error
   }

As of now, I have the direction of the swipe so I will apply switch case and handle the swipe up and swipe down gesture as below:

  1. When the user slides up:-  Show the Bottom Sheet by changing the state of the Bottom Sheet from STATE_HIDDEN to STATE_COLLAPSED(partially viewable).
                                          
  2. When the user slides down: – Hide the Bottom Sheet by changing the state of the Bottom Sheet to STATE_HIDDEN.

For doing this, we will modify the onFIing()’ method as shown below

@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
   switch (getDirection(e1.getX(), e1.getY(), e2.getX(), e2.getY())) {
       case TOP:
           bottomSheet.setState(BottomSheetBehavior.STATE_COLLAPSED);
           return true;
       case LEFT:
           return true;
       case DOWN:
           if(bottomSheet.getState()==BottomSheetBehavior.STATE_COLLAPSED){
               bottomSheet.setState(BottomSheetBehavior.STATE_HIDDEN);
           }
           return true;
       case RIGHT:
           return true;
       default:
           return false;
   }
}

Now, the custom gesture listener is implemented but it cannot start listening to the touch event on its own, so we need to resolve this by performing the following steps:

  1. Firstly, we need to create an object of class GestureDetector and pass the current activity context and the object of class ‘SwipeGestureListener’ as parameters. Also while creating the listener for ‘SwipeGestureListener’ we need to pass the object of the Bottom Sheet in it as a parameter.

    GestureDetector gestureDetector = new GestureDetector(this, new SwipeGestureListener(bottomSheetBehavior)); 
  2. Then we need to override the ‘onTouchEvent()’ method of our Activity and pass the event which is received as a parameter to the GestureDetector.
    Doing this will pass the touch event that it received to the GestureDetector for it to handle.

    @Override
    public boolean onTouchEvent(MotionEvent event) {
       gestureDetector.onTouchEvent(event);                
       return super.onTouchEvent(event);
    }
    

The Bottom Sheet is now responsive to the gestures on the screen and this will improve the User Experience.

Resources

  1. Detect Common Gestures – Android Developer Article –  Android documentation
  2. Choreographic animations with Android’s Bottom Sheet – Blog by Orkhan Gasimli

 

Continue Reading

Submitting a Github Issue through a Google Form

The Pocket Science Lab Android app has various functionalities which have been already implemented but it been on the verge of development, many functionalities are yet to be implemented completely, one such functionality is how the users report the issues of the app, to which comes the idea of using a Google form inside the app for the users to fill it and the issue get directly opened in Github.

Submitting a Github issue through a Google forms requires two things:-

    1. A Github access token which gives access to open a new issue.
      • To generate a Github access token one must follow these steps[2]
        • Go to the personal settings.

        • Select  Developers settings option from it.
        • In Developers settings option Go to personal access tokens and generate an access token.
    1. A fully-structured Google form which has all the details about the issue i.e the title of the issue, the body of the issue, label, etc..
      • Using a Google account create a Google Form which have all the relevant questions about that issue such as title of the issue, body of the issue, label etc..

Once done with all the steps follow these steps to send a Github issue[1]

    1. Click the Responses tab, in it click the More icon.
    2. Select Choose a response destination.
    3. Select New spreadsheet: Creates a new spreadsheet in Google Sheets for responses.
    4. Click Create to create and open the sheet.

Configure the App Script Logic[1]

    1. You should have a newly created blank spreadsheet with headers automatically generated from your form.
    2. Click Tools > Script editor… to launch the App Script editor coding environment. This Script will be bound to your sheet, so you can listen for form submissions and fire off a new issue to your GitHub repo.
    3. In the script editor write the following code
function onFormSubmit(e) {

var title = e.values[1];
var body = e.values[2];
var label = "User opened issue"
var payload = {
"title": title,
"body": a_body,
"label": label,
};

var options = {
"method": "POST",
"contentType": "application/json",
"payload": JSON.stringify(payload)
};
var response = UrlFetchApp.fetch("https://api.github.com/repos/abhinavraj23/AgeGroup/issues?access_token="+ghToken, options)
}

Note:The onFormSubmit function includes an event object e, which includes the form/spreadsheet field values as a simple array with values in the same order as they appear in the spreadsheet. e.values[0] is the first spreadsheet column

The following google-app script uses GitHub Issues API for posting a new issue in Github.

4.Give your app script project a name and save it .

Set up the Trigger[1]

        1. From within the app script editor, click Resources > Current project’s triggers.
        2. Click to add a trigger
          1. Run: onFormSubmit
          2. Events: From spreadsheet, On form submit
        3. Click Save and accept any authorizations to access your forms and access web services on your behalf.
        4. This trigger will listen to form submissions and pass the data to your function, which POSTs the new issue to your GitHub repo.

Thus using these steps one can submit an issue in github through a Google Form and thus the Google Forms can be used in the app as the users can send the issues using a google form, and through this method one can also get the email-id of the user for further contact and thus this is a very  useful method.

Resources

      1. Bmcbride, google-form-to-github-issue,gist.github.com: https://gist.github.com/bmcbride/62600e48274961819084#set-up-the-trigger
      2. Github help, Creating personal access token,help.github.com: https://help.github.com/articles/creating-a-personal-access-token-for-the-command-line/

Continue Reading
  • 1
  • 2
Close Menu