Raspberry Pi, I2c, Python and Adafruit_I2c library with Ardu

For Adafruit customers who seek help with microcontrollers

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
User avatar
impartit
 
Posts: 61
Joined: Tue Feb 04, 2014 12:50 am

Raspberry Pi, I2c, Python and Adafruit_I2c library with Ardu

Post by impartit »

ROBOT_TOKENIZE_TEST.txt
Arduino Sketch
(1.42 KiB) Downloaded 164 times
Motion.txt
Motion.py
(1.49 KiB) Downloaded 176 times
process_socket_commands.txt
python_socket_commands.py
(2.48 KiB) Downloaded 176 times
I have been attempting to cure this issue for some time now without success but it would appear that the fault lies within the Adafruit_I2C library "write_list function". The associated Python files "python_socket_commands.txt" and "Motion.txt" and the Arduino sketch "ROBOT_TOKENIZE_TEST.txt" are attached to assist you. The problem is that the Arduino receives the "command" and "parameter" over i2c but the parsing function "void ParseI2CData()" does not tokenize the string it receives into two values for command and parameter. I have written a short test Arduino sketch with a hard coded quoted string containing {"f, 100"} which tokenizes perfectly giving the command "f" and the "parameter "100". I attached this sketch ROBOT_TOKENIZE_TEST.txt also. Is it simply because the test sketch has the quotes not sent from the Pi?

process_socket_commands.py is the first Python script to be run.

For completeness these files are distributed in the following links:
http://letsmakerobots.com/blog/unixguru ... t-part-1-3
http://letsmakerobots.com/blog/unixguru ... t-part-2-3
http://letsmakerobots.com/blog/unixguru ... t-part-3-3

I have been unable to contact the author for comment or suggestions.

The 3 file attachment limit prevents me from uploading the Arduino sketch but here is the relevant code for parsing the I2C data received by the Arduino:

Code: Select all

// Take the Comma separated I2C string and format it to Command and Parameter
    void ParseI2CData()
    {

      char *p = I2CinBuffer;                // The data to be parsed
      char *str;                       // Temp store for each data chunk
      int count = 0;                   // Id ref for each chunk
        
      while ((str = strtok_r(p, ",", &p)) != NULL)    // seperate at each "," delimiter
      { 
        inParse[count] = str;      // Add chunk to array  
        count++;      
      }
      
      //Serial.print(I2CinBuffer); 
      //Serial.print("  "); 
      //Serial.println(count);
      //Serial.print('line 170');
      if(count == 2)     // If the data has two values then..  
      {
        Command = inParse[0];       // Define value 1 as a Command identifier
        //Serial.print("Command from I2C in is.... "); 
        //Serial.println(Command);
        Parameter = inParse[1];     // Define value 2 as a Parameter value
        //Serial.print("Parameter from I2C in is.... "); 
        //Serial.println(Parameter);
        
        processCommand();
      }
    }
Can you please help?
Last edited by adafruit_support_rick on Fri Jun 19, 2015 10:52 am, edited 1 time in total.
Reason: please use Code tags when posting code (</> button)

User avatar
adafruit_support_rick
 
Posts: 35092
Joined: Tue Mar 15, 2011 11:42 am

Re: Raspberry Pi, I2c, Python and Adafruit_I2c library with

Post by adafruit_support_rick »

It would help to know what the data sent from the pi looks like. Put back all the Serial Print statements, and port the serial output.

User avatar
impartit
 
Posts: 61
Joined: Tue Feb 04, 2014 12:50 am

Re: Raspberry Pi, I2c, Python and Adafruit_I2c library with

Post by impartit »

ROBOT_TOKENIZE_TEST.txt
Renamed Arduino sketch
(1.42 KiB) Downloaded 173 times
If I read the pi output into an array within the "Arduino" sketch and use Serial.print to view it in the monitor the array contains 6, 100 (no quotes) where: the appropriate button and parameter has been chosen from the html image. This is what throws me completely as to why this cannot be parsed into 2 tokens but the manual test sketch attached, containing the same parse function code works just fine.

User avatar
adafruit_support_rick
 
