Go Down

Topic: Python / Arduino Servo Controller (Read 2213 times) previous topic - next topic

CajunSniper

Arduino Newbee;

I'm having basic issues of python controlling my servos.

Arduino Mega 2560, Python 2.6, Servo Super 500 F21740

I originally wanted to transfer milliseconds from Python to Arduino to the servo. I gave up on that because of getting the string data across the serial port.

I settled for whole degrees, which worked. My new problem became at an output of 39 degrees the servo goes to 0 degrees, at 90 it is 90, at output 135 the servo goes to 180 degrees (2X issue). The original program had min pulse at 640 and max pulse at 2400 for 0 to 180 degrees. My servos are min pulse 1000 microseconds and max pulse 2000 microseconds for 0 to 300 degrees. My code is listed below. I've been through a couple of weeks of frustration, and it's time to seek help. Thanks beforehand.

I know that I could have used a wait in python instead of counting, but I had an issue loading the library "Time" in Python 2.6 through PIP.

 Ardunio Code:
/*
 * ------------------------------
 *   MultipleSerialServoControl
 * ------------------------------
 *
 * Uses the Arduino Serial library
 *  (http://arduino.cc/en/Reference/Serial)
 * and the Arduino Servo library
 *  (http://arduino.cc/en/Reference/Servo)
 * to control multiple servos from a PC using a USB cable.
 *
 * Dependencies:
 *   Arduino 0017 or higher
 *     (http://www.arduino.cc/en/Main/Software)
 *   Python servo.py module
 *     (http://principialabs.com/arduino-python-4-axis-servo-control/)
 *
 * Created:  23 December 2009
 * Author:   Brian D. Wendt
 *   (http://principialabs.com/)
 * Version:  1.1
 * License:  GPLv3
 *   (http://www.fsf.org/licensing/)
 *
 */

// Import the Arduino Servo library
#include <Servo.h>

// Create a Servo object for each servo
Servo servo1;
Servo servo2;
Servo servo3;
Servo servo4;
Servo servo5;
Servo servo6;

// TO ADD SERVOS:
//   Servo servo5;
//   etc...

// Common servo setup values
int minPulse = 1000;   // minimum servo position, us (microseconds) (Original program was 640)
int maxPulse = 2000;  // maximum servo position, us (original program was 2400)

// User input for servo and position
int userInput[3];    // raw input from serial buffer, 3 bytes
int startbyte;       // start byte, begin reading input
int servo;           // which servo to pulse?
int pos;             // servo angle 0-180
int i;               // iterator

// LED on Pin 13 for digital on/off demo
int ledPin = 13;
int pinState = LOW;

void setup()
{
  // Attach each Servo object to a digital pin
  servo1.attach(38, minPulse, maxPulse);
  servo2.attach(46, minPulse, maxPulse);
  servo3.attach(4, minPulse, maxPulse);
  servo4.attach(5, minPulse, maxPulse);
  servo5.attach(10, minPulse, maxPulse);
  servo6.attach(11, minPulse, maxPulse);
  // TO ADD SERVOS:
  //   servo5.attach(YOUR_PIN, minPulse, maxPulse);
  //   etc...

  // LED on Pin 13 for digital on/off demo
  pinMode(ledPin, OUTPUT);

  // Open the serial connection, 9600 baud
  Serial.begin(9600);
}

