1

I am a noob looking for help. Here is my problem. I have an Arduino Uno with two servomotors; one attached to pin 10, the other to pin 11. I want the servos to move independently according to instructions sent through a serial port to the Arduino from Python on Windows. As such I need Arduino code and Python code. I have used both Python 2.7 and 3.6 with pySerial installed. So far I have only been able to move the servos when using C# to send the coordinates to the Arduino, or from the Arduino code itself. Here is the code. I do not take credit for the Arduino code or the C# code.

Arduino code (Credit to Michael Reeves)

#include<Servo.h>

Servo serX;
Servo serY;

String serialData;

void setup() {
  serX.attach(10);
  serY.attach(11);
  Serial.begin(9600);
  Serial.setTimeout(10);
}

void loop() {
}

void serialEvent() {
  serialData = Serial.readString();
  serX.write(parseDataX(serialData));
  serY.write(parseDataY(serialData));
}

int parseDataX(String data){
  data.remove(data.indexOf("Y"));
  data.remove(data.indexOf("X"), 1);
  return data.toInt();
}

int parseDataY(String data){
  data.remove(0, data.indexOf("Y") + 1);
  return data.toInt();
}

I know that the Arduino code works because I can write to the servos within it and the servos respond correctly. It is also working with C#.

C# code (Credit to Michael Reeves):

using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Diagnostics;

namespace LaserControl {
  public partial class Form1 : Form {
    public Stopwatch watch { get; set; }
    public Form1() {
      InitializeComponent();
    }
    private void Form1_Load(object sender, System.EventArgs e) {
      watch = Stopwatch.StartNew();
      port.Open();
    }
    private void Form1_MouseMove(object sender, MouseEventArgs e) {
      writeToPort(new Point(e.X, e.Y));
    }
    public void writeToPort(Point coordinates) {
      if (watch.ElapsedMilliseconds > 15) {
        watch = Stopwatch.StartNew();
        port.Write(string.Format("X{0}Y{1}", (180 - coordinates.X / (Size.Width / 180)), (coordinates.Y / (Size.Height / 180))));
        System.Diagnostics.Debug.WriteLine(string.Format("X{0}Y{1}", (coordinates.X / (Size.Width / 180)), (coordinates.Y / (Size.Height / 180))));
      }
    }
  }
}

This code takes mouse input from a form and sends it to the servos. The data structure is a string that looks like this "X90Y100", where the letters correspond to servos and the numbers are the angle.

It is working and the servos move correctly.

Here is the Python code. It is simply a test of moving the servos.

import serial
port = serial.Serial("COM3", 9600)
port.write(b"X100Y70")

The servos do not move. What is the problem? Any help would be greatly appreciated.

Thank you.

0

1 Answer 1

1

The answer is on this page: Arduino and Python

It is worth noting that the example above will not work on a Windows machine; the Arduino serial device takes some time to load, and when a serial connection is established it resets the Arduino.

Any write() commands issued before the device initialised will be lost. A robust server side script will read from the serial port until the Arduino declares itself ready, and then issue write commands. Alternatively It is possible to work around this issue by simply placing a 'time.sleep(2)' call between the serial connection and the write call.

I've tested it and it works with the delay added:

import serial
import time

port = serial.Serial("COM3", 9600)
time.sleep(2)
port.write(b"X100Y70")

You should consider a more robust message format. At the least, it should have a terminator char (like "\n"). Serial.readString(); relies on a timeout to determine when a complete message has been received. This can cause errors. You can change your message format to have a terminator (or a fixed size):

void serialEvent() {
  static String serialData;
  while (Serial.available()) {
    char c = (char)Serial.read();
    if (c == '\n') {
       // Complete message, call a function to handle it
       serX.write(parseDataX(serialData));
       serY.write(parseDataY(serialData));
       // Reset for next message
       serialData = "";
    }
    else {
      // Otherwise keep building the message
      serialData += c;
    }
}
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you so much! Oh my goodness it works! I will do my best to implement the changes to serial communication tomorrow.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.