arduino auto servo movement signal from python - python

how do i change the if statement in arduino in order to move the servo the same degrees as whats randomized in python?
First he's the python code:
import serial
import time
import random
arduinoData = serial.Serial('com4',9600)
while True:
low = 0; high = 180
ran_number = random.randint(low, high)
print ran_number
time.sleep(1)
arduinoData.write(ran_number)
python code is fine works with other things.
Now the arduino code, fix this:
#include <Servo.h>
Servo myservo;
int data;
int pin=9;
int pos = 0;
void setup() {
myservo.attach(9);
pinMode(pin, OUTPUT);
digitalWrite (pin, LOW);
Serial.begin(9600);
}
void loop() {
while (Serial.available()){
data = Serial.read();
}
if statement here.....
}
}

What you are looking for is the ParseInt method. Instead of using read in a loop and constructing your number, Serial.ParseInt does exactly that for you.
The correct code would be:
#include <Servo.h>
Servo myservo;
int pin = 9;
void setup() {
myservo.attach(9);
pinMode(pin, OUTPUT);
digitalWrite(pin, LOW);
Serial.setTimeout(100);
Serial.begin(9600);
}
void loop() {
int number;
if (Serial.available()) {
number = Serial.parseInt();
myservo.write(number);
delay(0.5);
}
}
Notice that I set the serial timeout period to 100ms. This is to prevent parseInt to wait too much before deciding that it has read an entire int; otherwise when receiving a value (say, 42) it waits for about 1 second waiting for some other digits.
The Python script also has a problem or two. First, you should wait for a bit after establishing the connection because every time the serial is opened the Arduino resets, so it won't read the first couple of values. You could also get a cleaner solution by printing some string from the Arduino when ready (as the last instruction of the setup function, for example) and wait for it in the Python script with readLine.
Secondly, arduinoData.write takes a byte array as input, whereas you pass an int. You need to encode such int in bytes, first converting it to a string with str and then encoding it with encode.
I got the following program working:
import serial
import time
import random
arduinoData = serial.Serial('/dev/ttyUSB0',9600)
# Let Arduino some time to reset
time.sleep(2)
while True:
low = 0; high = 180
ran_number = random.randint(low, high)
print(ran_number)
arduinoData.write(str(ran_number).encode())
time.sleep(1)

Related

sending a Numpy array to Arduino via serial?

