2

I have written some Arduino code (with help from the post Serial Input Basics). On serial I send some data and, based on certain values sent, certain LEDs will be lit. Here is the Arduino code:

const byte numChars = 32;
char receivedChars[numChars];
char tempChars[numChars];        // Temporary array for use when parsing

// Variables to hold the parsed data
//char messageFromPC[numChars] = {0};
int cmd = 0;
int pitch = 0;
int velocity = 0;
int integerFromPC = 0;
int int2FromPC = 0;
boolean newData = false;

void setup() {

    // Put your setup code here, to run once:
    Serial.begin(9600);//set baud rate

    //Configure pins 2:5 as OUTPUT
    pinMode(2,OUTPUT);
    pinMode(3,OUTPUT);
    pinMode(4,OUTPUT);
    pinMode(5,OUTPUT);
    pinMode(13,OUTPUT);
}

void loop() {
    recvWithStartEndMarkers();
    if (newData == true) {
        strcpy(tempChars, receivedChars);
        // This temporary copy is necessary to protect the original data
        // because strtok() used in parseData() replaces the commas with \0.

        parseData();
        showParsedData();
        if(cmd==144 && velocity!=0){
            switch(pitch){
                case 30:
                    digitalWrite(2, HIGH);
                    break;

                case 31:
                     digitalWrite(3, HIGH);
                     break;

                case 32:
                    digitalWrite(4, HIGH);
                    break;

                case 33:
                    digitalWrite(5, HIGH);
                    break;

                default:
                    break;
            }
        }
        if(cmd==144 && velocity==0){
            switch(pitch){

                case 30:
                    digitalWrite(2, LOW);
                    break;

                case 31:
                    digitalWrite(3, LOW);
                    break;

                case 32:
                    digitalWrite(4, LOW);
                    break;

                case 33:
                    digitalWrite(5, LOW);
                    break;

                default:
                    break;
            }
        }
        newData = false;
    }
}

void recvWithStartEndMarkers() {

    static boolean recvInProgress = false;
    static byte ndx = 0;
    char startMarker = '<';
    char endMarker = '>';
    char rc;

    while (Serial.available() > 0 && newData == false) {
        rc = Serial.read();

        if (recvInProgress == true) {
            if (rc != endMarker) {
                receivedChars[ndx] = rc;
                ndx++;
                if (ndx >= numChars) {
                    ndx = numChars - 1;
                }
            }
            else {
                receivedChars[ndx] = '\0'; // Terminate the string
                recvInProgress = false;
                ndx = 0;
                newData = true;
            }
        }

        else if (rc == startMarker) {
            recvInProgress = true;
        }
    }
}

void parseData() {      // Split the data into its parts

    char * strtokIndx;  // This is used by strtok() as an index

    strtokIndx = strtok(tempChars, " "); // Get the first part - the string
    //strcpy(messageFromPC, strtokIndx); // Copy it to messageFromPC
    cmd = atoi(strtokIndx);

    strtokIndx = strtok(NULL, " ");      // This continues where the previous call left off
    //integerFromPC = atoi(strtokIndx);  // Convert this part to an integer
    pitch = atoi(strtokIndx);

    strtokIndx = strtok(NULL, " ");
    velocity = atoi(strtokIndx);         // Convert this part to a float
}

void showParsedData() {
    Serial.print("Comm ");
    Serial.println(cmd);
    Serial.print("Ptch ");
    Serial.println(pitch);
    Serial.print("Velo ");
    Serial.println(velocity);
    Serial.println("\n");
}

Now this works perfectly with sending data from the Arduino's serial monitor, so for example if I type the following on serial monitor:

<144 30 45>

Then the LED I expect to get lit does, and I can turn it off by:

<144 30 0>

Now, I want to send this data from a Python (2.7) program which I am reproducing here:

#!/usr/bin/env python
import time
import serial
ser = serial.Serial('/dev/cu.usbmodem1421', 9600)
noteOn = 144
veloMid = 75
veloSilent = 0
def sendData(cmd, pitch, velocity):
    global ser
    cmd = bytes(cmd)
    pitch = bytes(pitch)
    velocity = bytes(velocity)
    ser.write("<")
    ser.write(cmd)
    ser.write(pitch)
    ser.write(velocity)
    ser.write(">")

while 1:
    notes = range(30, 34)
    for note in notes:
        sendData(noteOn, note, veloMid)
        time.sleep(2)
        sendData(noteOn, note, veloSilent)

The idea was to do the same thing I was doing manually in serial monitor, except using a Python script. But this produces no result. I see the RX and TX pins on the Arduino toggling, so it looks like the program is indeed communicating with the Arduino. In the Python IDE I wrote a few lines as follows to read the data from Arduino:

import serial
ser = serial.Serial('/dev/cu.usbmodem1421', 9600, timeout=5)
while True:
    data_raw = ser.read()
    print data_raw

With above code I receive the following characters in the Python IDE:

C
o
m
m


P
t
c
h


V
e
l
o

I have a feeling there is some mismatch between the data types of the data I am sending between the Python script and the Arduino, but I am not sure exactly what this mismatch might be.

  • Why am I not seeing the values of cmd, pitch and veocity being printed out from the serial.read() although the other strings "Comm Ptch Velo" are printed?

  • What dataype is serial.write passing on that might than be causing mismatch with my Arduino code?

1
  • This is how you format code: Use the code formatting markdown (four leading spaces). For help see Markdown help. You should be able to do this by selecting the code and pressing Ctrl+K to have your browser do this for you. It was hard work changing your tags (from I don't know where) into what works here.
    – Nick Gammon
    Commented Oct 24, 2016 at 5:26

1 Answer 1

2

In your test with the serial monitor you are putting spaces between each number. Using my logic analyzer I got this being sent from your Python code to the Arduino:

Logic analyzer image

No spaces, right? So the Arduino is receiving:

<1443175>

And since you are using a space as a numeric delimiter your decoding isn't working.


Something like this is probably warranted:

    ser.write("<")
    ser.write(cmd)
    ser.write(" ")
    ser.write(pitch)
    ser.write(" ")
    ser.write(velocity)
    ser.write(">")
1
  • Nick....You are a genius!!! The spaces were exactly the problem. I completely forgot the spaces when I switched to the python code. After correctly formatting my output string things work as I want. Many thanks for your suggestion. I also apologize for the formatting issue. I will keep your suggested link handy next time I submit a question.
    – yankeemike
    Commented Oct 24, 2016 at 18:48

Your Answer

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

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