0

I'm working on a robot, more precisely on his head which have to track an human face.

I'm using a RPI which will detect the face and then send to the Arduino the angles for both servomotors.

I wrote a python script which will take 2 parameters and send them to the Arduino, this script will open the serial connection and send the command.

python script:

#!/usr/bin/env python

import serial
import time
import sys

ser = serial.Serial("/dev/ttyACM0", 9600)
time.sleep(2)

coords = [str(sys.argv[1]), str(sys.argv[2])]

commande = 'X' + coords[0] + 'Y' + coords[1] + 'V'

ser.write(commande)

ser.close()

The control of servos is working well on the Arduino but the problem is that each time I execute my script, the opening of the serial connection firstly reset both servos and once the Arduino receive the command both servos will go to the correct angles.

Arduino sketch:

//Bibliothèque :
#include <Servo.h> //Ajoute la librairie Servo

Servo servo1; //servo 180°
Servo servo2;    //servo 360°
int pos1 = 0; //Position initiale du servo1
int pos2 = 0; //Position initiale du servo2
int maxHaut = 90;
int maxBas = -35;
int maxGauche = 90;
int maxDroite = -85;

/**
 * Déclarations variables commandes
 */
 String commande = "";
 int coords[] = {0,0};
 int newCoords[] = {0,0};
 int indexX = 0;
 int indexY = 0;
 int indexFinCommande = 0;
 int result = 0;

void setup() {
  servo1.attach(9); //servo 180° sur pin 9
  servo1.write(35);
  servo2.attach(10); //servo 180° sur pin 10
  servo2.write(85);
  Serial.begin(9600);
}

void loop() {
  //pos1 = servo1.read();
  //pos2 = servo2.read();
  commande = "";
  if(Serial.available())
  {
    //Serial.println("Traitement de la commande..");
    commande = Serial.readString();
    //Serial.println(commande);
    traitementCommande(commande);
  }
}

void traitementCommande(String uneCommande)
{
  Serial.println(uneCommande);

  indexFinCommande = uneCommande.indexOf('V');
  indexX = uneCommande.indexOf('X');
  indexY = uneCommande.indexOf('Y');

  if((indexFinCommande==-1) || (indexX==-1) || (indexY==-1))
  {
    Serial.println("Commande non reconnue..");
    goto commandNotRecognized;
  }

  newCoords[0] = uneCommande.substring(indexX+1,indexY).toInt();
  newCoords[1] = uneCommande.substring(indexY+1, indexFinCommande).toInt();

  if((newCoords[0] < maxBas) || (newCoords[0] > maxHaut) || (newCoords[1] < maxDroite) || (newCoords[1] > maxGauche))
  {
    Serial.println("Coordonees invalides..");
    goto commandNotRecognized;
  }

  coords[0] = newCoords[0];
  coords[1] = newCoords[1];
  pos1 = coords[0] + 35;
  pos2 = coords[1] + 85;

  servo1.write(pos1);
  servo2.write(pos2);

  Serial.println("OK");
  commandNotRecognized:
  Serial.print(coords[0]);
  Serial.print(" ");
  Serial.println(coords[1]);
}

I want to know if there is an alternative to keep the serial connection open or if you guys had a solution for my problem.

I hope you will understand my request. Sorry for the fews french word used in my code, if something seems strange to you just ask me to explain it ;) And I'm also sorry for my english that should not be perfect..

Thank you for your time and your help.

  • Just curious: Why use the Ardunio at all in this case? You need the Pi for the tracking but it could also be the controller for the motors. – Brick Oct 4 '17 at 13:31
  • Oh sorry I didn't saw your comment ! I used the Arduino because the Pi will be mainly used for the face tracking and also to display the head of the robot on an LCD 3.5 so it's in order to reduce the charge of work we chose to use the Arduino for the motors control. But to answer you, yes, we could use the RPI to control both motors :) – Alexandre Ferret Oct 4 '17 at 15:18
0

Keep the script alive and use a infinite loop to keep it running without closing it:

while True:

    coords = [str(sys.argv[1]), str(sys.argv[2])]

    commande = 'X' + coords[0] + 'Y' + coords[1] + 'V'

    ser.write(commande)
  • Thank you for your answer ! I think this should work but this script will have to be call by another file and the parameters will change at each execution. Do you think this should be a problem ? – Alexandre Ferret Oct 4 '17 at 12:45
  • Ok!, so maybe, you can open the serial port on the first script and then pass it as a parameter to this one. – Luis Diaz Oct 4 '17 at 12:47
  • Because I'll not be able to change the parameters if it still in an infinite loop. The arduino will always receive the same command.. – Alexandre Ferret Oct 4 '17 at 12:47
  • 1
    Oh yeah very smart ! I'll try this and confirm you that once it's working ! Thanks – Alexandre Ferret Oct 4 '17 at 12:47
  • Sorry but can you explain me how I can pass as parameter the var of the serial port ? – Alexandre Ferret Oct 4 '17 at 13:32
1

I found something and it's actually working as I expected !

I used SimpleXMLRPCServer (https://docs.python.org/2/library/simplexmlrpcserver.html#simplexmlrpcserver-example) which permits me to store my serial instance !

Here is my first python script which will start my serial connection and store it into the server:

file: openSerialToArduino.py

#!/usr/bin/env python

import serial
import time
from SimpleXMLRPCServer import SimpleXMLRPCServer
from SimpleXMLRPCServer import SimpleXMLRPCRequestHandler

class RequestHandler(SimpleXMLRPCRequestHandler):
        rpc_paths = ('/RPC2',)

server = SimpleXMLRPCServer(("localhost", 8000), requestHandler=RequestHandler)

server.register_introspection_functions()

ser = serial.Serial("/dev/ttyACM0", 9600)
time.sleep(2)

server.register_instance(ser)

server.serve_forever()

Then I modify this file to be executable:

chmod +x openSerialToArduino.py

So I can execute this one in background to let me access to my serial instance:

nohup /home/pi/Documents/Projects/SerialPiArduinoServo/openSerialToArduino.py &

And finally I can execute my main script and get the instance of serial without re-open it:

file: serialControlServoAbsPi.py

#!/usr/bin/env python

import serial
import sys
import xmlrpclib

s = xmlrpclib.ServerProxy('http://localhost:8000')

coords = [str(sys.argv[1]), str(sys.argv[2])]

command = 'X' + coords[0] + 'Y' + coords[1] + 'V'

s.write(command)

And now both servos are going directly to the desired angles !

Thank you Luis Diaz for leaded me on this way ! Creating the serial instance before executing my script was the main part of the solution ! (BTW your answer didn't seems me too rude, you was totally correct ;) )

Hope this will help some Googlers !

Edit:

I get an error when I restarted RPI, don't know why and I was not able to fix this one so I used a fresh Raspbian and another version of SimpleXMLRPCServer for python 2 and it's working again even after reboot :)

  • Nice to see that you've been able to fix it! – Luis Diaz Oct 4 '17 at 15:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.