Control Servo Motor movement with Raspberry Pi, ionic android and Pubnub

Control Servo Motor movement with Raspberry Pi, ionic android and Pubnub

In this tutorial, we are going to see how to control a servo motor connected to Raspberry Pi module using Pubnub and an Ionic Android App. This post is still part of the tutorial series on the home automation system. You may be asking about the importance of this post.

See also:

You may want to pan a remote camera up or down, right or left using a user interface either from a smart phone or elsewhere. If that is the case, you might want to stick around. Let me go ahead to introduce the components needed, remember all of them are available in our store:

 

Setup

  • Connect  servo motor Vcc (the redish wire) to raspberry pi 5volt pin (use either pin 2 or 4)
  • Connect servo motor GND (the brown wire) to raspberry pi GND pin ( use either pin 6, 9, 20, 25, 34 or 39)
  • Connect servo motor Data (the orange wire) to raspberry pi BCM 13 pin which is pin 33
servo raspberry pi - steinacoz
servo raspberry pi – steinacoz

 

Codes

Create a python script with any filename you desire, I am naming mine auto_control.py. Copy and paste this lines of codes:

#!/usr/bin/env python
import RPi.GPIO as GPIO
import sys
import serial
import csv


# pubnub imports
from pubnub.pubnub import PubNub
# from pubnub.pubnub import pubnub
from pubnub.callbacks import SubscribeCallback
from pubnub.enums import PNOperationType, PNStatusCategory
from pubnub.pnconfiguration import PNConfiguration

import pigpio

pi = pigpio.pi() # Connect to local Pi

GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)

pin_servoCamera = 12 #23

GPIO.setup(pin_servoCamera, GPIO.OUT)  # servo motor for camera, set as output


pi.set_PWM_frequency(pin_servoCamera, 50)
sleep(1)





# pubnub channels

CAMERA = 'CAMERA'

# pubnub messages/payload
# pubnub payloads

# operating camera
camera_Right = 'RIGHT'  # right is to sitting room
camera_Left = 'LEFT'  # left is to bedroom
#camera_up = 'UP'
#camera_down = 'DOWN'



# initialize pubnub
pnconfig = PNConfiguration()
pnconfig.subscribe_key = '***enter yours******'
pnconfig.publish_key = '***enter yours******'

pubnub = PubNub(pnconfig)



#pubnub publish
def my_publish_callback(envelope, status):
    # Check whether request successfully completed or not
    if not status.is_error():
        pass  # Message successfully published to specified channel.
    else:
        pass  # Handle message publish error. Check 'category' property to find out possible issue
        # because of which request did fail.
        # Request can be resent using: [status retry];


# pubnub subcribe to channels
class MySubscribeCallback(SubscribeCallback):

    def presence(self, pubnub, presence):
        pass

    def status(self, pubnub, status):

        if status.category == PNStatusCategory.PNUnexpectedDisconnectCategory:
            print('inside disconnected')
            pubnub.reconnect()
            
            
        elif status.category == PNStatusCategory.PNConnectedCategory:
           
            
                        
        elif status.category == PNStatusCategory.PNReconnectedCategory:
           

        elif status.category == PNStatusCategory.PNDecryptionErrorCategory:
            pass
                
        elif status.category == PNStatusCategory.PNTimeoutCategory:
                     
            pubnub.reconnect()
        
        #else:
            #logger.debug(status)
        

    def message(self, pubnub, message):

        payload = message.message
        print (payload)

            
        if payload == camera_up:
            print('is up')
            pan_Up()
            
        elif payload == camera_down:
            print('is down')
            pan_Down()



pubnub.add_listener(MySubscribeCallback())
pubnub.subscribe().channels(CAMERA).execute()




