Code Monkey home page Code Monkey logo

rpi_gpio's Introduction

rpi_gpio v0.5.0

Ruby conversion of RPi.GPIO Python module

Features

Manipulate your Raspberry Pi's GPIO pins from Ruby!

  • Boolean input/output
  • Software-driven PWM (written in C for speed)
  • Event-driven input (blocking and non-blocking)

Up-to-date with RPi.GPIO Python module version 0.7.0, so it works on all Raspberry Pi models!

Sample Usage

I aimed to make the gem's usage exactly the same as its Python counterpart -- only with a few semantic differences to utilize Ruby's readability. If anything is confusing, you can always check here for the original Python module's documentation.

Download the gem

The easiest way to download the gem is to use Bundler with a Gemfile. In your Gemfile, include the line

gem 'rpi_gpio'

Then you can run bundle install to automatically download and compile the gem for your system. To include the gem in a Ruby file, use the line require 'rpi_gpio'.

Pin numbering

Before you can do anything with the GPIO pins, you need to specify how you want to number them.

RPi::GPIO.set_numbering :board
# or
RPi::GPIO.set_numbering :bcm

:board numbering refers to the physical pin numbers on the Pi, whereas :bcm numbering refers to the Broadcom SOC channel numbering. Note that :bcm numbering differs between Pi models, while :board numbering does not.

Input

To receive input from a GPIO pin, you must first initialize it as an input pin:

RPi::GPIO.setup PIN_NUM, :as => :input
# or
RPi::GPIO.setup [PIN1_NUM, PIN2_NUM, ...], :as => :input

The pin number will differ based on your selected numbering system and which pin you want to use.

You can use the additional hash argument :pull to apply a pull-up or pull-down resistor to the input pin like so:

RPi::GPIO.setup PIN_NUM, :as => :input, :pull => :down
# or
RPi::GPIO.setup PIN_NUM, :as => :input, :pull => :up
# or (not necessary; :off is the default value)
RPi::GPIO.setup PIN_NUM, :as => :input, :pull => :off

Now you can use the calls

RPi::GPIO.high? PIN_NUM
RPi::GPIO.low? PIN_NUM

to receive either true or false.

If you prefer to use a callback when a pin edge is detected, you can use the watch method:

RPi::GPIO.watch PIN_NUM, :on => :rising do |pin, value| # :on supports :rising, :falling, and :both
  ...
end

watch also supports the optional bounce_time parameter found in the Python module to prevent duplicate events from firing:

RPi::GPIO.watch PIN_NUM, :on => :falling, :bounce_time => 200 do |pin, value|
  ...
end

To stop watching a pin, use stop_watching:

RPi::GPIO.stop_watching PIN_NUM

If you want to block execution until a pin edge is detected, there's wait_for_edge:

puts 'Waiting to start...'
RPi::GPIO.wait_for_edge PIN_NUM, :rising # :rising, :falling, and :both are also supported here
puts 'Here we go!'

wait_for_edge accepts optional bounce_time and timeout arguments too:

puts 'Waiting to start...'
value = RPi::GPIO.wait_for_edge PIN_NUM, :falling, :bounce_time => 200, :timeout => 5000
if value.nil? # nil is returned if the timeout is reached
  print 'You took too long. '
end
puts 'Here we go!'

Output

To send output to a GPIO pin, you must first initialize it as an output pin:

RPi::GPIO.setup PIN_NUM, :as => :output
# or
RPi::GPIO.setup [PIN1_NUM, PIN2_NUM, ...], :as => :output

Now you can use the calls

RPi::GPIO.set_high PIN_NUM
RPi::GPIO.set_low PIN_NUM

to set the pin either high or low.

You can use the additional hash argument :initialize to set the pin's initial state like so:

RPi::GPIO.setup PIN_NUM, :as => :output, :initialize => :high
# or
RPi::GPIO.setup PIN_NUM, :as => :output, :initialize => :low

PWM (pulse-width modulation)

Pulse-width modulation is a useful tool for controlling things like LED brightness or motor speed. To utilize PWM, first create a PWM object for an output pin.

pwm = RPi::GPIO::PWM.new(PIN_NUM, PWM_FREQ)

The PWM_FREQ is a value in hertz that specifies the amount of pulse cycles per second.

