Joining Raspberry Pi and Arduino applications with SIMPL

details

featured

 

Description

The economy and simplicity of the network-transparent SIMPL toolkit makes it an ideal choice for the Raspberry Pi. In this article, we describe how to use the SIMPL toolkit to communicate between a Rasp Pi and an Arduino board.

 

Eight LED Example

The simplest configuration for a SIMPL application hosted by a Rasp Pi and Arduino is shown below schematically.

This communication will instruct the Arduino to illuminate any combination of eight LEDs, as shown below

This example illustrates three elements of the SIMPL toolkit:

  • tclSurrogate [2] and accompanying protocol
  • Arduino receiver sketch connecting via the tclSurrogate protocol
  • Python-SIMPL module connection using the normal channel

We will discuss each of these in turn, but before we do, some code needs to be installed on the Rasp Pi and the Arduino development host.

Code Installation

Installation of the SIMPL toolkit with the Python extensions was covered in the article [1]. You will find a self-installing archive for the Raspberry Pi at the project online [3]. Some updates have occurred in the SIMPL-Python libraries since the previous article was written, so if you installed the SIMPL toolkit back then, we recommend upgrading to the latest version.

The SIMPL website also contains a link to the SIMPL-Arduino self-installing archive [4]. This archive contains two components. The first component is the implementation of the tclSurrogate protocol in the form of an Arduino library. You need to install this component on the Arduino development host to support SIMPL communication over TCP/IP.

The second component in the archive is a couple of examples. One of these examples is the eight-LED project described in this article.

Arduino and SIMPL

The tclSurrogate protocol has been realized for the Arduino via a library called (you guessed it) Simpl. It should have been downloaded to the Rasp Pi using the self-installing archive [4] and then moved to the Arduino development host. The Simpl library uses the Ethernet library, which in turn uses the SPI library. Accordingly, all of these libraries are included in any Arduino sketch that uses SIMPL tclSurrogate protocols.

To enable the SIMPL toolkit connectivity, the Arduino needs to be equipped with an Ethernet shield. You’ll need to locate and record the MAC address on a label that is usually found on the underside of the shield PCB. This MAC address is needed by the sketch (Ethernet library) that we will be running on the Arduino.

Our demonstration hardware (middle box in Figure 2) consists of an Arduino Uno with an Ethernet shield and a PCB breakout with eight LEDs. The eight LEDs are connected to Arduino Uno I/O ports 2-9 via current-limiting 330-ohm (Ohm) resistors and transistors in a switch configuration. The I/O ports are configured for output in the sketch. Eight LEDs connected to the I/O ports through resistors valued from 100Ohm to 1kOhm on the anode and ground on the cathode will do just as well.

On the networking side, the Arduino is connected to an Ethernet hub. The Rasp Pi is also connected to this hub. A router is connected to this hub and acts a DHCP server. In this little network, the Rasp Pi receives an IP address via DHCP. It will also be necessary to record the value of the IP address given to the Rasp Pi. In our case, it is 10.0.1.32. You can get the IP address by issuing the ifconfig command on a terminal/console command line.

The code in Listing 1 is a SIMPL receiver running on the Arduino Uno. It is called eightLeds.ino. The line numbers have been added to help with the description in the “Listing 1 Annotation” box.

 

Arduino Code