def pan_Up():
    pulsew_default = 500 # set default pulse width
    print('outside if')
    print(pi.get_servo_pulsewidth(pin_servoCamera))

    pulsew = pi.get_servo_pulsewidth(pin_servoCamera) //get the current pulse width/position

    if pulsew == 0:  //if pulse = 0, just add 500 to the pulse width. servo is off at pulse width zero to start going up 
        print('inside if be4 set')
        print(pi.get_servo_pulsewidth(pin_servoCamera))
        pi.set_servo_pulsewidth(pin_servoCamera, pulsew + 500) 
        print('inside if after set')
        print(pi.get_servo_pulsewidth(pin_servoCamera))
    elif pulsew >= 500 and pulsew <= 2300: // if pulse width is between 500 and 2300, keep going up by addin 500
        print('inside if be4 set2')
        print(pi.get_servo_pulsewidth(pin_servoCamera))
        pi.set_servo_pulsewidth(pin_servoCamera, pulsew + 500)
        print('inside if after set2')
        print(pi.get_servo_pulsewidth(pin_servoCamera))
    elif pulsew >= 2400: //we dont want to exceed 2500, so we stop going up after 2400
        print('inside elif be4 set')
        print(pi.get_servo_pulsewidth(pin_servoCamera))
   
    else:
        print('inside else 1st line')
        print(pi.get_servo_pulsewidth(pin_servoCamera))
        pulsew = pulsew_default
        print('inside else b4 set')
        print(pi.get_servo_pulsewidth(pin_servoCamera))
        pi.set_servo_pulsewidth(pin_servoCamera, pulsew + 500)
        print('inside else after set')
        print(pi.get_servo_pulsewidth(pin_servoCamera))  
        


def pan_Down():
    pulsew_default = 500 # set default pulse width
    print('outside if')
    print(pi.get_servo_pulsewidth(pin_servoCamera))
    pulsew = pi.get_servo_pulsewidth(pin_servoCamera) //get the current pulse width or position
    
    if pulsew == 0:  //if pulse = 0, servo is off at pulse width zero
        print('inside if be4 set')
        print(pi.get_servo_pulsewidth(pin_servoCamera))

    elif pulsew >= 500 and pulsew <= 2300: // if pulse width is between 500 and 2300, keep going down by subtractin 500
        print('inside if be4 set2')
        print(pi.get_servo_pulsewidth(pin_servoCamera))
        pi.set_servo_pulsewidth(pin_servoCamera, pulsew - 500)
        print('inside if after set2')
        print(pi.get_servo_pulsewidth(pin_servoCamera))
    elif pulsew >= 2400:  //servo position is already beyond 2400, minus 500 to start comin down
        print('inside elif be4 set')
        print(pi.get_servo_pulsewidth(pin_servoCamera))
        pi.set_servo_pulsewidth(pin_servoCamera, pulsew - 500)

    elif pulsew <= 500:
        print('inside elif be4 set3')
        print(pi.get_servo_pulsewidth(pin_servoCamera))
    else:
        print('inside else 1st line')
        print(pi.get_servo_pulsewidth(pin_servoCamera))
        pulsew = pulsew_default
        print('inside else b4 set')
        print(pi.get_servo_pulsewidth(pin_servoCamera))
        pi.set_servo_pulsewidth(pin_servoCamera, pulsew - 500)
        print('inside else after set')
        print(pi.get_servo_pulsewidth(pin_servoCamera))

      
      
def start_irrigation(humid, temp):
    stop_irrigation_level = 85
    if data_from_arduino_serial() < soil_moisture_threshold and temp < temp_threshold and humid < humidity_threshold:
        if GPIO.input(pin_irrigation_status): # if irrigation is  on , dont irrigate
            pubnub.publish().channel(FEEDBACKS).message(irrigation_ON_ALREADY).async(my_publish_callback)
            
        else: # if irrigation is not on , ten irrigate
            while data_from_arduino_serial() < stop_irrigation_level:
                GPIO.output(pin_irrigation_status, GPIO.HIGH)    
                pi.set_servo_pulsewidth(pin_servoValve, 0)
                
                for dc in range(500, 2200, 100):
                    pi.set_servo_pulsewidth(pin_servoValve, dc)
                    print(dc)
                    sleep(10)
    
                for dc in range(2200, 500, -100):
                    pi.set_servo_pulsewidth(pin_servoValve, dc)
                    print(dc)
                    sleep(5)
        
                    pi.set_servo_pulsewidth(pin_servoValve, 0)    
    
 





 

I tried using GPIO pulse width but the experience was horrible. Please do stay away from that in case of servos, Pigpio has the perfect pulse width for servos.

It is paramount you check the specfication of your own Servo motor, you don’t want to push yours beyond its limit.

I got this from pigpio website: The selected pulsewidth will continue to be transmitted until changed by a subsequent call to set_servo_pulsewidth.

The pulsewidths supported by servos varies and should probably be determined by experiment. A value of 1500 should always be safe and represents the mid-point of rotation.

You can DAMAGE a servo if you command it to move beyond its limits.

 