Now you can call the following method to start PWM:

pwm.start DUTY_CYCLE

DUTY_CYCLE is a value from 0.0 to 100.0 indicating the percent of the time that the signal will be high.

Once running, you can get/set the PWM duty cycle with

pwm.duty_cycle # get
pwm.duty_cycle = NEW_DUTY_CYCLE # set

get/set the PWM frequency with

pwm.frequency # get
pwm.frequency = NEW_FREQUENCY # set

and get the PWM GPIO number with

pwm.gpio

Note that this number corresponds to :bcm numbering of the GPIO pins, so it will be different than pin number you used if you created the PWM with :board numbering.

To stop PWM, use

pwm.stop

To check if a PWM object is currently running, use

pwm.running?

Cleaning up

After your program is finished using the GPIO pins, it's a good idea to release them so other programs can use them later. Simply call

RPi::GPIO.clean_up PIN_NUM

to release a specific pin, or

RPi::GPIO.clean_up

to release all allocated pins.

Alternatively, you can call

RPi::GPIO.reset

to clean up all pins and to also reset the selected numbering mode.

Credits

Original Python code by Ben Croston modified for Ruby by Nick Lowery

Copyright (c) 2014-2020 Nick Lowery

View LICENSE for full license.

rpi_gpio's People

Contributors

clockvapor avatar codenamev avatar nsatragno avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

rpi_gpio's Issues

Doesn't work properly with more than 2 LEDs

Hi, I created a script that blinks the LEDs on channel 12, 7, and 8.
I am using Arch Linux ARM on Rapsberry Pi 3 model B.
My code:

#!/usr/bin/ruby -w
require 'rpi_gpio'
Object.prepend(RPi::GPIO)

set_warnings(false)
set_numbering(:board)

pins = [12, 7, 8].each { |x| setup(x, as: :output) }
c = pins.size.times.map { |x| ?- * x.next }

begin
	pins.each_with_index do |x, i|
		print "\e[2KPin #{c[i]}> #{x}\r"
		set_high(x)
		Kernel.sleep(0.5)
		set_low(x)
		Kernel.sleep(0.5)
	end while true

rescue SignalException, Interrupt, SystemExit
	pins.each(&method(:clean_up))
	exit 0

rescue Exception => e
	Kernel.warn(e)
	Kernel.sleep 1
	retry
end

I see irregular flashes. The LED [at pin] 12 turns on and off first. Then LED 7, then LED 8 without turning LED 7 off. Then LED 12 goes on and off. Then 7 goes off and on after a while. Then LED 8 goes off and on and it continues. It looks messy. This shouldn't happen! Same happens with PWM...

Keep up!

Keep up the good work, you are awesome!

not running on a RPi

Testing this setup on a Raspberry Pi 2 Zero W, I get an error that it doesn't think it's running on a RPi. I'm not sure if it's the recent release of this unit, so I thought I would post.

RPi::GPIO.set_numbering :board
PINS = [5,7,11,13,14,16,18]

PINS.each do |i|
  RPi::GPIO.setup i, as: :input
  puts "#{ i } high? #{ RPi::GPIO.high?(i) }"
end
Traceback (most recent call last):
	3: from test.rb:22:in `<main>'
	2: from test.rb:22:in `each'
	1: from test.rb:23:in `block in <main>'
test.rb:23:in `setup': not running on a RPi (RuntimeError)

Emulation of GPIO

It'd be nice to be able to build this on other operating systems, and have it simply emulate GPIO.

For instance, you could set direction/value and read back from it.

This would allow us to run unit tests against code using GPIO without being on a raspberry pi or having GPIO pins :)

Trying to run this gem within Docker, however it returns the error 'RuntimeError: this gem can only be run on a Raspberry Pi'

I'm running the latest hypriot version of Raspbian (Jessie) which is running Ruby (2.2.0) inside a Docker container and I have installed the gem rpi_gpio. When I open an irb session and after entering require 'rpi_gpio', it returns the error message

RuntimeError: this gem can only be run on a Raspberry Pi 

Can you fix it to run without a problem inside Docker on the Raspberry Pi?

rpi_gpio.so compiled as 32-bit on 64-bit system

On Ubuntu 20.04 LTS 64-bit, the gem installs fine but rpi_gpio.so is compiled as a 32-bit lib.