I'm trying to send a Numpy arrays of floats (every array has 3 members) like:
[-1.73921636 -0.47675802 -0.2068679 ]
to arduino via serial port.
it looks like that I know so little to solve this problem! I'm using these lines of code in Python:
import serial
arduino=serial.Serial('com4',9600)
while 1:
array = function(x,y,z);
data=bytearray(array)
arduino.write(data)
time.sleep(.5)
of course I can't use Arduino serial monitor, So I use a 16x2 LCD to see what I'm exactly receiving from python. All I see is random charachters (often japanese!) I think problem it with decoding numpy array because I can see the string if I put it in arduino.write(data).
Arduino code:
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
char inputBuffer[32];
LiquidCrystal_I2C lcd(0x27, 16, 2);
void setup() {
Serial.begin(9600);
lcd.begin();
lcd.backlight();
}
void loop() {
if (Serial.available()) {
lcd.clear();
delay(200);
if (Serial.available() > 0) {
//lcd.print(" ");
Serial.readBytesUntil('\n', inputBuffer, 32);
//Serial.read();
lcd.setCursor(0, 0);
lcd.print(inputBuffer);
memset(inputBuffer, 0, sizeof(inputBuffer));
}
}
}
When you call bytearray in python, it converts the numpy array to an array of bytes. For example, data = bytearray(np.array([-1.73921636, -0.47675802, -0.2068679])) gives you a byte array with 24 elements (each element in the numpy array is a double which is 8 bytes each).
When you read this on the Arduino, you need to convert this array of bytes into doubles again before doing any useful operation. union would be useful for this. I do not have an LCD to verify this, but something similar should correctly read the bytes as a double.
unsigned char inputBuffer[32];
union {float f; unsigned char b[8];} num1;
union {float f; unsigned char b[8];} num2;
union {float f; unsigned char b[8];} num3;
void loop() {
if (Serial.available()) {
lcd.clear();
delay(200);
if (Serial.available() > 0) {
Serial.readBytesUntil('\n', inputBuffer, 32);
for (int i = 0; i < 8; i++) {
num1.b[i] = inputBuffer[i];
num2.b[i] = inputBuffer[8 + i];
num3.b[i] = inputBuffer[16 + i];
}
// you can call the read float numbers using num1.f, num2.f, ...
// other operations to write to the LCD go here
}
}
Also, you might want to consider sending CRC checksum at the end of the message to be safe. When you send a stream of bytes, loosing one byte can lead to really weird numbers.

How to print a string as an input for a stdin stream?

How can I pass a stdin stream a custom string using for example python with printf? I can't do it before starting the executable because it's something i need to do after some other inputs.
The code is :
void play(){
int guess=0;
char buf[CHOICEBUFSIZE];
long long int attempt=0;
time_t timer;
int value;
time(&timer);
timer /= 60;
timer *= 60;
//printf("<<<<<< Time: %t\n", timer);
srand(timer);
do {
attempt += 1;
value = rand();
puts(" > Gimme the magic number or 0 to gtfo!");
printf(" < ");
//RIGHT DOWN HERE
fgets(buf, CHOICEBUFSIZE, stdin);
guess = atoi(buf);
printf("%d\n", value);
if (guess == value){
win(attempt);
return;
}
else {
puts(" > Not even close!\n > Try again!");
}
} while (guess);
}
Here's a screen showing where I need to input it.
Thanks in advance. I'm sure the answer is simple but I couldn't find anything similiar to my case.
stdin is an input stream, so you cannot write to it. Since it sounds like you're trying to perform two tasks in parallel and have one communicate with the other, you may want to look into using pthreads or fork().

Python code works in the shell, but not when encapsulated within a function

I wrote a sketch for Arduino that lights up an Adafruit NeoPixel Ring with 12 LEDs. It works fine if I use the serial monitor in the Arduino IDE to enter data.
The way it works is I give it a string and it uses that string to determine what RGB values to use for the LEDs. For example if I input 'r100g0b0w0' the LEDs will permanently display a red color. I could then input another string, for example 'r0g0b0w100', to give the LEDs another color (in this example, white).
I wrote a python function that interfaces with the Arduino (the Arduino is connected via USB to my computer) and enables the user to enter the colors they want and display them on the Arduino in real time (i.e. without uploading a new sketch to the Arduino).
The problem I am having is with the light_LED function at the bottom of the python file. It is supposed to use the given integers red_intensity, green_intensity, blue_intensity, and white_intensity to format a string similar to the ones given above. Then it converts the string from UTF to byte format and sends the string to the Arduino.
I used the python 3.6 shell in windows 10 command prompt.
If I run every line from the function "light_LED" separately (substituting appropriate integer values for the intensity numbers given as arguments), the NeoPixel Ring LEDs light up.
But when I run the function with integer arguments, the LED does not light up. So if I open the python shell by typing this in the command prompt:
py -3.6
And then I copy-paste this in the python shell:
import serial
import time
red_intensity=100
green_intensity=0
blue_intensity=0
white_intensity=0
ser = serial.Serial('COM6', 115200)
time.sleep(2)
rgb_string = (
'r' + str(red_intensity) + 'g' + str(green_intensity) + 'b'
+ str(blue_intensity) + 'w' + str(white_intensity)
)
byte_rgb_string = rgb_string.encode()
ser.write(byte_rgb_string)
The shell prints out the number of bytes sent (10) and the LEDs light up as they are supposed to. But if I run the function containing identical code by typing this in the windows command prompt:
py -3.6 -i light.py
And then this in the python shell:
light_LED(100, 0, 0, 0)
Nothing is printed and the LEDs on the AdaFruit device do not light up.
Here's my Python file:
import serial
import time
def light_LED(red_intensity, green_intensity, blue_intensity, white_intensity):
ser = serial.Serial('COM6', 115200)
time.sleep(2)
rgb_string = (
'r' + str(red_intensity) + 'g' + str(green_intensity) + 'b'
+ str(blue_intensity) + 'w' + str(white_intensity)
)
byte_rgb_string = rgb_string.encode()
ser.write(byte_rgb_string)
Here's my Arduino sketch if you want to see it as well:
#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
#include <avr/power.h>
#endif
#define PIN 5
#define NUM_LEDS 12
#define BRIGHTNESS 20
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LEDS, PIN, NEO_GRBW + NEO_KHZ800);
void setup() {
Serial.begin(115200);
strip.setBrightness(BRIGHTNESS);
strip.begin();
strip.show(); // Initialize all pixels to 'off'
}
void loop() {
if(Serial.peek() != -1) {
displayGivenColors();
// This prevents looping until additional data is sent by the computer.
// This is necessary because loops seem to interrupt the displayGivenColors function.
while(Serial.peek() == -1) {
}
}
}
void displayGivenColors(){
// Enter the different color intensities separated by non-integer characters.
// The first number represents red, the next represent blue, then green, then white.
// For example, the entry 'r255b0g0w0' will produce a full intensity red color.
int redIntensity = Serial.parseInt();
int blueIntensity = Serial.parseInt();
int greenIntensity = Serial.parseInt();
int whiteIntensity = Serial.parseInt();
setAllPixelsToColor(redIntensity, blueIntensity, greenIntensity, whiteIntensity);
strip.show();
}
void setAllPixelsToColor(int redNumber, int blueNumber, int greenNumber, int whiteNumber) {
for(uint16_t i=0; i<strip.numPixels(); i++) {
strip.setPixelColor(i, strip.Color(redNumber, blueNumber, greenNumber, whiteNumber) );
}
}

