Expand your Raspberry Pi with Arduino ports

栏目: IT技术 · 发布时间: 4年前

内容简介:As members of the maker community, we are always looking for creative ways to use hardware and software. This time,We decided to start by building a dashboard that allows the following serial port interactions:We also want to show all the interactions betw

As members of the maker community, we are always looking for creative ways to use hardware and software. This time, Patrick Lima and I decided we wanted to expand the Raspberry Pi's ports using an Arduino board, so we could access more functionality and ports and add a layer of protection to the device. There are a lot of ways to use this setup, such as building a solar panel that follows the sun, a home weather station, joystick interaction, and more.

We decided to start by building a dashboard that allows the following serial port interactions:

  • Control three LEDs to turn them on and off
  • Control three LEDs to adjust their light intensity
  • Identify which ports are being used
  • Show input movements on a joystick
  • Measure temperature

We also want to show all the interactions between ports, hardware, and sensors in a nice user interface (UI) like this:

You can use the concepts in this article to build many different projects that use many different components. Your imagination is the limit!

1. Get started

The first step is to expand the Raspberry Pi's ports to also use Arduino ports. This is possible using Linux ARM's native serial communication implementation that enables you to use an Arduino's digital, analogical, and Pulse Width Modulation (PWM) ports to run an application on the Raspberry Pi.

This project uses TotalCross , an open source software development kit for building UIs for embedded devices, to execute external applications through the terminal and use the native serial communication. There are two classes you can use to achieve this: Runtime.exec and PortConnector . They represent different ways to execute these actions, so we will show how to use both in this tutorial, and you can decide which way is best for you.

To start this project, you need:

  • 1 Raspberry Pi 3
  • 1 Arduino Uno
  • 3 LEDs
  • 2 resistors between 1K and 2.2K ohms
  • 1 push button
  • 1 potentiometer between 1K and 50K ohms
  • 1 protoboard (aka breadboard)
  • Jumpers

2. Set up the Arduino

Create a communication protocol to receive messages, process them, execute the request, and send a response between the Raspberry Pi and the Arduino. This is done on the Arduino.

2.1 Define the message format

Every message received will have the following format:

  • Indication of the function called
  • Port used
  • A char separator, if needed
  • A value to be sent, if needed
  • Indication of the message's end

The following table presents the list of characters with their respective functions, example values, and descriptions of the example. The choice of characters used in this example is arbitrary and can be changed anytime.

Characters Function Example Description of the example
* End of the instruction - -
, Separator - -
# Set mode #8,0* Pin 8 input mode
< Set digital value <1,0* Set pin 1 low
> Get digital value >13* Get value pin 13
+ Get PWM value +6,250* Set pin 6 value 250
- Get analogic value -14* Get value pin A0

2.2 Source code

The following source code implements the communication protocol specified above. It must be sent to the Arduino, so it can interpret and execute messages' commands:

void setup ( ) {

Serial. begin ( 9600 ) ;

Serial. println ( "Connected" ) ;

Serial. println ( "Waiting command..." ) ;

}

