Smooth movement with servos

One of the main problems of servos is that they move quite fast, as it can be seen in the video we included in Adding movement: servos .
With the setup I had imagined this was a problem. The camera has some non negligible weight and if we put something over the servo all of this can become unstable. See, for example:

The solution for this problem is quite simple: when we want to move to a certain position, we can reach it by means of a set of small steps. We can indicate a set of succesive positions for the servo, each one a bit more close to the final destination. In this way, even with fast movements, the camera is more or less stable.

The code could be similar to the one we can see here:

def move(self, servo, pos, posIni=MIN, inc=10):

	servoGPIO=18
	servoGPIO=17
	posFin=posIni + (MAX-MIN)*pos
	steps=abs(posFin - posIni) / inc

	print "Pos ini", posIni
	print "Pos fin", posFin
	print "Steps", steps
	print int(steps)

	if pos < 0:
		pos = -pos
		sign = -1
	else:
		sign = 1

	for i in range(int(steps)):
		servo.set_servo(servoGPIO,posIni+10*i*sign)
		time.sleep(VEL)

	print "Pos ini", posIni
	print "Pos fin", posFin
	print "Steps", steps
	print int(steps)

	servo.stop_servo(servoGPIO)

That is, if we start at position (posIni) and we want to move a certain percentage of the available range (a real number between 0 and 1) we can compute the final position if we know the total range (MAX – MIN):


posFin=posIni + (MAX-MIN)*pos

And then, we can compute the needed steps to reach this destination; if we use increments of 10 (inc=10):


steps=abs(posFin - posIni) / inc

We are using the absolute value because the movement can be forward and backward (depending on the starting point for the movement). This is solved by means fo this conditional:


if pos < 0:
...

Finally, we use a for loop to reach the destination:

for i in range(int(steps)):
	servo.set_servo(servoGPIO,posIni+10*i*sign)
	time.sleep(VEL)

The result can be seen in the following video:

There we can observe a forward and backward movements (to recover the initial position) with an improvised model.
The speed can be controlled with the time between steps (VEL value).

Maybe we should have chosen other type of motor, but we could solve the problem with this approach.

My second bot

In Raspberry Pi: ¿qué temperatura hace en mi casa? (only in Spanish, sorry) we presented our first attempt at doing a bot. It allowed us to interact with the Raspberry Pi from our location, provided we had an internet connection. In this video we can see that interaction using IRC.

I tested SleekXMPP and phenny but I found some limits and continued my search. When I found err I discovered that it was in that moment under develoment and that it has a somewhat active community in Google+, Err. It provides a modular architecture for adding features to the bot.

My first steps were to adapt some tests I programmed for phenny and to add the possibility to take pictures with my cameras and sending them by email The code is at: err-plugins (it will change in the future, so we will pay atention to the current version):

The first one is pruebas.plug. It contains some meta-information needed to define the module following the bot syntax:

[Core]
Name = Pruebas
Module = pruebas

[Documentation]
Description = let's try things !

And the file pruebas.py contains the actual code for the programmed actions. For example, the following code takes a pictures and then sends it by mail:

<br />
@botcmd<br />
def foto(self, msg, args):<br />
	"""Take a picture"""<br />
	quien=msg.getFrom().getStripped()<br />
	yield "I'm taking the picture, wait a second "<br />
	if(args):<br />
		try:<br />
			cam=int(args)<br />
		except:<br />
			cam=0<br />
	else:<br />
		cam=0<br />
	yield "Camera %s"%cam<br />
	self.camera("/tmp/imagen.png",cam)<br />
	yield "Now I'm sending it"<br />
	self.mail("/tmp/imagen.png", quien)<br />
	my_msg = "I've sent it to ... %s"%quien<br />
	yield my_msg<br />

The first line indicates that this funcion defines an instruction for the bot. The name of the funcion will be the command that we will need to send by IM (we will need a configurable prefix, that serves to differenciate among instructions for the bot and other strings),

In our case, the instruction

.foto

would execute a function that is almost the same as the one commented in Sending an image by mail in Python.