Python equivalent for byte array transfer from Java (Processing) to C (ardunio) over USBserial

As my first foray into programming with python (previous exp only with vba and very basic java), I am trying to replicate some functionality of a GUI application, osPID Frontend, written in Processing, which communicates with an Arduino sketch, osPID-Firmware, over USB serial.
The front end takes a float array, converts it to a byte array, and then sends this over the serial link.
I have been trying to test sending a byte array to the device using the following python code:
import serial
def Send_Dash(myPort):
#To_Controller()
byteSet = 1,2,3 #bytes(1),bytes(4),bytes(3)
toSend = bytearray(byteSet)
myPort.write('5')
myPort.write('1')
myPort.write(toSend)
myPort = serial.Serial('/dev/ttyUSB0',9600,8,'N',timeout=None) # open first serial port
if myPort.isOpen():
myPort.read(10)
#typeReq = bytearray('0,0')
#myPort.write(typeReq)
Send_Dash(myPort)
Unfortunately which I can connect ok, I don't seem to be able to send any successful commands. I'd like to come up with some generic function I can use to send commands to the arduino (either by replicating the Processing code in python, or doing away with the byte array structure entirely (if possible). The original code was written to allow values such as 300000 and 0.000001 to the device. I will be unlikely to send anything greater than 300, or with decimals below 0.001, but as I hope to release this open source, others might.
For reference, the relevant arduino and Processing functions are below:
The function which converts the float array to a byte array is:
byte[] floatArrayToByteArray(float[] input)
{
int len = 4*input.length;
int index=0;
byte[] b = new byte[4];
byte[] out = new byte[len];
ByteBuffer buf = ByteBuffer.wrap(b);
for(int i=0;i<input.length;i++)
{
buf.position(0);
buf.putFloat(input[i]);
for(int j=0;j<4;j++) out[j+i*4]=b[3-j];
}
return out;
}
An example of one of the functions which packs the data is:
// Sending Floating point values to the arduino
// is a huge pain. if anyone knows an easier
// way please let know. the way I'm doing it:
// - Take the 6 floats we need to send and
// put them in a 6 member float array.
// - using the java ByteBuffer class, convert
// that array to a 24 member byte array
// - send those bytes to the arduino
void Send_Dash()//To_Controller()
{
float[] toSend = new float[3];
toSend[0] = float(SPField.getText());
toSend[1] = float(InField.getText());
toSend[2] = float(OutField.getText());
Byte a = (AMLabel.valueLabel().getText()=="Manual")?(byte)0:(byte)1;
byte identifier = 1;
myPort.write(identifier);
myPort.write(a);
myPort.write(floatArrayToByteArray(toSend));
}
A more simple function is:
void Run_Profile()
{
byte[] toSend = new byte[2];
toSend[0]=8;
toSend[1]=1;
myPort.write(toSend);
}
The byte array is made into a union:
boolean ackDash = false, ackTune = false;
union { // This Data structure lets
byte asBytes[32]; // us take the byte array
float asFloat[8]; // sent from processing and
} // easily convert it to a
foo; // float array
And read by SerialReceive(), which takes action based on the data:
void SerialReceive()
{
// read the bytes sent from Processing
byte index=0;
byte identifier=0;
byte b1=255,b2=255;
boolean boolhelp=false;
while(Serial.available())
{
byte val = Serial.read();
if(index==0){
identifier = val;
Serial.println(int(val));
}
else
{
switch(identifier)
{
case 0: //information request
if(index==1) b1=val; //which info type
else if(index==2)boolhelp = (val==1); //on or off
break;
case 1: //dasboard
case 2: //tunings
case 3: //autotune
if(index==1) b1 = val;
else if(index<14)foo.asBytes[index-2] = val;
break;
case 4: //EEPROM reset
if(index==1) b1 = val;
break;
case 5: //input configuration
if (index==1)InputSerialReceiveStart();
InputSerialReceiveDuring(val, index);
break;
case 6: //output configuration
if (index==1)OutputSerialReceiveStart();
OutputSerialReceiveDuring(val, index);
break;
case 7: //receiving profile
if(index==1) b1=val;
else if(b1>=nProfSteps) profname[index-2] = char(val);
else if(index==2) proftypes[b1] = val;
else foo.asBytes[index-3] = val;
break;
case 8: //profile command
if(index==1) b2=val;
break;
default:
break;
}
}
index++;
}
//we've received the information, time to act
switch(identifier)
{
case 0: //information request
switch(b1)
{
case 0:
sendInfo = true;
sendInputConfig=true;
sendOutputConfig=true;
break;
case 1:
sendDash = boolhelp;
break;
case 2:
sendTune = boolhelp;
break;
case 3:
sendInputConfig = boolhelp;
break;
default:
break;
}
break;
case 1: //dashboard
if(index==14 && b1<2)
{
setpoint=double(foo.asFloat[0]);
//Input=double(foo.asFloat[1]); //Not used
if(b1==0)
{
output=double(foo.asFloat[2]);
}
}
break;
case 2: //Tune
if(index==14 && (b1<=1))
{
kp = double(foo.asFloat[0]); //
ki = double(foo.asFloat[1]); //
kd = double(foo.asFloat[2]); //
}
break;
case 3: //ATune
if(index==14 && (b1<=1))
{
aTuneStep = foo.asFloat[0];
aTuneNoise = foo.asFloat[1];
aTuneLookBack = (unsigned int)foo.asFloat[2];
}
break;
default:
break;
}
}
Edit:
Sorry Lesto, yes I did read the duplicate answers, but I've only just figured out how to use struct.pack (I think!).
It appears that the existing Processing code packs (up to) 6 floats into a 32 byte array, using ByteBuffer. 6 floats is 24 bytes using struct.pack - although I gather I can pad this out by adding 1s and 0s into the format string, provided I know where they should go?
Following the comments by lesto, I have had another try (but still not quite there).
import struct
import serial
from array import array
def packByteArray(formatToSend):
bytesToSend = bytearray()
#bytesToSend.extend(struct.pack('#fffff',1,0,20,0,10) #Different result?
bytesToSend.extend(struct.pack(formatToSend,1)) #request Type
bytesToSend.extend(struct.pack(formatToSend,0)) #identifier
bytesToSend.extend(struct.pack(formatToSend,20)) #Setpoint
bytesToSend.extend(struct.pack(formatToSend,0)) #Input
bytesToSend.extend(struct.pack(formatToSend,10)) #Output
return bytesToSend
def main():
myPort = serial.Serial('/dev/ttyUSB0',9600,8,'N',timeout=None)
#Check if port is open, and if so, send the byta array.
if myPort.isOpen():
thisVar = packByteArray('>f')
print len(thisVar)
myPort.write(thisVar)
if __name__ == '__main__':
main()

PySerial and microcontroller

I'm trying to communicate with an MCU via UART with pySerial.
I use an Arduino USB2Serial Light Converter to send the data from PC to my PIC33F.
Because of the Arduino Converter I cant use CTS or RTS.
I managed to send data to the MCU and also receive data from it. But the problem is
the data isn't always what it should be.
For example I want to send a whole string from the MCU to the terminal but what I get is not the string given in the code of the MCU programm. Another problem is
that NO comparison between characters work. Which means I send a character to the MCU and the MCU compares it with a character to make decisions.
Ok now to some code:
1. Send string from PIC33F to PC and read it with pySerial
putsU1("string");
// print a string
int putsU1(char *s) {
while(*s)
putU1(*s++);
}
// print a character
int putU1(int c) {
while (_UTXBF);
U1TXREG = c;
return c;
}
The result I get for this code if I read it via pySerial is the following;
In [13]: ser = serial.Serial('/dev/ttyACM0', 9600, bytesize=7, xonxoff=0)
In [14]: while True:
print(struct.unpack('s', ser.read()))
....:
('\x7f',)
('c',)
('\x11',)
('\t',)
('e',)
('y',)
('=',)
('\x7f',)
2. Send data to PIC33F with pySerial and echo it back
This one works only for single characters and not for strings. Also the characters echoed back are switching randomly between uppcase and lowercase.
getsnU1(s, BUF_SIZE);
char *getsnU1(char *s, int len) {
char *p = s;
int cc = 0;
do {
*s = getU1();
putU1(*s);
if ((*s == 0x8) && (s > p)) {
putU1(' ');
putU1(0x8);
len++;
s--;
continue;
}
if (*s == '\n')
continue;
if (*s == '\r')
break;
s++;
len--;
} while (len > 1);
*s = '\0';
return p;
}
The UART configuration:
#define FOSC 8000000
#define FCY (FOSC/2)
#define BAUD 9600
#define U1BRGValue (((FCY/BAUD)/16)-1)
void initUART1(void) {
/* general UART config */
RPINR18bits.U1RXR = U1RXPIN; // set RP5 as UART1 RX
_RP6R = 0b00011; // set RP6 as UART Tx pin
U1RXPINTRIS = 1; // set RP5 (RB5) as input
U1MODEbits.PDSEL = DATAPARITY; // set data bits and parity
U1MODEbits.STSEL = STOPBITS; // set stop bits
U1MODEbits.ABAUD = 0; // auto-baud disabled
U1MODEbits.BRGH = 0; // low speed baud rate
U1BRG = U1BRGValue; // set baud value
/* enable interrupt on error */
IEC4bits.U1EIE = 1; // enable UART1 error interrupt
IPC16bits.U1EIP = 6; // set interrupt priority to 6
/* enable RX buffer interrupt */
IEC0bits.U1RXIE = 0; // enable UART1 RX interrupt
U1STAbits.URXISEL = 0b00; // interrupt flag is set when buffer is 3/4 full
IPC2bits.U1RXIP = 6; // set interrupt priority to 6
/* enable TX interrupt */
IEC0bits.U1TXIE = 0;
/* enable UART1 module */
U1MODEbits.UEN = 0b00;
U1MODEbits.UARTEN = 1;
_UTXEN = 1; // enable UART Tx
}
I'm kinda frustrated because I can't figure out where the problem lies. Been testing and reading for hours and everywhere it seems so simple to get this up and running but it just wont on my end ;(.
I tried to write data to the PIC33F with serial.write('text'.encode('ascii')) and
serial.write(struct.pack('s',('test'))) which all produce the same results.
Any help is highly appreciated!
I don't think you want bytesize=7 (unless you know exactly why).
Also, a classical problem with UARTs is that individual characters work, but whole strings don't - this is usually when the receiving microcontroller does only buffer a single character in hardware. I don't know PIC, but in that code above where you do getU1() followed by putU1() I guess that putU1() waits for the duration of one character, so when you call getU1() again later you will have missed the one character (if the software did send it without pause).
My usual workaround is something like:
def write(s):
for c in s:
ser.write(c)
time.sleep(0.001) # often not required
In general pyserial seems to work okay for all my projects, but you should also check with a normal terminal program to be sure. Apart from that I can only suggest you double-check the baudrate and FOSC on your microcontroller.

Categories

Resources