void loop ( ) {

String text = "" ;

char character ;

String pin = "" ;

String value = "0" ;

char separator = '.' ;

char inst = '.' ;

while ( Serial. available ( ) ) { // verify RX is getting data

delay ( 10 ) ;

character = Serial. read ( ) ;

if ( character == '*' ) {

action ( inst , pin , value ) ;

break ;

}

else {

text. concat ( character ) ; }

if ( character == ',' ) {

separator = character ;

if ( inst == '.' ) {

inst = character ; }

else if ( separator != ',' && character != inst ) {

pin. concat ( character ) ; }

else if ( character != separator && character != inst ) {

value. concat ( character ) ; }

}

}

void action ( char instruction , String pin , String value ) {

if ( instruction == '#' ) { //pinMode

pinMode ( pin. toInt ( ) , value. toInt ( ) ) ;

}

if ( instruction == '<' ) { //digitalWrite

digitalWrite ( pin. toInt ( ) , value. toInt ( ) ) ;

}

if ( instruction == '>' ) { //digitalRead

String aux = pin + ':' + String ( digitalRead ( pin. toInt ( ) ) ) ;

Serial. println ( aux ) ;

}

if ( instruction == '+' ) { // analogWrite = PWM

analogWrite ( pin. toInt ( ) , value. toInt ( ) ) ;

}

if ( instruction == '-' ) { // analogRead

String aux = pin + ':' + String ( analogRead ( pin. toInt ( ) ) ) ;

Serial. println ( aux ) ;

}

}

2.3 Build the electronics

Define what you need to test to check communication with the Arduino and ensure the inputs and outputs are responding as expected:

  • LEDs are connected with positive logic. Connect to the GND pin through a resistor and activate it with the digital port I/O 2 and PWM 3.
  • The button has a pull-down resistor connected to the digital port I/O 4, which sends a signal of 0 if not pressed and 1 if pressed.
  • The potentiometer is connected with the central pin to the analog input A0 with one of the side pins on the positive and the other on the negative.

2.4 Test communications

Send the code in section 2.2 to the Arduino. Open the serial monitor and check the communication protocol by sending the commands below:

#2,1*<2,1*>2*

#3,1*+3,10*

#4,0*>4*

#14,0*-14*

This should be the result in the serial monitor:

One LED on the device should be on at maximum intensity and the other at a lower intensity.

leds.jpg

Expand your Raspberry Pi with Arduino ports

(Bruno Muniz, CC BY-SA 4.0 )

Pressing the button and changing the position of the potentiometer when sending reading commands will display different values. For example, turn the potentiometer to the positive side and press the button. With the button still pressed, send the commands:

> 4 *

- 14

*

Two lines should appear:

3. Set up the Raspberry Pi

Use a Raspberry Pi to access the serial port via the terminal using the cat command to read the entries and the echo command to send the message.

3.1 Do a serial test

Connect the Arduino to one of the USB ports on the Raspberry Pi, open the terminal, and execute this command:

cat /dev/ttyUSB0 9600

This will initiate the connection with the Arduino and display what is returned to the serial.

serial-test.png

Expand your Raspberry Pi with Arduino ports

(Bruno Muniz, CC BY-SA 4.0 )

To test sending commands, open a new terminal window (keeping the previous one open), and send this command:

echo "command" > /dev/ttyUSB0 9600

You can send the same commands used in section 2.4.

You should see feedback in the first terminal along with the same result you got in section 2.4:

serial-test2.png

Expand your Raspberry Pi with Arduino ports

(Bruno Muniz, CC BY-SA 4.0 )

4. Create the graphical user interface

The UI for this project will be simple, as the objective is just to show the ports expansion using the serial. Another article will use TotalCross to create a high-quality GUI for this project and start the application backend (working with sensors), as shown in the dashboard image at the top of this article.

This first part uses two UI components: a Listbox and an Edit. These build a connection between the Raspberry Pi and the Arduino and test that everything is working as expected.

Simulate the terminal where you put the commands and watch for answers:

  • Edit is used to send messages. Place it at the bottom with a FILL width that extends the component to the entire width of the screen.
  • Listbox is used to show results, e.g., in the terminal. Add it at the TOP position, starting at the LEFT side, with a width equal to Edit and a FIT height to vertically occupy all space not filled by Edit.

package com.totalcross.sample.serial ;

import totalcross.sys.Settings ;

import totalcross.ui.Edit ;

import totalcross.ui.ListBox ;

import totalcross.ui.MainWindow ;

import totalcross.ui.gfx.Color ;

public class SerialSample extends MainWindow {

ListBox Output ;

Edit Input ;

public SerialSample ( ) {

setUIStyle ( Settings. MATERIAL_UI ) ;

}

@Override

public void initUI ( ) {

Input = new Edit ( ) ;

add ( Input, LEFT, BOTTOM, FILL, PREFERRED ) ;

Output = new ListBox ( ) ;

Output. setBackForeColors ( Color . BLACK , Color . WHITE ) ;

add ( Output, LEFT, TOP, FILL, FIT ) ;

}

}

It should look like this:

ui.png

Expand your Raspberry Pi with Arduino ports

(Bruno Muniz, CC BY-SA 4.0 )

5. Set up serial communication

As stated above, there are two ways to set up serial communication: Runtime.exec and PortConnector.

5.1 Option 1: Use Runtime.exec

The java.lang.Runtime class allows the application to create a connection interface with the environment where it is running. It allows the program to use the Raspberry Pi's native serial communication.

Use the same commands you used in section 3.1, but now use the Edit component on the UI to send the commands to the device.

Read the serial

The application must constantly read the serial, and if a value is returned, add it to the Listbox using threads. Threads are a great way to work with processes in the background without blocking user interaction.

The following code creates a new process on this thread that executes the cat command, tests the serial, and starts an infinite loop to check if something new is received. If something is received, the value is added to the next line of the Listbox component. This process will continue to run as long as the application is running:

new Thread ( ) {

@Override

public void run ( ) {

try {

Process Runexec2 = Runtime . getRuntime ( ) . exec ( "cat /dev/ttyUSB0 9600 \n " ) ;

LineReader lineReader = new LineReader ( Stream. asStream ( Runexec2. getInputStream ( ) ) ) ;

String input ;

while ( true ) {

if ( ( input = lineReader. readLine ( ) ) != null ) {

Output. add ( input ) ;

Output. selectLast ( ) ;

Output. repaintNow ( ) ;

}

}

} catch ( IOException ioe ) {

ioe. printStackTrace ( ) ;

}

}

} . start ( ) ;

}