01 #include <SPI.h>
02 #include <Ethernet.h>
03 #include <Simpl.h>
04
05  // message token definition
06 #define BRINKY_RITE  0
07
08 // structure definition of the received/replied message
09 typedef struct
10     {
11     unsigned short token; // message token indicating what to do
12     unsigned char state; // state of the LEDs; on/off; eight bits-eight LEDs
13     } MSG;
14 .
15  EthernetClient client;
16
17 void setup()
18 {
19 const unsigned port = 8000; // port that the tclSurrogate is waiting on
20 char *serverName = "10.0.1.32"; // Rasp Pi host where tclSurrogate lives
21 // char *serverName = "www.icanprogram.ca";
22 byte mac[] = {0x90, 0xA2, 0xDA, 0x0D, 0x0D, 0x77}; // ethernet shield MAC address
23
24  // start serial messaging
25 Serial.begin(9600);
26 Serial.println();
27 Serial.println("starting up");
28
29 // start ethernet
30 if (!Ethernet.begin(mac))
31     {
32     Serial.println("error on ethernet");
33     while(1);
34     }
35 // give the ethernet shield a chance to initialize
36 delay(1000);
37
38 // remotely SIMPL name attach the name "ARDUINO" on RasPi
39 if (nameAttach(serverName, port, &client, "ARDUINO") == -1)
40     {
41     Serial.println(whatsMyError());
42     client.stop();
43     while(1);
44     }
45
46 // initialize the digital pins as an output and test LEDs
47 for (int ledPin = 2; ledPin <= 9; ledPin++)
48     {
49     pinMode(ledPin, OUTPUT);
50     digitalWrite(ledPin, HIGH);
51     }
52 delay(3000);
53 for (int ledPin = 2; ledPin <= 9; ledPin++)
54     {
55     digitalWrite(ledPin, LOW);
56     }
57 Serial.println("initialization complete");
58 }
59
60 void loop()
61 {
62 long senderId;     // the unique id of the sending program
63 MSG msg;           // incoming/outgoing message variable
64 int ret;                // function return value
65 unsigned char state;    // 8 led state masking variable
66
67 // check for an incoming message
68 ret = Receive(&client, &senderId, &msg, sizeof(MSG));
69 if (ret == -1) // problem
70    {
71    Serial.println(whatsMyError());
72    nameDetach(&client);
73    while(1);
74    }
75 else if (ret > 0) // incoming message
76    {
77    // reply instantly to the remote sender
78    if (Reply(&client, &senderId, NULL, 0) == -1)
79        {
80        Serial.println(whatsMyError());
81        nameDetach(&client);
82        while(1);
83        }
84
85     // check the message token for veracity
86     if (msg.token != BRINKY_RITE)
87        {
88        Serial.println("Incorrect msg token");
89        nameDetach(&client);
90        while(1);
91        }
92
93     // set the blinky lights according to the message state variable
94     for (int ledPin = 2, state = 1; ledPin <= 9; ledPin++, state <<= 1)
95        {
96        digitalWrite(ledPin, msg.state & state);
97        }
98    }
99 }

 

Python Code (For Pi)

01 # import necessary modules
02 import sys
03 import csimpl
04 if sys.version < '3':
05    from Tkinter import *
06    iimport tkMessageBox
07 else:
08    from tkinter import *
09    from tkinter import messagebox
10
11 BRINKY_RITE = 0
12 global leds            # a series of eight button widgets
13 global numLeds
14
15 # a callback for changing the text value of a led button
16 def hndlChange(event):
17    # make certain that entered text is black
18    event.widget["foreground"] = "black"
19    # decide on the next character after a left button mouse click
20    if event.widget["text"] == "OFF":
21        event.widget["text"] = "ON"
22    else:
23        event.widget["text"] = "OFF"
24
25 # a callback for the send button
26 def hndlSubmit(nee, receiverId):
27    # assemble the message
28    outToken = BRINKY_RITE
29    outValues = 0
30    for num in range(numLeds):
31        if leds[num]["text"] == "ON":
32            outValues |= (1 << num)
33
34    # load the message to be sent to the Arduino sketch
35    nee.packMsg(nee.BIN, "hb", outToken, outValues)
36
37    # send the message
38    retVal = nee.send(receiverId)
39    if retVal == -1:
40        if sys.version < '3':
41           tkMessageBox.showerror("Error", nee.whatsMyError())
42        else:
43            messagebox.showerror("Error", nee.whatsMyError())
44        sys.exit(-1)
45
46 # operational start of the program
47 # check command line
48 if len(sys.argv) == 1:
49    rName = "ARDUINO"
50 elif len(sys.argv) == 2:
51    rName = sys.argv[1] + ":" + "ARDUINO"
52 else:
53    print("Incorrect command line")
54    sys.exit(-1)
55
56 # initialize some variables
57 numLeds = 8
58 leds = [None] * numLeds
59
60 # make an instance of Simpl
61 nee = csimpl.Simpl( "EIGHT_LEDS", 1024)
62
63 # name locate the C program SIMPL receiver
64 receiverId = nee.nameLocate("sys.argv[1]:ARDUINO")
65 if receiverId == -1:
66    err = nee.whatsMyError() + ": is the receiver program running?"
67    if sys.version < '3':
68       tkMessageBox.showerror("Error", err)
69    else:
70       messagebox.showerror("Error", err)
71    sys.exit(-1)
72
73 # initialize Tk for graphics
74 root = Tk()
75 rowframe = Frame(root)
76 rowframe.pack(fill=BOTH)
77 for num in range(numLeds):
78    leds[num] = Button(rowframe,  borderwidth=2, relief=SOLID, justify=CENTER, bg="Yellow", \
                         fg="Black", text="OFF", font=("Times", 12, "bold"), width=3)