"rpi_gpio.so: wrong ELF class: ELFCLASS32"

ubuntu@rpi4:~/test$ uname -a
Linux rpi4 5.4.0-1018-raspi #20-Ubuntu SMP Sun Sep 6 05:11:16 UTC 2020 aarch64 aarch64 aarch64 GNU/Linux
ubuntu@rpi4:~/test$ rbenv version
2.7.1 (set by /home/ubuntu/.rbenv/version)
ubuntu@rpi4:~/test$ 

ubuntu@rpi4:~/test$ cat test.rb 
require 'rpi_gpio'
ubuntu@rpi4:~/test$ bundle exec ruby test.rb 
Traceback (most recent call last):
	3: from test.rb:1:in `<main>'
	2: from test.rb:1:in `require'
	1: from /home/ubuntu/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/rpi_gpio-0.5.0/lib/rpi_gpio.rb:1:in `<top (required)>'
/home/ubuntu/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/rpi_gpio-0.5.0/lib/rpi_gpio.rb:1:in `require': /home/ubuntu/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/rpi_gpio-0.5.0/lib/rpi_gpio/rpi_gpio.so: wrong ELF class: ELFCLASS32 - /home/ubuntu/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/rpi_gpio-0.5.0/lib/rpi_gpio/rpi_gpio.so (LoadError)
ubuntu@rpi4:~/test$

wrong commit author

Hey man, I hate to bug you with this but my commit/pull request was submitted with the wrong git author/email. I know it's inconvenient but I would greatly appreciate if you would roll back to before my pull request so I can create a new one with my updated settings. I have already fixed it on my end.

How to read the status of an output pin

Will be useful to be able to β€œread” status of output pin (High/Low).

In Python version you can do that by this syntax:

GPIO.input(PIN_NUM)

I checked specs and not found an option for reading status of an output pin.

based on source code of high?/low? methods working only with "Input".

Can't require gem on RPi 3B+

I am getting an wrong ELF class: ELFCLASS32 when trying to require gem. Tested on ruby 2.7.0 and 2.5.7

Full output:

Traceback (most recent call last):
2: from pwm.rb:1:in <main>' 1: from /usr/share/rvm/rubies/ruby-2.7.0/lib/ruby/2.7.0/rubygems/core_ext/kernel_require.rb:92:in require'
/usr/share/rvm/rubies/ruby-2.7.0/lib/ruby/2.7.0/rubygems/core_ext/kernel_require.rb:92:in require': cannot load such file -- rpi_gpio (LoadError) 6: from pwm.rb:1:in

'
5: from /usr/share/rvm/rubies/ruby-2.7.0/lib/ruby/2.7.0/rubygems/core_ext/kernel_require.rb:156:in require' 4: from /usr/share/rvm/rubies/ruby-2.7.0/lib/ruby/2.7.0/rubygems/core_ext/kernel_require.rb:168:in rescue in require'
3: from /usr/share/rvm/rubies/ruby-2.7.0/lib/ruby/2.7.0/rubygems/core_ext/kernel_require.rb:168:in require' 2: from /home/egorpr0/.rvm/gems/ruby-2.7.0/gems/rpi_gpio-0.5.0/lib/rpi_gpio.rb:1:in <top (required)>'
1: from /usr/share/rvm/rubies/ruby-2.7.0/lib/ruby/2.7.0/rubygems/core_ext/kernel_require.rb:92:in require' /usr/share/rvm/rubies/ruby-2.7.0/lib/ruby/2.7.0/rubygems/core_ext/kernel_require.rb:92:in require': /home/egorpr0/.rvm/gems/ruby-2.7.0/gems/rpi_gpio-0.5.0/lib/rpi_gpio/rpi_gpio.so: wrong ELF class: ELFCLASS32 - /home/egorpr0/.rvm/gems/ruby-2.7.0/gems/rpi_gpio-0.5.0/lib/rpi_gpio/rpi_gpio.so (LoadError)

Happy to perform some testing!

Channels switch on(low) when setting to output.

I don't know if this is a bug or something wrong with my setup but at the beginning of the script I'm working on I initialize like so:

RPi::GPIO.set_numbering :board
pin = {1=>5,2=>7,3=>8,4=>10,5=>11,6=>12,7=>13,8=>15,9=>16,10=>18,11=>19,12=>21,13=>22,14=>23,15=>24,16=>26}
for i in 1..16
RPi::GPIO.setup pin[i], :as => :output
RPi::GPIO.set_high pin[i]
end

Yet all the channels switch on, regardless of the set_high directive.
I looked at the source for this and the py version but couldn't figure out a solution.
The python version accepts a third argument GPIO.setup(channel, GPIO.OUT, initial=GPIO.HIGH).
Is there an equivalent argument in this version?

event_detected() function

Hello, I would like to know the way to use event_detected() function and wait_for_edge() function
Thanks in advance.

Cannot open shared object

Getting next error on a rpi 3B+

	5: from /usr/lib/ruby/2.5.0/rubygems/core_ext/kernel_require.rb:39:in `require'
	4: from /usr/lib/ruby/2.5.0/rubygems/core_ext/kernel_require.rb:135:in `rescue in require'
	3: from /usr/lib/ruby/2.5.0/rubygems/core_ext/kernel_require.rb:135:in `require'
	2: from /var/lib/gems/2.5.0/gems/rpi_gpio-0.5.0/lib/rpi_gpio.rb:1:in `<top (required)>'
	1: from /usr/lib/ruby/2.5.0/rubygems/core_ext/kernel_require.rb:59:in `require'
/usr/lib/ruby/2.5.0/rubygems/core_ext/kernel_require.rb:59:in `require': libruby.so.2.7: cannot open shared object file: No such file or directory - /var/lib/gems/2.5.0/gems/rpi_gpio-0.5.0/lib/rpi_gpio/rpi_gpio.so (LoadError)

Can't Require Gem on RPi 4

I get a load error on a Raspberry Pi 4B for version 0.5.0. Version 0.4.0 loads without issue, here's the stack trace

I see the Readme mentions Ruby 2.0.0 as the highest version tested, but on the Pi4, 2.4 is the lowest version I could easily install with rbenv.

irb(main):001:0> require 'rpi_gpio'
LoadError: libruby.so.2.7: cannot open shared object file: No such file or directory - /home/pi/.rbenv/versions/2.4.0/lib/ruby/gems/2.4.0/gems/rpi_gpio-0.5.0/lib/rpi_gpio/rpi_gpio.so
	from /home/pi/.rbenv/versions/2.4.0/lib/ruby/gems/2.4.0/gems/rpi_gpio-0.5.0/lib/rpi_gpio.rb:1:in `require'
	from /home/pi/.rbenv/versions/2.4.0/lib/ruby/gems/2.4.0/gems/rpi_gpio-0.5.0/lib/rpi_gpio.rb:1:in `<top (required)>'
	from (irb):1:in `require'
	from (irb):1
        [ bundler stack trace continues ]

lib/rpi_gpio/rpi_gpio.so does exist on my machine. I also tried using the code from #20, but get the RuntimeError: this gem can only be run on a Raspberry Pi.

Happy to perform any debugging steps on my machine

Wrong ELF class on RPZ2

Reinstalled rpi_gpio 0.5.0 and it's reporting this issue on Bundler.require:

1: from /home/rich/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/rpi_gpio-0.5.0/lib/rpi_gpio.rb:1:in `<top (required)>'
/home/rich/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/rpi_gpio-0.5.0/lib/rpi_gpio.rb:1:in `require': /home/rich/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/rpi_gpio-0.5.0/lib/rpi_gpio/rpi_gpio.so: wrong ELF class: ELFCLASS32 - /home/rich/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/rpi_gpio-0.5.0/lib/rpi_gpio/rpi_gpio.so (LoadError)

I've closed ssh sessions, and same issue. Nothing else reporting errors, but then I'm not doing much on it outside of trying to get pins working.

is this only for raspberry pi?

Hi, i was wondering to use this library for raspberrypi , but i needed to contribute between raspi gpio pins and other micro controller such as ESP8266 , is controlling pins on other modules possible with this library? and is it same usage as raspberrypi?

Toggle method

Hello,

I would be nice to have a toggle method that took a bool in addition to the set_low and set_hight methods.
Very often I'm writing things like

RPi::GPIO.send(state ? :set_high : :set_low, gpio)

It could event toggle the state if no bool is provided but it's less needed.
What do you think ?

Cheers

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.