Posts: 35092
Joined: Tue Mar 15, 2011 11:42 am

Re: Raspberry Pi, I2c, Python and Adafruit_I2c library with

Post by adafruit_support_rick »

The robot code outputs the substrings. Can you post the serial output? The problem is probably someplace else besides the parse routine

User avatar
impartit
 
Posts: 61
Joined: Tue Feb 04, 2014 12:50 am

Re: Raspberry Pi, I2c, Python and Adafruit_I2c library with

Post by impartit »

I'm not quite sure what you mean by posting the "Serial Output" as the "pi" is sending and the "Arduino" is receiving i2c data. The only place in the "Arduino" code where I can look at the i2c data received in the I2CinBuffer array is within the ParseI2CData function at line 158 in the Arduino sketch. If I place this code at the top of this function it reveals the two comma separated values sent from the pi. e.g. (6, 100)

int i;
for (i = 0; i < 32; i = i + 1) {
Serial.println(I2CinBuffer);
}

User avatar
adafruit_support_rick
 
Posts: 35092
Joined: Tue Mar 15, 2011 11:42 am

Re: Raspberry Pi, I2c, Python and Adafruit_I2c library with

Post by adafruit_support_rick »

Uncomment the serial.print statements in this section of code. That will tell you everything you need to know:

Code: Select all

// Take the Comma separated I2C string and format it to Command and Parameter
    void ParseI2CData()
    {

      char *p = I2CinBuffer;                // The data to be parsed
      char *str;                       // Temp store for each data chunk
      int count = 0;                   // Id ref for each chunk
        
      while ((str = strtok_r(p, ",", &p)) != NULL)    // seperate at each "," delimiter
      { 
        inParse[count] = str;      // Add chunk to array  
        count++;      
      }
      
      Serial.print(I2CinBuffer); 
      Serial.print("  "); 
      Serial.println(count);
      Serial.print('line 170');
      if(count == 2)     // If the data has two values then..  
      {
        Command = inParse[0];       // Define value 1 as a Command identifier
        Serial.print("Command from I2C in is.... "); 
        Serial.println(Command);
        Parameter = inParse[1];     // Define value 2 as a Parameter value
        Serial.print("Parameter from I2C in is.... "); 
        Serial.println(Parameter);
        
        processCommand();
      }
    }

User avatar
impartit
 
Posts: 61
Joined: Tue Feb 04, 2014 12:50 am

Re: Raspberry Pi, I2c, Python and Adafruit_I2c library with

Post by impartit »

I placed these statements into the original code to help me debug the problem.

They confirm that it does NOT parse two values. Here is the output, as captured in the Serial Monitor, of the uncommented code sample to include this array print block;

int i;
for (i = 0; i < 8; i = i + 1) {
Serial.println(I2CinBuffer);
}

6
,

4
0
0

Values in I2CinBuffer 0
14128

How strange is that ? The only difference between the test routine and the required sketch is that the values are hard coded as {"6, 100"} and INCLUDE QUOTES. Without the quotes if does not parse the two values. So why or where are the " " removed or not provided by the python code?

User avatar
adafruit_support_rick
 
Posts: 35092
Joined: Tue Mar 15, 2011 11:42 am

Re: Raspberry Pi, I2c, Python and Adafruit_I2c library with

Post by adafruit_support_rick »

The quotes are irrelevant. They are simple there as part of the syntax for defining a string. They don't become part of the string in your test code.

So, the input of 6, 400 looks correct, but strtok_r is not parsing it. I don't know why.

Is there a leading space in front of the 6? It looks like there's a leading space in front of the 400.

As an aside, there's a simpler way of doing this. That is to use the sscanf function.
This will give you a character for Command and an integer for Parameter, so there's no need for conversions in processCommand.
If there's a leading space in front of the command character, then you'll have to add a leading space to the format string in sscanf (i.e., " %c,%d")

Code: Select all

    char Command;
    int Parameter;

    void ParseI2CData()
    {
      int count = sscanf(I2CinBuffer, "%c,%d", &Command, &Parameter);
      if(count == 2)     // If the data has two values then..  
      {
        Serial.print("Command from I2C in is.... "); 
        Serial.println(Command);
        Serial.print("Parameter from I2C in is.... "); 
        Serial.println(Parameter);
        
        processCommand();
      }
    }