Send commands

Sending commands is a simpler process. It happens whenever you press Enter on the Edit component.

To forward the commands to the device, as shown in section 3.1, you must instantiate a new terminal. For that, the Runtime class must execute a sh command on Linux:

try {

Runexec = Runtime . getRuntime ( ) . exec ( "sh" ) . getOutputStream ( ) } catch ( IOException ioe ) {

ioe. printStackTrace ( ) ;

}

After the user writes the command in Edit and presses Enter , the application triggers an event that executes the echo command with the value indicated in Edit:

Input. addKeyListener ( new KeyListener ( ) {

@Override

public void specialkeyPressed ( KeyEvent e ) {

if ( e. key == SpecialKeys. ENTER ) {

String s = Input. getText ( ) ;

Input. clear ( ) ;

try {

Runexec. write ( ( "echo \" " + s + " \" > /dev/ttyUSB0 9600 \n " ) . getBytes ( ) ) ;

} catch ( IOException ioe ) {

ioe. printStackTrace ( ) ;

}

}

}

@Override

public void keyPressed ( KeyEvent e ) { } //auto-generate code

@Override

public void actionkeyPressed ( KeyEvent e ) { } //auto-generate code

} )

;

Run the application on the Raspberry Pi with the Arduino connected and send the commands for testing. The result should be:

Runtime.exec source code

Following is the source code with all parts explained. It includes the thread that will read the serial on line 31 and the KeyListener that will send the commands on line 55:

package com.totalcross.sample.serial ;

import totalcross.ui.MainWindow ;

import totalcross.ui.event.KeyEvent ;

import totalcross.ui.event.KeyListener ;

import totalcross.ui.gfx.Color ;

import totalcross.ui.Edit ;

import totalcross.ui.ListBox ;

import java.io.IOException ;

import java.io.OutputStream ;

import totalcross.io.LineReader ;

import totalcross.io.Stream ;

import totalcross.sys.Settings ;

import totalcross.sys.SpecialKeys ;

public class SerialSample extends MainWindow {

OutputStream Runexec ;

ListBox Output ;

public SerialSample ( ) {

setUIStyle ( Settings. MATERIAL_UI ) ;

}

@Override

public void initUI ( ) {

Edit Input = new Edit ( ) ;

add ( Input, LEFT, BOTTOM, FILL, PREFERRED ) ;

Output = new ListBox ( ) ;

Output. setBackForeColors ( Color . BLACK , Color . WHITE ) ;

add ( Output, LEFT, TOP, FILL, FIT ) ;

new Thread ( ) {

@Override

public void run ( ) {

try {

Process Runexec2 = Runtime . getRuntime ( ) . exec ( "cat /dev/ttyUSB0 9600 \n " ) ;

LineReader lineReader = new

LineReader ( Stream. asStream ( Runexec2. getInputStream ( ) ) ) ;

String input ;

while ( true ) {

if ( ( input = lineReader. readLine ( ) ) != null ) {

Output. add ( input ) ;

Output. selectLast ( ) ;

Output. repaintNow ( ) ;

}

}

} catch ( IOException ioe ) {

ioe. printStackTrace ( ) ;

}

}

} . start ( ) ;

try {

Runexec = Runtime . getRuntime ( ) . exec ( "sh" ) . getOutputStream ( ) ;

} catch ( IOException ioe ) {

ioe. printStackTrace ( ) ;

}

Input. addKeyListener ( new KeyListener ( ) {

@Override

public void specialkeyPressed ( KeyEvent e ) {

if ( e. key == SpecialKeys. ENTER ) {

String s = Input. getText ( ) ;

Input. clear ( ) ;

try {

Runexec. write ( ( "echo \" " + s + " \" > /dev/ttyUSB0 9600 \n " ) . getBytes ( ) ) ;

} catch ( IOException ioe ) {

ioe. printStackTrace ( ) ;

}

}

}

@Override

public void keyPressed ( KeyEvent e ) {

}

@Override

public void actionkeyPressed ( KeyEvent e ) {

}

} ) ;

}

}

