Let's Make Robots!

Controlling a Raspberry Pi / Arduino Bot from the Internet Part 2 of 3

This is part two of a three part Series to explain how I control my BotTwo semi-Autonomous Robot from a webpage on the Internet. 


In Part One, we talked about the Interaction and Communications between the end user device (laptop/tablet/phone), the Web Server presenting the control panel, and the socket service listening for commands on the Robot itself.

 

This series will allow you to operate your Robot like an RC Car via the Internet.


 

 

This is the mode described here, with code examples for each programming platform.  As part of my learning process, I chose a very simple DIY approach, as opposed to a framework like node.js 

 

For the sake of completion, here is how the Raspberry Pi and Arduino are connected via I2C

 


 

 

In this posting, we will discuss how to use python on the Raspberry Pi to initialise a tcp socket listener for incoming commands from the Web Server.

 

We will take the incoming message, and repeat it via I2C to the Arduino that is managing the DC motors and wheel encoders.

 

        Note:  typically, there would be a validation step between receiving the command, and issuing it to the motor controllers.

 

You would want to ensure that the command made sense, but also ensure that it was not going to put the robot into danger.  This would include proximity / obstacle detection, as well as "cliff detection". In more advanced robots, you may also have environmental sensors that could ensure that the path chosen was safe to travel.

 

Ok... so... in my implementation, I rely heavily on the Adafruit Raspberry Pi python library for I2C communications both for existing I2C sensors, as well as for communicating with my Arduino's.  I fully admit to replicating an existing I2C sensor library, and then making it work with my motor controller Arduino.

 

Adafruit_I2C.py  provides a number of methods for sending and receiving data via I2C, in 8bit bytes, 16bit integers, or character array (python list) form.

 

I'm not going to explain how to prepare your Pi for I2C... 

 

 

 I had looked at Quick2Wire, and WiringPi, but their implementations is based on python3, whereas it appears that more I2C connectivity libraries exist for python 2.x via Adafruit.

 

Here is my stripped down "library" for sending a command string to the Arduino Motor Controller via I2C.

 

Motion.py 

#!/usr/bin/python

# Motion.py    Python library for Arduino as I2C Motor Controller.

# Copyright 2014 Michael Ball  unix_guru at hotmail dot com


from Adafruit_I2C import Adafruit_I2C


class Motion(Adafruit_I2C):

    # Minimal constants carried over from Arduino library

    MOTION_ADDRESS          = 0x33 # I2C Device Address

    MOTION_DATA             = 0x00 # Sensor data 



    def __init__(self, busnum=-1, debug=False):

        self.move = Adafruit_I2C(self.MOTION_ADDRESS, busnum, debug)


    def getMotionData(self):

        return self.move.readU8(self.MOTION_DATA) # & 0x0F

 

    # Read the Motion sensors

    def read_sensors(self):

        raw = self.move.readList(self.MOTION_DATA, 11)

        res = []

        for i in range(0, 10, 2):

            g = raw[i] | (raw[i+1] << 8) 

            res.append(g)

        return res


    # Send Commands to Motion Controller

    def write_command(self, command):

err = self.move.writeList(self.MOTION_DATA, map(ord,command))

return err


# Simple example prints wheel encoder data and then sends a 

# "Forward 200mm" command every 2 seconds:

# Please note that sending a string via I2C bus is not the most 

# efficient use of this bus.  

# Data register method will be shown in an upcoming article


if __name__ == '__main__':

    from time import sleep


    motion = Motion()

    print '[Motion lpulse/rpulse]'

    while True:

        print motion.getMotionData()

        print motion.read_sensors()

sleep(.5)

print motion.write_command("f, 200 \n\r");

        sleep(2) 

 

With no further ado... here is my python "command repeater"   aka tcp socket listener-I2C Master.

#! /usr/bin/python

#

#  Process_Socket_Commands.py   Michael Ball Feb 2014

#  Manage command/response between Arduino Motor/Sensor controller, 

#  and Raspberry Pi intelligent controller.

#  Using tcp socket listener to receive commands from end user, 

#  and I2C to communicate with Arduino


import socket               # Import socket module

import time

import thread


