I would like to program a Raspberry Pi to take a single keyboards inputs in one USB port and then output through the Pi's two other USB ports in order to control two Macs at once with one keyboard.
I'm very new to Python. Which functions and commands do I need in order to program this function to my Pi?
I've been searching for the proper command, but I came here for help.
This isn't exactly something easily done with Python. This is because you're delving into developing device drivers on your Macs' side. Please allow me to explain:
Assuming you're using Raspbian on the Raspberry Pi (a flavor of Linux, and thus a Posix system onto itself), you would need to read the appropriate /dev/tty* file which maps to your keyboard first, and then appropriately convert and write out to the appropriate /dev/usb* files. Do note, most computers also send handshakes back and forth to the USB devices (for example, to register them on their own USB busses).
To be frank, you'd probably have better luck splicing wires from your keyboard, and connecting it to another USB male-socket, and then plugging both male-socket ends into your Macs.
Related
My ultimate goal is to control a number of peripheral chips on a PCB from a GUI interface on a PC. To do so, my plan was to incorporate a RP2040 (and memory) on the PCB in order to hold all the python scripts and to program/monitor all the peripheral chips. Then, using a PC to interface with the RP2040, send commands over the serial port to execute specific python files on the pico.
I realize that is a bit confusing, so the attached block diagram should help.
Block diagram
Starting on the left of the block diagram, I have a PC running a tkinter GUI. I am currently running the tkinter gui in Thonny. (eventually i would like it to be an executable, but that is beyond the scope of this post) The gui has a number of buttons to choose which python scripts to run. The PC is connected to the PCB through the USB cable. The USB data lines are routed to the RP2040's USB inputs (pins 47,48). The memory on the PCB holds a number of python scrips that correspond to the buttons in the GUI. Ideally, pressing a button on the PC would execute the corresponding py file on the pcb.
What I've got working so far:
My real expertise lies in peripheral chips and PCB design, in this case the front end for a 2-18GHz transceiver, so bare with me if some of my python questions seem basic or misinformed. I've written and tested all the .py files on the pico's memory. To test those scripts I used Thonny to connect to my pico and simply ran (f5) the scripts with the peripherals connected to the right GPIOs. I was also able to get tkinter working and create functioning buttons that can execute commands. Using the pyserial module, I am also able to connected to the pico through the USB and write... strings. Not very useful, but a start.
import serial
ser = serial.Serial('COM3', 38400, timeout=1, parity=serial.PARITY_EVEN, rtscts=1)
s = ser.read(100) # read up to one hundred bytes or as much is in the buffer
print(ser.name) # check which port was really used
ser.write(b'ToggleLED.py') # write a string
ser.close() # close port
Remaining task: The final task I have been failing miserably at the past 2 days has been actually trying to execute the .py files located on the pico's memory through the serial port. My unexperienced/naïve notion was to simply send a string with the files name, obviously not correct. Any thoughts on how to execute those py files using that pyserial module?
BTW, if there is a better solution, please feel free to share! Perhaps the files should be located on the PC and i send 1 command at time?
I can't say anything about your serial problems until you clarify just what is running on the pi (see my comment: I'll update this answer when you do), but re 'is there a better way': possibly.
Since the Pi is running a full operating system, there are a few options. You are basically creating a network connection to the Pi. Whilst this can be done over serial (with the Pi, presumably, acting as a fake USB serial device), it can also be done more conventionally over wifi or ethernet. Lastly, you could host your interface on the Pi and interact with it in a webbrowser, cutting the second computer out of the picture. Exactly which option you decide to take is up to you, and is really off topic here (though it might be on topic elsewhere on SE).
Sending commands to the pi and having it run scripts is Remote Procedure Call. You might want to lookup some of the protocols (like JSON-RPC) generally used to do that, but the basic approach will have code running on the pi:
def do_something():
pass
def do_something_else():
pass
functions = {"something": do_something, "something_else": do_something_else}
while True:
cmd = get_input() # blocks until input comes
if cmd in functions:
reply(f"Running {cmd}")
output = functions[cmd]()
reply(f"{cmd} returned with output {output}")
else:
reply(f"Invalid command {cmd}")
This is schematic: exactly what get_input() on the pi is will depend on how you end up connecting, and what protocol (if any) you end up using. Notice that I have built in confirmation: you want to know if things work or fail.
Whilst you could store these commands in separate scripts and invoke them, if they are just python scripts there is no reason not to call the functions directly from the code running on the pi.
I've seen two different solutions to the question:
With the Pi pico running the REPL (python shell), text strings can simply be sent from a python program running on the host (Windows or Raspberry Pi, etc., connected to the USB com port, with Thonny window closed), and sent to the pico as python commands. This approach is detailed in:
https://blog.rareschool.com/2021/01/controlling-raspberry-pi-pico-using.html
On the pico side, one just need to define a number of functions that will execute from the REPL. E.g.,:
from machine import Pin
# use onboard LED which is controlled by Pin 25
led = Pin(25, Pin.OUT)
# Turn the LED on
def on():
led.value(1)
# Turn the LED off
def off():
led.value(0)
Any string sent to the pico, such as
on()
will be executed accordingly.
In the 2nd approach, the pico will read each line from the USB serial port and parse the line into command and additional parameters, to be compared against a list of predefined commands and executed accordingly. I did that using the Arduino Due, and I'm in the process of porting it to the pico (= no code to show yet :-().
I am looking for a DIY replacement for the $1500 Go-Box for mass provisioning Chromebooks. I have managed to replicate this by using a Raspberry Pi Pico as the "HID Emulation". However, I need this on a mass scale. I want to be able to do 20 Chromebooks at one time. I can do this with just 20 Raspberry Pi Picos but I need to change the script every 100-150 Chromebooks I provision (changing credentials etc.). Changing each script manually is time-consuming, so I need to be able to change all 20 scripts at once, or one "master" script that the "slave" Picos go and get on boot.
At first, I thought about an SD card they can all read from and when needed, I can take it out and change the script on there, and then when the Pico boots it can copy the new script to the root of the Pico. However, this may be an issue since I do not know if the Picos will clash with each other when trying to read the script from the same place at the same time. This is my first issue.
Then I thought about a Master and Slaves setup. One Pico acts as a Master and holds the script. The other 20 are slaves that get the script from the Master when a pin is high (to signify the Picos need reprogramming). I would only use the Master when reprogramming the script. When I turn the Master on, I would have it set a pin to high and all the other slaves would check on the boot to see if the pin is high. If the Slaves find that the pin is high, it won't run the script, but it will update it from the Master. This is where I run into the problem with this method. I need to transfer the script from Master to Slaves. I haven't got any experience in communication protocols like UART, SPI, or I2C but I understand that if I want to do multiple Slaves, then I am better off using I2C.
This is my last resort since I have been googling for days and can't find a suitable solution. Is anyone able to provide any insight on any of the following:
How to get the script from one place to twenty?
Will the SD card idea clash when all 20 Picos try to access it?
How to transfer files over I2C or similar protocol?
I appreciate any help anyone can provide. I am using MicroPython v1.16 on 2021-06-18; Raspberry Pi Pico with RP2040
The pico has a uart (2 actually) which is easy to program; there are lots of examples of serial communication with the pico, typically to a full Raspberry Pi.
You could join all the rx receiver pins on the picos to the master tx transmit pin and talk to them all in parallel, with no replies.
I don't know if it is possible to tri-state the tx pins so that they could all be connected too, but only one enabled at a time, by sending suitable commands from the master tx. The problem is that the electrical load of 20 receivers, and the excessive length of the parallel cabling might not give error free transfers.
Or you could daisy chain the serial ports so the rx of pico1 is read by the software there and repeated out on its tx, which is connected to the rx of pico2, and so on. You can start each data packet with a "node number", which each pico decrements before sending it on. If this number is 1, then the packet appplies to this node. This is a sort of auto-numbering of the picos. A number like 255 can be used for a broadcast.
If the last pico's tx is wired back to the master you can even allow any pico to send a reply, provided the software waits for a break in incoming data.
It also allow for rudimentary flow control and error checking. If the master sends only 1 byte at a time, and waits for each byte to be "echoed" back from the last pico, it can ensure everyone has seen the data. Also, each serial segment can be short so there are no electrical load problems, or signal corruption.
Look at the gpib bus which daisy chains something like this, or at the simple individually-addressible RGB leds like the WS2812B which are also daisy chained.
How can I set HIGH or LOW to a usb port connections using Python.
This could be used in come custom usb device.
For Example,
Consider I have a LED connected to the usb port(DATA Line) .
Now through the code I want to blink it or control it.
Now this can be easily achieved by using any micro controller, Arduino, Raspberry Pi
But I want to achieve this with with a normal computer and python.
[EDIT]
Can I achieve this by making a C or C++ API and make a wrapper to use it in Python. Is yes then what will be the best way to achieve it?
NOTE :
My main objective isn't just blinking some LED. I just gave it as an example.
I want to be able to directly control the USB ports.
Quoting : https://www.cmd-ltd.com/advice-centre/usb-chargers-and-power-modules/usb-and-power-module-product-help/usb-data-transfer-guide/#:~:text=How%20is%20data%20sent%20across,amounts%20known%20as%20'packets'.
Within the standard USB 2.0 connector you can see four metal strips. The outer two strips are the positive and ground of the power supply. The two central strips are dedicated to carrying data.
With the newer USB 3.0 connector, the data transfer speed is increased by the addition of extra data-carrying strips; four extra signalling wires help USB 3.0 achieve its super speed.
I want to set the values of the Data pins.
By my saying HIGH LOW please don't misunderstand that I want to set the value to +5V and GND. But I mean to control its value directly via my code without any external driver present in the computer.
I mentioned HIGH LOW to just make the language simple and so that it is easier to understand.
Controlling components like LEDs from devices like Arduino and Raspberry Pi are done using GPIO pins. In contrast, USB is designed for data transfer and not for maintaining more constant high or low signals like GPIO. It also consumes different voltage and current levels than GPIO pins and could potentially damage components meant for GPIO.
However, you can get USB to GPIO adapters for this purpose (see here for an example discussion on these options).
In terms of Python, you can use packages such as PyUSB or the libusb Python wrapper to control/transfer data/communicate with USB devices (such as the USB to GPIO adapters). The companies providing the adapters might also have designed their own easy-to-use Python package to wrap around a lower-level driver (probably written in C). See this USB controlled LED device as an example with its own Python driver. The drivers are just software programs that take in relatively simple commands from the user for what they want a device to do. They then encapsulate the lower-level complexities required for following a protocol to communicate the user's intention to the USB device and controlling the USB port at the lowest possible software level.
You cannot achieve that for several reasons:
The USB port has its own protocol of connection. Data is transmitted in packets with starting and ending bits. The negotiation and handshake process is done in the hardware layer between microchips. This process also selects the communication speed in the bidirectional data line. You have to direct access to the pin (like GPIO) to turn LEDs ON and Off or create your own connection protocol. This cannot be done in USB.
There are also voltage and current limitations. The data line is not +5 and GND. The data line is 2.8v for D+ and 0.3v for D- and both with respect to the GND. The data is transmitted and received differentially (D+ with respect to D-) and they are not compared with the GND for 1s and 0s.
The button line is you have no direct control over USB.
I want to make a simple python program, which controls my laptop's usb hubs. Nothing extra, just put first usb port's DATA+ channel into HIGH (aka 5V) or LOW (aka 0 V) state.
Python is way to highlevel for this problem, this behavior would require you to rewrite the USB Driver of your OS.
I don't think you can do this. Even if you knew how to write low-level drivers for your operating system, this is probably not possible because the data pins of USB ports are only designed to output voltages between 0 and 3.3 V. They are also designed to send and receive USB packets, not arbitrary voltages.
Instead, you should get a small programmable microcontroller with a normal USB interface and use its output pins.
This may seem like a bit of an odd question, but I was wondering if it is possible to associate two drivers with a peripheral device?
The reason I ask is that I am building an input device for Maya using an Arduino microcontroller. The Arduino already has its own device driver, but I was thinking of developing a UMDF driver to take the data that comes in from Arduino over the serial port and pre-process it ready to go into Maya.
Right now, I have two Python programs running - a 32-bit Python program running outside of Maya which listens to the serial port and converts the data to a form which a second 64-bit program inside the 64-bit version of Maya can understand and use in the Maya scene. This works fine, but it is a bit annoying having to start that external server program every time I want to use this device in Maya. If I can have a UMDF driver ready to jump into action when the appropriate type of data comes in off the Arduino then this would help immensely. Will this approach work?
It's more a comment/suggestion than an answer, but maybe it would be worth to invest some time and check if the filter driver would do the job for you. In WDM you can put it above the kernel device driver on the driver stack for that device, and use it to pre-process your device data. I think it is also possible in UMDF.
See Creating a New Filter Driver (MSDN).
You may always try to use Teensy/Teensyduino instead of Arduino to implement a virtual keyboard, mouse, joystick or other HID device. This does not require Windows drivers, and accessing the keyboard or joystick from Maya may be easier that the serial port.