The main differences are:

  • It gets its parameters from the function call (Err manages this)

    def foto(self, msg, args):

  • It replies to the mail of the person who sent the order:

    quien=msg.getFrom().getStripped()

  • The argument can be 0, 1 or no argument (no validation is done) because we have two cameras attached to our raspi. By default (no parameters provided or some uninterpretable paramenter proviede) it uses camera 0.
  • Now it replies telling us the chosen camera:

    yield "Camera %s"%cam

  • And now it calls the actual funciont in charge of taking the picture; its parameters are very similar to the ones commented in a previous post (the name of the file and the chosen camera):

    self.camera("/tmp/imagen.png",cam)

  • Now it calls the funciont that will send the picture to the previously defined mail address, so the parameters are the name of the file and this address.

    self.mail("/tmp/imagen.png", quien)

  • Finally, it uses again yield to reply, finishin the process.

If we look at the code, the main difference for these two functions are that they do not have a @bootcmd line; they are internal funcions, and they are not available as bot commands. They need some configuration options (as presented in Sending an image by mail in Python ).

Errbot manages this by means of:

<br />
def get_configuration_template(self):<br />
return{'ADDRESS' : u'kk@kk.com', 'FROMADD' : u'kk@kk.com',<br />
'TOADDRS' : u'kk@kk.com', 'SUBJECT' : u'Imagen',<br />
'SMTPSRV' : u'smtp.gmail.com:587', 'LOGINID' : u'changeme',<br />
'LOGINPW' : u'changeme'}<br />

It is a dictionary with the parameters we need to configure.

If we send the order via IM:

.config Pruebas

In this case, Pruebas is the name of the module and we have selected the dot (.) as the indicator that the following string is an instruction for the bot. The config instruction returns the current configuration (if it has not been configured it returns the defined template; if it is configured it returns the actual values). These values can be used as a template for the module configuration.

.config Pruebas {'TOADDRS': u'mydir@mail.com', 'SMTPSRV':
u'smtp.gmail.com:587', 'LOGINPW': u'mypassword',
...
}

We are almost done, soon we will be able to show the whole thing.

Adding movement: servos

Once we have a camera (or two) attached to our raspi helps us to discover one of the annoying limitations they have: they cannot move!
Fortunately, there are plenty of options for doing this. I decided to buy a couple of servos.

View this post on Instagram

Motor #raspi

A post shared by Fernando Tricas García (@ftricas) on

They are cheap, small and noisy.

There are lots of pages explaining the theory behind their inner working so we only will remind here just a couple of things: they have some rotation constraints (the ones I bought can just move 180 degrees) and the way to control them is by sending some pulses whose duration determines the angle (for interested people, you can have a look at How do servos work? -in English- or at Trabajar con Servos -in Spanish-).

From our program our mission will be to find the way to send the adequate pulses to the selected pin where we have connected the servo (remember: physical world-computer connection).

There are lots of examples in the net.

For example, the programs : servo, servo2, servoYT, and servoYT2 are based on what we can see in the video Servo control using Raspberry pi (and also in this one Servo Control with the Raspberry Pi).

As usual, we are commenting on the main steps here, following the third program.

First the python modules that we need:

import RPi.GPIO as GPIO
import time

The first one is used for sending instructions through the pins to our raspi. The second one is for managing time related data.

Now, some setup: we will make reference to the pins by their number and we configure the 11 pin as output.

GPIO.setmode(GPIO.BOARD)

GPIO.setup(11,GPIO.OUT)

Now, we are going to define the controller with a frequency of 50Hz and we’ll start it in the central position:

p = GPIO.PWM(11,50)

p.start(7.5)

Finally, a bit more of code changing the position each second:

try:
    while True:
        print "Uno"
        p.ChangeDutyCycle(7.5)
        time.sleep(1)
        print "Dos"
        p.ChangeDutyCycle(12.5)
        time.sleep(1)
        print "Tres"
        p.ChangeDutyCycle(2.5)
        time.sleep(1)

That is, it starts at the central position and moves to both extremes. From the center it goes to one side, then to the contrary one and finally it returns to the initial position. You can see this movements in the following video:


