Raspberry Pi to Arduino Serial Communication - Arduino Serial Port Problems

Hello Everyone, I am newbie to arduino serial communication, there is some challenges I encountered while I was sending simple byte data from Raspberry Pi python program to my arduino sketch. Basically, what I am doing is to send '0' or '1' from raspberry pi to arduino for driving six servo motors in different angle gradually.

Here is my Arduino code:

#include <Servo.h>
#include <Adafruit_NeoPixel.h>

// Which pin on the Arduino is connected to the NeoPixels?
#define PIN 6 // On Trinket or Gemma, suggest changing this to 1

// How many NeoPixels are attached to the Arduino?
#define LED_NUM 8

Adafruit_NeoPixel pixels(LED_NUM, PIN, NEO_GRB + NEO_KHZ800);

Servo servo01;
Servo servo02;
Servo servo03;
Servo servo04;
Servo servo05;
Servo servo06;
int counter;
int servoPin_1 = 7;
int servoPin_2 = A5;
int servoPin_3 = A4;
int servoPin_4 = A3;
int servoPin_5 = A2;
int servoPin_6 = A1;
int currentAngle = 0;

void setup()
{
  Serial.begin(9600);
  pixels.begin();
  for (int i = 0; i < LED_NUM; i++) {
    pixels.setPixelColor(i, pixels.Color(230, 120, 0));
    pixels.setBrightness(0);
    pixels.show();
  }
  servo01.attach(servoPin_1);
  servo02.attach(servoPin_2);
  servo03.attach(servoPin_3);
  servo04.attach(servoPin_4);
  servo05.attach(servoPin_5);
  servo06.attach(servoPin_6);
  pinMode(servoPin_1, OUTPUT);
  pinMode(servoPin_2, OUTPUT);
  pinMode(servoPin_3, OUTPUT);
  pinMode(servoPin_4, OUTPUT);
  pinMode(servoPin_5, OUTPUT);
  pinMode(servoPin_6, OUTPUT);
  servo01.write(currentAngle);
  servo02.write(currentAngle);
  servo03.write(currentAngle);
  servo04.write(currentAngle);
  servo05.write(currentAngle);
  servo06.write(currentAngle);
  Serial.print("Current Angle: ");
  Serial.println(currentAngle);
}

void loop()
{

  if (Serial.available() > 0) { //check reading from serial port
    int inByte = Serial.read(); // read condition

    if (inByte == '0' ) { // Start Counting if it is good words
      counter++;

      if (counter > 10)
        counter = 10;
      Serial.print("counter Up: ");
      Serial.println(counter);
      motorUp();
    } else if (inByte == '1') {
      counter--;
      if (counter < 0)
        counter = 0;
      Serial.print("counter Down: ");
      Serial.println(counter);
      motorDown();
    }
    lamp();

  } // End of Serial Checking

} // End of loop

void motorUp() {
  currentAngle = currentAngle + 18;
  if (currentAngle >= 180) currentAngle = 180;
  Serial.print("Current Angle: ");
  Serial.println(currentAngle);
  servo01.write(currentAngle);
  servo02.write(currentAngle);
  servo03.write(currentAngle);
  servo04.write(currentAngle);
  servo05.write(currentAngle);
  servo06.write(currentAngle);
}

void motorDown() {
  currentAngle = currentAngle - 18;
  if (currentAngle <= 0) currentAngle = 0;
  Serial.print("Current Angle: ");
  Serial.println(currentAngle);
  servo01.write(currentAngle);
  servo02.write(currentAngle);
  servo03.write(currentAngle);
  servo04.write(currentAngle);
  servo05.write(currentAngle);
  servo06.write(currentAngle);
}

void lamp() {
  if (counter == 10) {
    Serial.println("Turn On");
    for (int i = 0; i < LED_NUM; i++) {
      pixels.setPixelColor(i, pixels.Color(230, 120, 0));
      pixels.setBrightness(255);
      pixels.show();
    }
  } else if (counter < 10) {
    Serial.println("Turn Off");
    for (int i = 0; i < LED_NUM; i++) {
      pixels.setPixelColor(i, pixels.Color(0, 0, 0));
      pixels.setBrightness(0);
      pixels.show();
    }
  }
}

and my python script that perform serial communication:

#!/usr/bin/env python3
# Copyright 2017 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""A demo of the Google CloudSpeech recognizer."""
import argparse
import locale
import logging
import aiy.voice.tts
import serial

from time import sleep
from aiy.board import Board, Led
from aiy.cloudspeech import CloudSpeechClient

