Using PyFirmata with a simulator like SimulIDE

Question:

I’m trying to learn PyFirmata, but don’t want to get all of the hardware I need to do so. Instead I want to use a simulator, right now I’m using SimulIDE. In order to use PyFirmata, a board has to be connected to a COM port. Is there a way to get around this and use SimulIDE, or another simulator, instead?

Here is the code I want to run:

import pyfirmata
import time

board = pyfirmata.Arduino('/dev/ttyACM0')

while True:
    board.digital[13].write(1)
    time.sleep(1)
    board.digital[13].write(0)
    time.sleep(1)
Asked By: kmoore1616

||

Answers:

According to this page, it’s possible to connect your simulated Arduino to a real or virtual serial port (look for the "Connecting to Serial Port" section). You haven’t specified what OS you’re using; I’ll show an example of doing that with Linux.

Create a virtual serial port on your host

We can use socat to create a virtual serial port like this:

mkdir /tmp/vport
socat -v 
  pty,raw,echo=0,link=/tmp/vport/board 
  pty,raw,echo=0,link=/tmp/vport/python

This links a pair of PTY devices (which will have unpredictable names like /dev/pts/6 and /dev/pts/7) and creates convenience symlinks in /tmp/vport. The -v option means socat will print on the console any data being sent back and forth.

As an alternative to socat, you could also use tty0tty to create a linked pair of PTY devices. If you’re on Windows, I believe that com0com does something similar, but I don’t have an environment in which to test that out.

Create a serial port in SimulIDE

In the component panel, open the "Perifericals" section…

enter image description here

…and place a "SerialPort" in your circuit. Connect the TX pin on the serial port to the RX pin on your Arduino, and the RX pin on the serial port to the TX pin on the Arduino.

Double click on the serial port and configure it to connect to /tmp/vport/board:

enter image description here

Then select the "Config" panel and make sure the port is set for 57600 bps:

enter image description here

Close the configuration window and select the "Open" button on the serial port. It should end up looking something like:

enter image description here

Load some firmware on your Arduino and run it

For testing the serial port, I used the following code (in a sketch named SerialRead:

void setup() {
  // We use 57600bps because this is the rate that Firmata uses by default
  Serial.begin(57600);
}

void loop() {
  int incomingByte = 0;

  if (Serial.available() > 0) {
    incomingByte = Serial.read();
    Serial.print("Received:");
    Serial.println(incomingByte);
  }
}

And then compiled it using the arduino-cli tool like this:

cd SerialRead
mkdir build
arduino-cli  compile -b arduino:avr:uno --build-path build .

This creates (among other files) the file build/SerialRead.ino.hex, which is what we’ll load into the simulator.

In SimulIDE, right-click on the Arduino and select "Load firmware", then browse to that SerialRead.ino.hex file and load it:

enter image description here

Connect a serial tool to the virtual port

I’m using picocom to verify that things are connected properly (but you can use any other serial communication software, like minicom, cu, etc). On the host, run:

picocom /tmp/vport/python

In SimulIDE, power on the Arduino. In picocom, start typing something and you should see (if you type "ABCD"):

Received:97
Received:98
Received:99
Received:100

This confirms that we have functional serial connectivity between the virtual serial port on our host and the software running on the simulated Arduino. Now let’s try Firmata!

So what about Firmata?

Now that we’ve confirmed that we have the appropriate connectivity we can start working with pyfirmata. First, you’ll need to compile the StandardFirmata sketch into a .hex file, as we did with the SerialRead sketch earlier, and then load the .hex file into your simulated Arduino.

I wired up an LED between pin 7 and GND, and a switch between pin 8 and 3v3, and used the following code to test things out:

import sys
import pyfirmata
import time

board = pyfirmata.Arduino('/tmp/vport/python')
print('connected')

# start an iterator for reading pin states
it = pyfirmata.util.Iterator(board)
it.start()

board.digital[7].mode = pyfirmata.OUTPUT
board.digital[8].mode = pyfirmata.INPUT
board.digital[8].enable_reporting()

while True:
    if not board.digital[8].read():
        print('on')
        board.digital[7].write(1)
        time.sleep(0.5)
        print('off')
        board.digital[7].write(0)
        time.sleep(0.5)

Running this Python code produces the following behavior in SimulIDE:

enter image description here

Answered By: larsks