79    leds[num].bind("<Button-1>", hndlChange)
80    leds[num].pack(side=LEFT)
81
82 # the bottom frame of buttons
83 rowframe = Frame(root)
84 rowframe.pack(fill=BOTH)
85 Button(rowframe, justify=CENTER, text="Send", font=('Times', 12, 'bold'), \
          command=(lambda: hndlSubmit(nee, receiverId))).pack()
86
87 # handle user input
88 root.mainloop()

 

For Testing

01 #import required modules
02 import tclsimpl
03 import sys
04 if sys.version < '3':
05       from Tkinter import *
06       import tkMessageBox
07 else:
08       from tkinter import *
09       from tkinter import messagebox
10
11 # defines
12 BRINKY_RITE = 0
13
14 global leds
15
16 def deconstructMsg(nee):
17         # extract the incoming message
18         intoken,status = nee.unpackMsg(nee.BIN, "hb")
19
20         if intoken == BRINKY_RITE:
21                for num in range(8):
22                        bit = 1 << num
23                        if status & bit:
24                                leds[num]["text"] = "ON"
25                        else:
26                                leds[num]["text"] = "OFF"
27
28
29 # define functionality to be performed whan a message is received
30 def hndlMessage(a, b):
31        # receive a message
32        messageSize, senderId = nee.receive()
33
34        if messageSize == -1:
35                # error
36                print("receive error")
37                sys.exit(-1)
38
39       # examine the message
40       deconstructMsg(nee)
41
42       # reply to sending program
43       retVal = nee.reply(senderId)
44       if retVal == -1:
45                print("reply error")
46                sys.exit(-1)
47
48 # define callback function when exit button is selected
49 def finish(event):
50       sys.exit(0)
51
52
53 #***** main part of program ******************************
54
55 # constructor for simpl class object
56 nee = tclsimpl.Simpl("8000:localhost:ARDUINO")
57
58 # initialize Tk for graphics
59 root = Tk()
60
61 # get the receive fifo file descriptor
62 fd = nee.whatsMyFd()
63
64 # attach a callback for incoming simpl messages
65 root.tk.createfilehandler(fd, READABLE, hndlMessage)
66
67 rowframe = Frame(root)
68 rowframe.pack(fill=BOTH)
69
70 leds = [None] * 8
71 for num in range(8):
72
73      leds[num] = Button(rowframe,  borderwidth=2, relief=SOLID, justify=CENTER, \
                 bg="Yellow", fg="Black", text="OFF", font=("Times", 12, "bold"), width=3)
74      leds[num].pack(side=LEFT)
75
76 # the bottom frame of buttons
77 rowframe = Frame(root)
78 rowframe.pack(fill=BOTH)
79
80 # build an exit button widget
81 button = Button(root)
82 button["text"] = "Exit"
83 button.bind("<Button>", finish)
84 button.pack()
85
86 # handle user input and simpl messaging
87 root.mainloop()

Conclusion

In this article, we showed how the SIMPL toolkit can be used to glue a Raspberry Pi to an Arduino and make it appear as a single SIMPL application. We discussed and illustrated another SIMPL surrogate: tclSurrogate. As with all SIMPL surrogates, the tclSurrogate fully encapsulates the networking and messaging details associated with connecting an Arduino to the Raspberry Pi. Once again, the SIMPL developer can focus energy on the business logic of the application at hand.

 

For More Information: http://www.raspberry-pi-geek.com/Archive/2014/06/Joining-Raspberry-Pi-and-Arduino-applications-with-SIMPL

Tags: 201802, W5100, Ethernet, Arduino, Raspberry Pi, SIMPL

COMMENTS

Please Login to comment
  Subscribe  
Notify of