ser = serial.Serial('/dev/ttyACM0', 
                    baudrate = 9600, 
                    bytesize = serial.EIGHTBITS,
                    parity = serial.PARITY_NONE,
                    stopbits = serial.STOPBITS_ONE,
                    timeout=1,
                    xonxoff=0,
                    rtscts=0,
                    )

def get_hints(language_code):
    if language_code.startswith('en_'):
        return (# Positive Words
                'happy',
                # Negaive Words
                'sad',
                )
    return None

def locale_language():
    language, _ = locale.getdefaultlocale()
    return language

def main():
    logging.basicConfig(level=logging.DEBUG)

    parser = argparse.ArgumentParser(description='Assistant service example.')
    parser.add_argument('--language', default=locale_language())
    args = parser.parse_args()

    logging.info('Initializing for language %s...', args.language)
    hints = get_hints(args.language)
    client = CloudSpeechClient()
    with Board() as board:
        while True:
            count = ser.inWaiting()
            if count !=0:
                recv = ser.read(count)
                ser.write(recv)
                ser.flushInput()
                time.sleep(0.1)
            if hints:
                logging.info('Say something, e.g. %s.' % ', '.join(hints))
            else:
                logging.info('Say something.')
            text = client.recognize(language_code=args.language,
                                    hint_phrases=hints)
            if text is None:
                logging.info('You said nothing.')
                continue

            logging.info('You said: "%s"' % text)
            text = text.lower()
            # New command:
            # Positive Words:
            if 'happy' in text:
                ser.write(b'0')
                sleep(0.5)
                
            # Negative Words
            if 'sad' in text:
                ser.write(b'1')
                sleep(0.5)


if __name__ == '__main__':
    main()

My problem is that whenever I was trying to run the python script, the arduino will change the com port and caused my python program crashed and rage quit. I cannot get my script run successfully even the code is completely functional.

To fix this problem, I saw a thread that using the PC to Arduino Demo.
I am following the demo from Robin2: PC - Arduino comms using Python -- updated - Interfacing w/ Software on the Computer - Arduino Forum
in which Robin provides a arduino sketch and python program.

I would like to try using that method in my program to see if it is works. However I am confused by some part of code and would like to ask for some help:

Any suggestion about how to modify the following code (from Robin's python script) so that I can send data to my arduino board from my python3 script running on raspberry pi?

send a message at intervals

if time.time() - prevTime > 1.0:
sendToArduino("this is a test " + str(count))
prevTime = time.time()
count += 1

I need to send the byte 0 or 1 when meet the specific if statement in my python script, for example:

if 'happy' in text:
ser.write(b'0')

if 'sad' in text:
ser.write(b'1')

when arduino receive 0, it drives motor up; when arduino receive 1, it drives motor down

Should I change it in this way? I am a bit confused with the str(count), what is the count for?

if 'happy' in text:
if time.time() - prevTime > 1.0:
sendToArduino(str(1))
prevTime = time.time()
count += 1

if 'sad' in text:
if time.time() - prevTime > 1.0:
sendToArduino(str(0))
prevTime = time.time()
count += 1
I am very new to python and the serial connection for raspberry pi and arduino. Any ideas and suggestions would be greatly appreciated.

Let's start at the beginning. Have you been able to get the code in this simple Python - Arduino demo working correctly.

If it does not work then the problem will be easier to solve with that simple program before reviewing your more complex program.

...R

Robin:

It is working on my raspberry pi and arduino, here is the result(see attached image) :

Even though my python seems to be a bit complex, but I tried to use another simple python program to send data to arduino, also result in the same port changing problem. Here is the simple python script:


import serial
ser = serial.Serial('/dev/ttyUSB0',9600,timeout=1)

try:
while 1:
str = raw_input()
ser.write(str)

except KeyboardInterrupt:
ser.close()


Therefore, I highly suspected that it is the problem of my arduino script.

Image from Reply #2 so we don't have to download it. See this Simple Image Guide

...R

Now that we know the communication can work it is time to consider other things.

My problem is that whenever I was trying to run the python script, the arduino will change the com port and caused my python program crashed and rage quit. I cannot get my script run successfully even the code is completely functional.

My guess is that something is drawing too much power from the Arduino and causing it to reset when the 5v supply falls to a too-low voltage.

How are you powering your servos? The should NOT be drawing power through the Arduino.

...R

Hi Robin,

Sorry for the late reply. After I saw your suggestion, I plugged an external power supply (6V) to my Arduino. It works like a charm!! I have been searching the problem in the code but never thought of the hardware problem. I should have do more research before asking dumb questions, Thank you Robin.

Thanks for the update.

...R