Using python serial connection to communicate with Roboclaw motorcontroller - python

So im newish to python and im trying to use the following program to control a roboclaw motor controller. I have one motor i am just trying to turn via serial commands and am failing miserably. Everything works well with pwm using an arduino but when i run it via raspi over serial in python...it just turns slow and always in the same direction. Roboclaw specifies that full fwd motion achieved by sending 127, 64 is stop, and 1 is full reverse. Electrically its connected appropriately and the motorcontroller is set to the right setting and baudrate, but something with this code is no good...just turns slow and only in one direction and never stops with the stop command. Help an old man out and let me know what you think. The code is as follows:
import RPi.GPIO as GPIO
import time
import serial
GPIO.setmode(GPIO.BOARD)
ser = serial.Serial(
port='/dev/ttyS0',
baudrate = 38400,
parity =serial.PARITY_NONE,
stopbits=serial.STOPBITS_ONE,
bytesize=serial.EIGHTBITS,
timeout=1)
#allstop = 0b00000000 or 0
#fwd = 0b00000001 or 1
#stop = 0b01000000 or 64
#rev = 0b01111111 or 127
ser.write('00000001')
time.sleep(5)
ser.write('01000000')
time.sleep(5)
ser.write('01111111')
time.sleep(5)
ser.write('00000000')
print 'done'

Related

How to send string to arduino from raspberry pi using python