User avatar
impartit
 
Posts: 61
Joined: Tue Feb 04, 2014 12:50 am

Re: Raspberry Pi, I2c, Python and Adafruit_I2c library with

Post by impartit »

Many thanks for the alternative suggestion using "sscanf" function but the pi is sending a 'comma separated string' from the AdafruitI2C library function writeList(self, reg, list) which means that Command and Parameter must both be char ?

It does look as if there is a space before the 6 and after the comma which is probably why the parsing is not functioning. How would I modify the delimiter value to handle this?

User avatar
impartit
 
Posts: 61
Joined: Tue Feb 04, 2014 12:50 am

Re: Raspberry Pi, I2c, Python and Adafruit_I2c library with

Post by impartit »

Many thanks for the alternative suggestion using "sscanf" function but the pi is sending a 'comma separated string' from the AdafruitI2C library function writeList(self, reg, list) which means that Command and Parameter must both be char ?

It does look as if there is a space before the 6 and after the comma which is probably why the parsing is not functioning. How would I modify the delimiter value to handle this?

User avatar
impartit
 
Posts: 61
Joined: Tue Feb 04, 2014 12:50 am

Re: Raspberry Pi, I2c, Python and Adafruit_I2c library with

Post by impartit »

With the Command and Parameter variables set as Strings and the format "%c,%d" changed to "%c,%c" (as both Command and Parameter are BOTH strings" the count value returns -1 with Serial.print(count) immediately following the sscanf call. Does this format handle the space before the 6 and after the , in { 6, 100}?

User avatar
adafruit_support_rick
 
Posts: 35092
Joined: Tue Mar 15, 2011 11:42 am

Re: Raspberry Pi, I2c, Python and Adafruit_I2c library with

Post by adafruit_support_rick »

If you want to use character arrays for Command and Parameter (not String objects - that won't work!), then you have to change the format to " %s, %s". The spaces are significant, since the %s parser will stop at the first whitespace character it sees.

Code: Select all

    char Command[2];  //one character plus a null
    char Parameter[6];   //five characters plus a null

    void ParseI2CData()
    {
      int count = sscanf(I2CinBuffer, " %s, %s", Command, Parameter);
      if(count == 2)     // If the data has two values then..  
            ... etc ...
However, if you do it the way I had it originally, then you don't need to mess around with strings. commandProcessor actually operates on a character and an integer, which it what you'll get directly from the original code I posted.

User avatar
impartit
 
Posts: 61
Joined: Tue Feb 04, 2014 12:50 am

Re: Raspberry Pi, I2c, Python and Adafruit_I2c library with

Post by impartit »

I really .appreciate you help but still no luck. I attach a test sketch for you to try and comment. With or without spaces in the array. e.g. { 6, 100} or {6.100} does not produce a count of 2. Please note "The Command can be a single character or integer and the Parameter a maximum of 255"
ROBOT_TOKENIZE_TEST.txt
Arduino Test Sketch
(1.42 KiB) Downloaded 180 times

User avatar
adafruit_support_rick
 
Posts: 35092
Joined: Tue Mar 15, 2011 11:42 am

Re: Raspberry Pi, I2c, Python and Adafruit_I2c library with

Post by adafruit_support_rick »

When I run that sketch it works:

Code: Select all

count contains... 1
count contains... 2
Finished Parsing I2CinBuffer data
Command from I2C is.... t
Parameter from I2C is.... 987

User avatar
impartit
 
Posts: 61
Joined: Tue Feb 04, 2014 12:50 am

Re: Raspberry Pi, I2c, Python and Adafruit_I2c library with

Post by impartit »

That's good. I had a space before the ' t' when I last ran the sketch and it proves that the 'tokenization' works as it should. This is the same code as in the process_socket_commands,py script. The source of the "token list" is the "Adafruit_I2C.py" library "write_list" function. Why is it inserting spaces?

Locked
Please be positive and constructive with your questions and comments.

Return to “Microcontrollers”