By the end of the video you can see that we can control more than one servo (with the only limitation of the number of available pins). The code for this can be seen at:
servoYT2).
We have added pin number 12 and we use two controllers (p1 and p2). Then, we just send instructions to each one in sequence. You can have a look at this mini-video:

View this post on Instagram

Dos motores #raspi

A post shared by Fernando Tricas García (@ftricas) on

We will see soon how to manage all the parts we have commented until now in order to finish the project.

This post has been posted originally in Spanish at: Añadiendo movimiento: servos.

Sending an image by mail in Python

Once we are able to take a picture with our webcam (A camera for my Raspberry Pi ) the next step is to see the picture from wher we are.

There are lots of texts explaining how to configure a web server for this
but I didn’t want to publish a web server with my raspi to the internet.
You’d need to setup the server, open some ports in the router and take into
account the problem of not having a fixed IP.
It found this approach not very robuts.
There is also the possibility of somebody cracking your server and
accessing our network in some way (maybe difficult, but not impossible).

I also evaluated the possibility of sending the images by means of an
instant messaging app but I’m not sure if this can be done, or maybe it is
just that I’ve not been able to find the adequate documentantion, so I
discarded this option.

The final election was the old and reliable email. My bot is going to be
able to get petitions by different ways (XMPP, IRC, …) and it will send
the images as a reply by email.

There are lots of documents explaining how to prepare a message with an
attachment. In fact, I had a program from previous experiments and this was
the one I decided to use.
It can be seen at mail.py.

It basically constructs a message from its components (From, To, Subject, Attachments, …)

It needs some parameters, that need to be configured. The way to do this
is by means of an auxiliar module that is imported at the beginning of the program.

import mailConfig

The only content for this file are the variables whose values need to be
adapted. Our program just reads them (it could of course use them
directly).

destaddr = mailConfig.ADDRESS
fromaddr = mailConfig.FROMADD
toaddrs = mailConfig.TOADDRS
subject = mailConfig.SUBJECT
smtpsrv = mailConfig.SMTPSRV
loginId = mailConfig.LOGINID
loginPw = mailConfig.LOGINPW

imgFile = ‘/tmp/imagen.png’

We are selecting also a default filename for the image, and we can choose a
different one from the command line.

We also setup a default address for sending emails to (destaddr) but we can
also include a different one in the command line (not very robust, there is
not validation of the email address).

From this, we can construct the message.

Detection and filling the parameters for the object we are sending:

format, enc = mimetypes.guess_type(imgFile)
main, sub = format.split('/')
adjunto = MIMEBase(main, sub)

Notice that in this way, the program can be used for sending other files
that need not to be just images.

Now we construct the attachment, with the adequate condification and we
attach it to the message:

adjunto.set_payload(open(imgFile,"rb").read())
Encoders.encode_base64(adjunto)
adjunto.add_header('Content-Disposition', 'attachment; filename="%s"' % imgFile)
mensaje.attach(adjunto)

Finally, we add the other parameters:

mensaje['Subject'] = subject
mensaje['From'] = fromaddr
mensaje['To'] = destaddr
mensaje['Cc'] = toaddrs

The message is empty, it does not contain text (Exercice for the reader:
can you add some text? Something like: ‘This picture was taken on day
xx-xx-xxxx at hh:mm’).

And finally, we send the message (direct negotiation with the smtp server):

server = smtplib.SMTP()

server.connect(smtpsrv)
server.ehlo()
server.starttls()
server.login(loginId, loginPw)
server.sendmail(fromaddr, [destaddr]+[toaddrs], mensaje.as_string(0))
server.quit()

In this way we have a small Python program that will send by mail a file.
We can provide the name of the file in the command line and we can also
provide an email address.
By default it will send a image with the fixed name to the pre-configured
address.
As a sort of backup and logging system the program will always send a copy of the mail to the ‘toaddrs’.

On the configuration side, we need ‘destaddr’, ‘fromaddr’ and ‘toaddrs’ to be valid email addresses.

The server ‘smtpsrv’ can be any server that we can use and the program uses
authenticated sending (and this is the reason for needing the user and
password). For example, we can use the Google servers, and the
configuration would be:

smtpsrv='smtp.gmail.com:587'

And we could use some user and password for a pre-existing account.