For the Ionic Android app, refer to their docs or this post on how to create a new ionic mobile app. I will just paste the relevant codes here:

src/pages/home/home.ts:

import { Component } from '@angular/core';
import { NavController } from 'ionic-angular';
import { PubNubAngular } from 'pubnub-angular2';


@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {

//pubnub channels


CAMERA:string = 'CAMERA'

//pubnub messages/payload
//pubnub payloads
//get sensors' data


//operating camera

camera_up:string = 'UP'
camera_down:string = 'DOWN'

stat: any = 'NOT CONNECTED' ;


irri:boolean = false;


  constructor(public navCtrl: NavController, private pubnub: PubNubAngular) {
     
  }

  ionViewDidLoad() {
    console.log('ionViewDidLoad Page');
    this.pubnub.init({
            subscribeKey: "***enter yours******",
            publishKey: "****enter yours******",
            ssl: true
        });

       this.pubnubAddListener()
       console.log('subcribin');
  this.pubnub.subscribe({
  channels  : [this.MODE, this.SENSORS_SOIL, this.CAMERA, this.FEEDBACKS, this.SENSOR_DATA, this.SENSORS_HUMID, this.SENSORS_TEMP, this.IRRIGATE],
  triggerEvents: true,
  withPresence: true
  });

  
console.log('subcribed');
  }



 //function to add listeners 
  pubnubAddListener(){

      var st = '';

   
    
  this.pubnub.addListener({
    message: function(m) {
        // handle message
        var channelName = m.channel; // The channel for which the message belongs
        var channelGroup = m.subscription; // The channel group or wildcard subscription match (if exists)
        var pubTT = m.timetoken; // Publish timetoken
        var msg = m.message; // The Payload

        console.log(channelName);
        console.log(m.message);
        
 
    },

    presence: function(p) {
        
    },
    status: function(s) {
        var affectedChannelGroups = s.affectedChannelGroups;
        var affectedChannels = s.affectedChannels;
        var category = s.category;
        var operation = s.operation;

        console.log(category);

        if ( category === "PNConnectedCategory") {
          console.log('connected in conected')
           this.st = 'CONNECTED';
          
        

            }

            if (category === "PNTimeoutCategory"){
                this.st = 'NOT CONNECTED' 
                
            }

            if (category === "PNReconnectedCategory"){
                 console.log('connected in conected')
                this.st = 'CONNECTED' 
                getSensorsData



            } 
            if (category === "PNNetworkIssuesCategory"){
                this.st = 'NOT CONNECTED' 
              
            } 

            if (category === "PNNetworkDownCategory"){
               this.st = 'NOT CONNECTED'
                           }

            if (category === "PNNetworkUpCategory"){
                this.st = 'NETWORK UP'
            } 

            

    }
    
});

this.stat = st



  }



  //function to publish commands
  pubnubPublishCommands(publishChannel: string, publishMessage: string):void {
      
    this.pubnub.publish(
    {
        message: publishMessage,
        channel: publishChannel

    }).then((status) => {
        console.log(status);
        this.stat = 'success in publishing';
        console.log('success');
    }).catch((error) => {
        console.log(error)
        this.stat = 'error in publishing';
        console.log('error');
    });
    

  }

  tiltUp($event): void {
   console.log('up');
   this.pubnubPublishCommands(this.CAMERA, this.camera_up); 
}

tiltDown($event): void {
   console.log('down'); 
   this.pubnubPublishCommands(this.CAMERA, this.camera_down);  
}
  




}

 

 

src/pages/home/home.html:

<ion-header>
  <ion-navbar>
    <ion-title>
      Pubnub Raspberry Servo
    </ion-title>
  </ion-navbar>
</ion-header>

<ion-content padding>
 
   

  <ion-item>
    <button ion-button color="primary" large (click)="tiltUp($event)"> Up</button>
    <button ion-button color="primary" large (click)="tiltDown($event)"> Down</button>
  </ion-item>   
  
</ion-content>

 

add this script tag to your index.html inside the <head> :

<script src="https://cdn.pubnub.com/sdk/javascript/pubnub.4.20.2.js"></script>

 

You can now test whether it was successful, run ionic serve or build the application: Don’t forget to follow this blog and our social media channels for more tutorials like these.

 

 

2 thoughts on “Control Servo Motor movement with Raspberry Pi, ionic android and Pubnub

Leave a Reply

Your email address will not be published. Required fields are marked *