void loop()
{
  // Wait for serial input (min 3 bytes in buffer)
  if (Serial.available() > 2) {
    // Read the first byte
    startbyte = Serial.read();
    // If it's really the startbyte (255) ...
    if (startbyte == 255) {
      // ... then get the next two bytes
      for (i=0;i<2;i++) {
        userInput = Serial.read();
      }
      // First byte = servo to move?
      servo = userInput[0];
      // Second byte = which position?
      pos = userInput[1];
      // Packet error checking and recovery
      if (pos == 255) { servo = 255; }

      // Assign new position to appropriate servo
      switch (servo) {
        case 1:
          servo1.write(pos);    // move servo1 to 'pos'
          break;
        case 2:
          servo2.write(pos);
          break;
        case 3:
          servo3.write(pos);
          break;
        case 4:
          servo4.write(pos);
          break;
        case 5:
          servo5.write(pos);
          break;
        case 6:
          servo6.write(pos);
          break;

   // TO ADD SERVOS:
   //     case 5:
   //       servo5.write(pos);
   //       break;
   // etc...

        // LED on Pin 13 for digital on/off demo
        case 99:
          if (pos == 180) {
            if (pinState == LOW) { pinState = HIGH; }
            else { pinState = LOW; }
          }
          if (pos == 0) {
            pinState = LOW;
          }
          digitalWrite(ledPin, pinState);
          break;
      }
    }
  }




Python Code
import pythoncom, pyHook, serial
import numpy as np


usbport = 'COM3'
ser = serial.Serial(usbport, 9600, timeout=1) # Set up serial baud rate

# Declaring Variables
global servoxposition, servoyposition
global servo,position

# Initial Values
servo,position = (1,90)
servoxposition = 90
servoyposition = 90

global count
count=1
delaytime=32000000

     
def move(servo, angle):
   
    print "I'm in the subroutine"
    if (0 <= angle <= 180):
        ser.write(chr(255))
        ser.write(chr(servo))
        ser.write(chr(angle))
    else:
        print("Servo angle must be an integer between 0 and 180.\n")


def init():
    move(1,90)
    move(2,90)
    move(3,90)
    move(4,90)
    move(5,90)
    move(6,90)


init()

count=1
while count<delaytime:
    count=count+1
   
move(1,servoxposition)
print "Moving 1 to 35 degrees"
count=1
while count<delaytime:
    count=count+1

servoxposition = servoxposition+10
   
move(1,servoxposition)
print "Moving 1 to 90 degrees"
count=1
while count<delaytime:
    count=count+1
   
servoxposition = servoxposition+10
   
move(1,servoxposition)
print "Moving 1 to 90 degrees"
count=1
while count<delaytime:
    count=count+1

move(1,90)
print "Moving 1 to 90 degrees"
count=1
while count<delaytime:
    count=count+1




count=1
move(2,45)
print "Moving 2 to 45 degrees"
while count<delaytime:
    count=count+1
   

count=1
move(2,135)
print "Moving 2 to 135 degrees"
while count<delaytime:
    count=count+1


count=1
move(2,90)
print "Moving 2 to 135 degrees"
while count<delaytime:
    count=count+1



 

PaulS

Code: [Select]
int userInput[3];    // raw input from serial buffer, 3 bytes
Why are you wasting memory storing bytes in an int array?

Code: [Select]
int startbyte;       // start byte, begin reading input
Using a type (byte) in a name, when the type in the name is NOT the type of the variable, is stupid. Do NOT do that.

Code: [Select]
move(1,servoxposition)
print "Moving 1 to 35 degrees"

That is not what the code does.

It really isn't clear what your problem is. Make the python program attempt to move ONE servo, to specific positions, without the use of variables. Have the Arduino send data to the serial port. Have the python app read that data, so you can see what the Arduino got and how it used what it got.
The art of getting good answers lies in asking good questions.

CajunSniper

I appreciate your constructive criticism. My problem is basically trying to get Python to send a position through the Arduino to a servo and have the servo move to that position. If you have a better example on how to accomplish that task, I would appreciate seeing it. I have tried numerous examples that I found on the internet and all have failed. As far as the text, I was just printing text to see that the code lines were being executed. Thanks.   

Delta_G

Code: [Select]
  if (Serial.available() > 2) {
    // Read the first byte
    startbyte = Serial.read();
    // If it's really the startbyte (255) ...
    if (startbyte == 255) {
      // ... then get the next two bytes
      for (i=0;i<2;i++) {
        userInput = Serial.read();
      }


Here's one bug.  IF you have 2 bytes available then read one and if it matches then read two more.  That sounds an awful lot like 3 bytes to me. 

Go have a look at @Robin2's fabulous Serial Input Basics thread.  That would probably help you a lot. 
|| | ||| | || | ||  ~Woodstock

Please do not PM with technical questions or comments.  Keep Arduino stuff out on the boards where it belongs.

CajunSniper

 Delta_G Thanks for pointing me towards a good starting point.

PaulS

Quote
IF you have 2 bytes available then read one
If there are only two bytes available, nothing will be read, because 2 is not greater than 2. Reading happens only when the number of bytes available is greater than 2.
The art of getting good answers lies in asking good questions.

CajunSniper


Go Up