5.2 Option 2: Use PortConnector

PortConnector is specifically for working with serial communication. If you want to follow the original example, you can skip this section, as the intention here is to show another, easier way to work with serial.

Change the original source code to work with PortConnector:

package com.totalcross.sample.serial ;

import totalcross.io.LineReader ;

import totalcross.io.device.PortConnector ;

import totalcross.sys.Settings ;

import totalcross.sys.SpecialKeys ;

import totalcross.ui.Edit ;

import totalcross.ui.ListBox ;

import totalcross.ui.MainWindow ;

import totalcross.ui.event.KeyEvent ;

import totalcross.ui.event.KeyListener ;

import totalcross.ui.gfx.Color ;

public class SerialSample extends MainWindow {

PortConnector pc ;

ListBox Output ;

public SerialSample ( ) {

setUIStyle ( Settings. MATERIAL_UI ) ;

}

@Override

public void initUI ( ) {

Edit Input = new Edit ( ) ;

add ( Input, LEFT, BOTTOM, FILL, PREFERRED ) ;

Output = new ListBox ( ) ;

Output. setBackForeColors ( Color . BLACK , Color . WHITE ) ;

add ( Output, LEFT, TOP, FILL, FIT ) ;

new Thread ( ) {

@Override

public void run ( ) {

try {

pc = new PortConnector ( PortConnector. USB , 9600 ) ;

LineReader lineReader = new LineReader ( pc ) ;

String input ;

while ( true ) {

if ( ( input = lineReader. readLine ( ) ) != null ) {

Output. add ( input ) ;

Output. selectLast ( ) ;

Output. repaintNow ( ) ;

}

}

} catch ( totalcross. io . IOException ioe ) {

ioe. printStackTrace ( ) ;

}

}

} . start ( ) ;

Input. addKeyListener ( new KeyListener ( ) {

@Override

public void specialkeyPressed ( KeyEvent e ) {

if ( e. key == SpecialKeys. ENTER ) {

String s = Input. getText ( ) ;

Input. clear ( ) ;

try {

pc. writeBytes ( s ) ;

} catch ( totalcross. io . IOException ioe ) {

ioe. printStackTrace ( ) ;

}

}

}

@Override

public void keyPressed ( KeyEvent e ) {

}

@Override

public void actionkeyPressed ( KeyEvent e ) {

}

} ) ;

}

}

You can find all the code in the project's repository .

6. Next steps

This article shows how to use Raspberry Pi serial ports with Java by using either the Runtime or PortConnector classes. You can also call external files in other languages and create countless other projects—like a water quality monitoring system for an aquarium with temperature measurement via the analog inputs, or a chicken brooder with temperature and humidity regulation and a servo motor to rotate the eggs.

A future article will use the PortConnector implementation (because it is focused on serial connection) to finish the communications with all sensors. It will also add a digital input and complete the UI.

Here are some references for more reading:

After you connect your Arduino and Raspberry Pi, please leave comments below with your results. We'd love to read them!


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

不是为了快乐

不是为了快乐

宗萨蒋扬钦哲仁波切 / 姚仁喜 / 深圳报业集团出版社 / 2013-1 / 38.00元

前行修持是一套完整的实修系统,它既是一切佛法修持的根基,又囊括了所有修持的精华,以及心灵之道上所需的一切;既适合入门者打造学佛基本功,也是修行人需要终生修持的心法。书中除了实际的方法指导之外,还不断启发佛法的珍贵与修持的必要,并处处可见对学佛者的鼓舞和纠正,其最终的用心,是让我们踏上不间断的修持之路,真正转化我们僵硬、散乱和困惑的心。 在现代人看来,快乐,理应是最值得追求的目标。我们希望生活......一起来看看 《不是为了快乐》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具