I have an Arduino microcontroller (Adafruit feather M0), and if I have it plugged into my windows PC and open the serial monitor, I can type P 0 2 1 0 and then enter, the Arduino interprets this command and works as expected.
Now I want to plug in the same device into my raspberry pi, and have python do this instead.
I have done this in the past on a different microcontroller (sparkfun pro micro) and it worked great. I can't seem to get it to work and am not sure what I am missing.
python code:
import serial
import time
ser = serial.Serial('/dev/ttyACM0', 115200, timeout = None)
time.sleep(2)
returnKey = "\r\n"
ser.write(str.encode("P 2 1 0"))
ser.write(str.encode(returnKey)
The code finishes, but the Arduino simply does nothing, as if it discarded the command or didn't get it at all.
The serial speed is matching on the Arduino too (115200).
I also tried:
ser.write(b'P 2 1 0')
ser.write(returnKey.encode())
Any ideas what I am missing here?
Solved it.
Ended up using
import serial
import time
ser = serial.Serial('/dev/ttyACM0', 115200, timeout = None)
time.sleep(2)
ser.write(b'P 2 1 0 \r\n')

Communicate between 2 Raspberry Pi with UART

I want to send data from one pi to another with UART communication. The first Raspberry model is Raspberry Pi 4, and the second one Raspberry Pi 3. To do this communication Im connecting both Raspberry pins in this way:
Pi 4 -> Pi 3
Tx -> Rx
Rx -> Tx
Ground -> Ground
I have already activated both Pis serial connection on the raspberry configuration following the steps of this link: https://iot4beginners.com/raspberry-pi-configuration-settings/. In order to write and send the data I have created the next python program:
import time
import serial
ser = serial.Serial(
port='/dev/ttyS0', #Replace ttyS0 with ttyAM0 for Pi1,Pi2,Pi0
baudrate = 9600,
parity=serial.PARITY_NONE,
stopbits=serial.STOPBITS_ONE,
bytesize=serial.SEVENBITS)
counter=0
while True:
ser.write(str.encode(str(counter)))
time.sleep(1)
counter += 1
To read and print the data received I have created the next program:
import time
import serial
ser = serial.Serial(
port='/dev/ttySO', #Replace ttyS0 with ttyAM0 for Pi1,Pi2,Pi0
baudrate = 9600,
parity=serial.PARITY_NONE,
stopbits=serial.STOPBITS_ONE,
bytesize=serial.SEVENBITS
)
counter=0
while 1:
x = ser.readline()
print(x)
Finally when I run the reading program I get the next error:
Traceback (most recent call last):
File "serial_read.py", line 14, in <module>
x = ser.readline()
File "/usr/lib/python2.7/dist-packages/serial/serialposix.py", line 501, in read
'device reports readiness to read but returned no data '
serial.serialutil.SerialException: device reports readiness to read but returned no data (device disconnected or multiple access on port?)
I'm new to Raspberry communication and I will be thankful for any suggestion.
Python 2.7 is officially dead, so I would recommend using Python3 - especially for new projects such as yours.
So, rather than run your script with:
python3 YourScript.py
you could put a proper shebang at the start so it automatically uses the correct Python version you intended:
#!/usr/bin/env python3
import ...
Then make the script executable with:
chmod +x YourScript.py
Now you can run it with:
./YourScript.py
and be happy it will use Python3, and also even if someone else uses it.
The actual issue, I think, is that the readline() on the receiving end is looking for a newline that you didn't send. So I would try adding one:
ser.write(str.encode(str(counter) + '\n'))
Personally, I find f-strings to be much easier than the older % and .format() stuff, so maybe try:
ser.write(str.encode(f'{counter}\n'))

Python Serial Writing but seemingly not reading. Raspberry Pi 0 to Arduino

I'm having trouble with a python script running on an RPI0 reading serial input from an Arduino. I know the Arduino's code is correct as everything works as intended interacting with the Arduino over the built in serial monitor in the Arduino software(send code a10(code to drive a relay HIGH), Arduino sends back 11(basically asking for how long), send code b5, Arduino will hold pin HIGH for 5 seconds(b5)).
However when I attempt to read any serial input in python using the pyserial module, nothing happens. I know it does successfully send the code to the arduino as it will hold the pin HIGH for the specified seconds when I rewrite the python script with ser.write("a10b5").
The serial connection is NOT USB. I'm using jumper wires with a voltage shifter in between them using the Arduino's and Pi's GPIO TX and RX pins.
using python -V in the terminal it tells me I'm running version 3.8
I've tried multiple baud rates(300, 1200, 9600, 57600) with no change in behavior
I've also tried changing if x == 11: to if x == "11": in case for some reason it was receiving strings and not ints, also to no avail.
Here is the code:
import time
import serial
ser = serial.Serial(
port='/dev/ttyAMA0',
baudrate = 9600,
parity=serial.PARITY_NONE,
stopbits=serial.STOPBITS_ONE,
bytesize=serial.EIGHTBITS,
timeout=None
)
print("sending data over serial now")
ser.write("a10") #a10 is relay HIGH code
while True:
x = ser.read()
if x == 11: ##arduino code 11(asking for how long)
print("recieved code 11")
print("arduino recieved relay HIGH code and is waiting for time to hold relay for")
print("sending time now")
ser.write('a5') # 5 seconds
time.sleep(1)
if x == 13: #arduino code 13(water success)
print("recieved code 13")
print("arduino reports watering complete")
x = 0 ##this is to clear the variable every loop. Not sure if it's needed
And here is a simple serial reader I've pulled from online. Opening it up in a second terminal and running it at the same time with my own script it will actually read the codes from the arduino business as usual.
#!/usr/bin/env python
import time
import serial
ser = serial.Serial(
port='/dev/ttyAMA0',
baudrate = 57600,
parity=serial.PARITY_NONE,
stopbits=serial.STOPBITS_ONE,
bytesize=serial.EIGHTBITS,
timeout=1
)
while True:
x=ser.readline()
print x
What gives?
Answering my own question. In the arduino code I used
Serial.println(whatevergoeshere)
instead of
Serial.print(whatevergoeshere)
So the arduino was sending out '\n' at the end of every serial line that was not being printed by either the arduino serial console and the python script. Updating my IF statements in python to
if x == "11\n":
Solves the issue and everything works as intended.

Raspberry Pi RS485/Uart Modbus

I'm attempting to get an RS485 adapter connected at the UART to communicate via modbus on a Raspberry Pi. My end goal is to have all this working with a Node application, but so far my dev has been with Python.
My hardware connection looks like:
[Modbus-Device] <===> [RS485 chip <==> Raspberry PI GPIO] pins. The RS485 has three wires (Transmit, Receive, Direction) they are connected as follows
RaspiPi <=> Adapter
GPIO 14 (8) - Tx <=> Data+
GPIO 15 (10)- Rx <=>- Data-
GPIO 18 (12) - Direction
The RS485 isn't a typical 9-pin adapter. I have three wires running off a chip. A twisted pair that serves as differential set and a ground wire.
I have been able to send serial communications between this adpater and a USB-RS485 adapter by manually flipping GPIO18 for send/recieve. (Code below)[1]. This code is purely for proving the adapter works
I'm stuck at getting modbus to work on GPIO adapter. I've tried using minimalmodbus, which works well with the USB-RS485 adapter, but fails with the GPIO adapter. I suspect this is because the direction pin isn't being set.
The ideal resolution would be to find an RS485 driver for GPIO on the pi, but short of that I see three options
1 - Make my own driver (Something I am completely unfamiliar with)
2 - Somehow get a modbus library to flip the GPIO pin in Kernel space
3 - Manually send modbus messages over serial and adjust the GPIO pin in user space. This seems the easiest but also the worst in terms of speed and reliability. My code attempt is below [2]
Any advice on this topic would be very appreciated. If someone has done something similar before and could weigh in on my options that would be helpful. I've never worked on software at this level so I wouldn't find it surprising if there were some obvious answer I'm completely overlooking.
[1] This code communicates with another RS485 adapter on the raspberry pi connected with USB. This was written to prove the GPIO adapter is working and that I can control direction with Pin 12 on the Raspberry pi
import time
import serial
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BOARD)
GPIO.setup(12, GPIO.OUT);
ser = serial.Serial(
port= '/dev/ttyS0',
baudrate= 57600,
parity= serial.PARITY_NONE,
stopbits= serial.STOPBITS_ONE,
bytesize= serial.EIGHTBITS,
timeout=1
)
def write_add():
counter = 0;
message = 0
while (True):
print "writing",
GPIO.output(12,1) #set high/transmit
ser.write('%d \n'%(message))
time.sleep(0.005) #baud for 57600
#time.sleep(0.5) #baud for 9600
GPIO.output(12, 0) #pin set to low/receive
loop_count = 0
res =""
while (res == ""):
res =ser.readline();
if(res != ""):
print ""
print "Read Cycles: "+str(loop_count)+" Total: "+str(counter)
print res
message = int(res) + 1
counter = counter + 1
elif(loop_count > 10):
res = "start over"
else:
print ".",
loop_count = loop_count + 1
write_add()
[2] This code is attempting to communicate with another modbus device. My message is being sent, but the response is garabge. My assumption is that the GPIO direction pin is being flipped either too soon and cutting off the message or too late and missing some of the response.
import serial
import time
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BOARD)
GPIO.setup(12, GPIO.OUT)
ser = serial.Serial(
port='/dev/ttyS0',
baudrate = 57600,
parity=serial.PARITY_NONE,
stopbits=serial.STOPBITS_ONE,
bytesize=serial.EIGHTBITS,
timeout=1
)
GPIO.output(12,1) #set high/transmit
ByteStringToSend = "\x00\x03\x01\xb8\x00\x01\x04\x02"
ser.write(ByteStringToSend)
time.sleep(0.005) #baud for 57600
GPIO.output(12, 0) #pin set to low/receive
ReceivedData = ""
while (ReceivedData == ""):
RecievedData = ser.readline();
print RecievedData
[3] Working USB-RS-485 code. USB adapter on Pi connected to Modbus device This code reads register 440 every second.
#1/usr/bin/env python
import minimalmodbus
import time
print minimalmodbus._getDiagnosticString()
minimalmodbus.BAUDRATE=57600
minimalmodbus.PARITY='N'
minimalmodbus.BYTESIZE=8
minimalmodbus.STOPBITS=1
minimalmodbus.TIMEOUT=0.1
instrument = minimalmodbus.Instrument('/dev/ttyUSB0', 0) #port and slave
#instrument.debug = True
while True:
batterVolt = instrument.read_register(440, 2) #register number, number decimals
print batterVolt
time.sleep(1)
Edit: Clarified scheme.
Edit2: Further clarified scheme and added/edited code
The code in example-2 actually works correctly. I just needed to format the response.
print RecievedData.encode('hex')
This will give the hex string in a modbus response format. As Andrej Debenjak alluded to time.sleep(x) will be dependent on baud rate and message size.
Side note: I found this page helpful in deciphering the modbus transmission.
http://www.modbustools.com/modbus.html
Edit: The ByteString I'm sending should not work on a proper modbus setup. The first byte x00 is the broadcast byte and should not solicit a response. It seems the hardware I'm working with has something funky going on. In a typical modbus setup you would need to address which device you're trying to communicate with. Thanks Marker for pointing this out.

How do I get my GPIB interface to communicate correct values with python?

I have gotten the Simulator to finally start communicating back to me (see past question); however, I do not know what it is saying to me. Here is a simple code that sends a message to the simulator.
`import serial
port = '/dev/tty.usbserial-PXFO5L2L'
baudrate = 9600
timeout = 1
ser = serial.Serial(port = port, baudrate = baudrate, timeout = timeout)
ser.write('VOLT:LEVEL 4')
`
This is supposed to set the voltage 4, but all it returns is 12. Along with other commands, they all return ints. Can anyone tell me what this means? Or if I am using the write command correctly?

Categories