from Motion import Motion




####################################################################

# Global Variables

cmd_received = 0

controlCommand = ""


####################################################################

# Declare functions


# Retrieve commands from tcp socket if available, and send to I2C

def get_next_command():       


  while True:

    # Inside processing loop we wait for a connection

    client_socket, address = server_socket.accept()

    print 'Got connection from', address

    client_socket.send('Thank you for connecting')

    controlCommand = client_socket.recv(1024)


    # controlCommand is a comma separated string from the Webserver

    # that consists of a single character Command, plus a Parameter

    # Move forward 200mm  would be represented as "f,200\n\r"

    print controlCommand



    # Normally, you would insert validation checking here, 

    # like proximty / obstacle avoidance, or cliff checking



    #send command to arduino

    motion.write_command(controlCommand)


    # Read Wheel Encoder info from arduino 

    print motion.getMotionData()

    print motion.read_sensors()


    client_socket.close()                # Close the connection


            

##########################################################################

#

#This is where all the good stuff starts...

#

print 'Arduino Bot Command Processor - Feb 2014'


#  Create and open the socket will be listening on

server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

server_socket.bind(("192.168.0.105", 5000))

server_socket.listen(5)


print "Running Socket Server"


# initialize I2C Arduino motor controller - 

# Note there are no condition checks here

# a robust implementation would ensure that 

# the motor controller was actually online

motion = Motion()         


print "Arduino I2C Motor Controller Initialized"



try:

    running = True

    # Start up a Command tcp socket listener thread

    thread.start_new_thread(get_next_command, ())   


    while 1: # Continuous loop

       pass

  

except (KeyboardInterrupt, SystemExit): #when you press ctrl+c

    print "\nKilling Thread..."

    db.close()

print "Done.\nExiting."

Please read the comments.  This is a bare-bones implementation that takes a command string, and forwards it to The arduino via I2C for processing.   

 

You will need to add your proximity and safety testing to this.  As well, sending a string via I2C is not the most efficient use of the bus.   I simply did this so that I had both options available on the Arduino.

A proper Data Register method will be shown in an upcoming article.

 

As you will see in the next segment of this series,  I share the Command Interpreter / processor between the serial port and the I2C.  Commands can be received via either.

 

 

 

 

References:

 

http://dsscircuits.com/index.php/articles/78-arduino-i2c-slave-guide

http://gammon.com.au/i2c

Adafruit: Configuring the Pi for I2C

http://blog.oscarliang.net/raspberry-pi-arduino-connected-i2c/

https://wiki.python.org/moin/TcpCommunication

https://docs.python.org/3/howto/sockets.html

https://docs.python.org/2/library/socketserver.html

http://www.lucidtronix.com/tutorials/16

http://www.instructables.com/id/How-To-Make-an-Obstacle-Avoiding-Arduino-Robot/

https://github.com/adafruit/Adafruit-Raspberry-Pi-Python-Code

http://en.wikipedia.org/wiki/I%C2%B2C

http://www.robot-electronics.co.uk/acatalog/I2C_Tutorial.html

http://www.penguintutor.com/linux/raspberrypi-webserver

http://www.instructables.com/id/Raspberry-Pi-I2C-Python/?ALLSTEPS

http://raspberrypi4dummies.wordpress.com/2013/07/18/raspberry-pi-master-controls-arduino-uno-slaves-via-i2c/

 

Also read:


http://quick2wire.com/category/python/

https://github.com/quick2wire/trackbot

http://blog.chris.tylers.info/index.php?/archives/274-New-Pidora-Package-quick2wire-python-api.html

http://think-bowl.com/raspberry-pi/installing-the-think-bowl-i2c-libraries-for-python/

https://projects.drogon.net/raspberry-pi/wiringpi/i2c-library/

 

 

 


AttachmentSize
Motion.py_.txt1.49 KB
process_socket_commands.py_.txt2.48 KB

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

Sweet Guide UG. Thanks a lot. Just got my hand on a rapsberry pi, can't wait to try this out.

Ugh. Now I want to get a Pi B+. :) Not sure I mentioned lately, but I enjoy your thorough documentation, sir. Hope you're well.