Pregunta

Buenos días! Recientemente he comprado una placa Arduino para hacer una especie de "control de la luz" en mi habitación. Aquí está el código del firmware escribí:

int control = 0;
int pin = 0;

void setup()
{
  Serial.begin(9600);
  for(pin = 0; pin <= 13; pin++) pinMode(pin, OUTPUT);
}

void loop()
{
  control = Serial.read();
  if (control > 0 && control <= 13) digitalWrite(control, HIGH);
  if (control < 256 && control >= (256-13)) digitalWrite((256-control), LOW);
}

Después de eso, he usado PySerial desde Python intérprete para controlar los pasadores, y todo estaba funcionando bien. Aquí es una pieza de salida intérprete:

Python 2.6.5 (r265:79063, Apr 16 2010, 13:57:41) 
[GCC 4.4.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import serial
>>> ser = serial.Serial('/dev/ttyUSB0', 9600)
>>> ser.write(chr(12))
>>> # The light turned on here
... 
>>> ser.write(chr(256-12))
>>> # The light turned off here
...

Entonces decidió escribir un simple script de Python para hacer lo mismo:

#!/usr/bin/env python

import serial
import time

ser = serial.Serial('/dev/ttyUSB0', 9600)

ser.write(chr(12))
time.sleep(1)
ser.write(chr(256-12))

Sin embargo, no funciona en absoluto! Los espectáculos de Arduino que algo se recibió durante el tiempo que puso en marcha el guión, pero no pasa nada. Aquí es una pieza de salida de strace para el script:

open("/dev/ttyUSB0", O_RDWR|O_NOCTTY|O_NONBLOCK) = 3
ioctl(3, SNDCTL_TMR_TIMEBASE or TCGETS, {B9600 -opost -isig -icanon -echo ...}) = 0
ioctl(3, SNDCTL_TMR_TIMEBASE or TCGETS, {B9600 -opost -isig -icanon -echo ...}) = 0
ioctl(3, SNDCTL_TMR_TIMEBASE or TCGETS, {B9600 -opost -isig -icanon -echo ...}) = 0
ioctl(3, SNDCTL_TMR_START or TCSETS, {B9600 -opost -isig -icanon -echo ...}) = 0
ioctl(3, SNDCTL_TMR_TIMEBASE or TCGETS, {B9600 -opost -isig -icanon -echo ...}) = 0
open("/dev/ttyUSB0", O_RDWR|O_NOCTTY|O_NONBLOCK) = 4
ioctl(4, SNDCTL_TMR_TIMEBASE or TCGETS, {B9600 -opost -isig -icanon -echo ...}) = 0
ioctl(4, SNDCTL_TMR_TIMEBASE or TCGETS, {B9600 -opost -isig -icanon -echo ...}) = 0
ioctl(4, SNDCTL_TMR_TIMEBASE or TCGETS, {B9600 -opost -isig -icanon -echo ...}) = 0
ioctl(4, SNDCTL_TMR_START or TCSETS, {B9600 -opost -isig -icanon -echo ...}) = 0
ioctl(4, SNDCTL_TMR_TIMEBASE or TCGETS, {B9600 -opost -isig -icanon -echo ...}) = 0
write(4, "\f", 1)                       = 1
close(4)                                = 0
rt_sigaction(SIGINT, {SIG_DFL, [], SA_RESTORER, 0x7f45cf4c88f0}, {0x4d9820, [], SA_RESTORER, 0x7f45cf4c88f0}, 8) = 0
exit_group(0)                           = ?

Parece que todo debe estar bien, así que no sé lo que el problema puede ser. Le agradecería cualquier ayuda, muchas gracias de antemano!

PS Cuando ejecuto el programa bajo AP, todo funciona bien. A Heisenbug.

ACTUALIZACIÓN: Hice el envío controlador ME volver los datos que recibía y que parece que no está recibiendo nada cuando estoy ejecutando la secuencia de comandos, pero recibe todo cuando envío los datos del intérprete. El código del firmware ahora se ve así:

int control = 0;
int pin = 0;

void setup()
{
  Serial.begin(9600);
  for(pin = 0; pin <= 13; pin++) pinMode(pin, OUTPUT);
}

void loop()
{
  if (Serial.available() > 0)
  {
    control = Serial.read();
    if (control <= 13) digitalWrite(control, HIGH);
    if (control < 256 && control >= (256-13)) digitalWrite((256-control), LOW);
    Serial.println(control);
  }
}
¿Fue útil?

Solución

Creo que es probablemente una condición de carrera entre el momento en que se abre el puerto serie y cuando se envían los datos. Probablemente me quedo dormido en medio de la abierta y las llamadas de escritura.

Como alternativa, en lugar de utilizar esta biblioteca "en serie" es posible que desee simplemente abierto y escribir directamente al dispositivo, tal vez se está haciendo algo gracioso (ver el doble abierta mencionado en otras)

Otros consejos

Mi conjetura es que tiene algo que ver con el medio ambiente.

import os
print os.environ['PS1']

A partir de un guión que no se establecerá. (Y tal vez algo más.)

TTY del almacenará de manera diferente dependiendo de si o no creen que el terminal es interactivo. Esa debería ser la única diferencia entre la forma en que sus dos métodos funcionan. Un lote aplicaciones deciden esto en si es o no PS1 (su terminal del sistema) se establece. Si se establece este entorno en el que manualmente se puede empezar a comportarse de la misma manera como lo hace de forma interactiva.

Además, me gustaría llamar a la llamada del comando ras PySerial manualmente en el script. (Y esto sería la mejor forma de hacerlo. En lugar de pasar por un terminal interactivo.)

sus programas de salida de strace se abre el puerto serie de lectura / escritura dos veces . La segunda vez que se escribe sólo el chr (12), a continuación, cierra el archivo. No tengo suficiente información para resolver el problema para usted, pero tal vez esto ayuda? o ¿ya darse cuenta de eso?

Puede hacer doble verificación si se restablece el Arduino cuando se abra la conexión en serie? En caso de que no restablecer los primeros bytes de serie que envíe será recibida por el gestor de arranque y no por su código. El gestor de arranque podría entonces asumir que desea programar el controlador y esperar a que otros comandos y / o datos.

El comportamiento exacto del gestor de arranque depende de su específica Arduino.

Con el fin de prueba para esta escritura un pequeño boceto que destella LED 13 y ver si la inicialización de la secuencia de comandos de Python afecta al parpadear. Si es así hay un gestor de arranque.

Con el fin de solucionar este problema hay varias soluciones posibles:

1) asegurarse de que no hay ningún reinicio causado por la inicialización de la interfaz serie. 1a) hacer esto en el lado Python 1b) hacer esto en el lado Arduino   1b solución de hardware) desconecte los rastros ofensivos en el tablero   solución de software 1b) deshacerse del gestor de arranque

2) No enviar datos mientras el cargador de arranque está haciendo su trabajo.

La solución más simple es (2) mi solución preferida es deshacerse del gestor de arranque. Sin embargo, en este caso se necesita un programador de sistema (que es una idea buena de todos modos).

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top