Niveles de autonomía en coches


Estamos sin duda todos familiarizados a la conducción autónoma gracias al carismático Elon Musk y sus famosa marca Tesla Motors, pero como vamos a ver en este humilde post no todos los coches autónomos son fabricados por Tesla y además existen hasta seis niveles de automoción, lo cual sin duda nos da esperanza que en un futuro cercano desde este momento podremos adquirir un vehículo con cierto grado de atomía en pro de mejorar entre todos la seguridad en la carretera.

La conducción autónoma ha sido clasificada en seis niveles por la Sociedad de Ingenieros de Automoción (SAE, por sus siglas en inglés). La actualización más reciente es el estándar J3016.

Los tres primeros niveles de la SAE para los vehículos autónomos (0 al 2) incluyen características de asistencia al conductor. Mientras tanto, los tres últimos (3 al 5) incluyen características reales de automatización.

Nivel 0

No hay conducción autónoma, no hay control continuo del vehículo. Aquí englobamos aquellos sistemas que proporcionan un aviso al conductor (por ejemplo, un sistema de detección de objetos en el ángulo muerto o asistente al cambio de carril), un sistema de frenado automático de emergencia… hablamos, por lo tanto, de sistemas de seguridad. Por tanto en este nivel 0 de los vehículos autónomos es aplicable a los coches más comunes en la actualidad, ya que no se automatizan las acciones del conductor.

Características:

  • El conductor realiza todas las tareas y maniobras.
  • El vehículo puede incluir sensores o radares que notifican al conductor de eventos y objetos cercanos.

Limitaciones:

  • Los coches en este nivel no incluyen ningún tipo de control autónomo.

Nivel 1

Los primeros sistemas de asistencia a la conducción que han ayudado al conductor de forma continua se encuentran englobados en este Nivel 1. Son aquellos capaces de controlar el vehículo bien longitudinal o lateralmente, pero nunca las dos cosas a la vez.

La diferencia con las tecnologías consideradas de nivel 0 es que las del nivel 1 el coche realiza cambios por su cuenta. Un ejemplo son los sistemas de frenada de emergencia automática (AEB) que cuando detectan la presencia de un obstáculo moderan la velocidad sin necesidad de que el conductor presione el pedal.

Los vehículos autónomos de nivel 1 pues incluyen sistemas que controlan la dirección, la velocidad y el frenado. Muchos modelos disponibles en la actualidad incluyen funciones de este nivel, entre otras:

  • Piloto automático adaptativo (control de crucero).
  • Sistema de control de carril.
  • Asistencia de estacionamiento.
  • Control de distancia y anticolisión.
  • Sistema automático de frenado de emergencia.

Características:

  • VhAsistencia autónoma en sistemas de dirección o de velocidad.
  • El conductor sigue controlando la mayoría de las funciones del coche.
  • Se mantienen las manos en el volante.

Limitaciones:

  • Solo hay asistencia autónoma en un sistema a la vez. Asistencia en la dirección o en la velocidad, pero no en ambos en simultáneo.

MODELOS

  • El ejemplo más claro, y el primero de estos sistemas en ver la luz (1998) es el ACC – Adaptive Cruise Control. 
  • Ha habido intentos previos que solo controlaban motor (Mitsubishi)
  • Mercedes en 1998 lanzó en el Clase S un sistema capaz de ajustar la velocidad de forma automática al vehículo precedente, usando información de un radar situado en la parte frontal. Controlaba sistema de gestión de motor y sistema de frenado, liberando al conductor de la necesidad de pisar pedal alguno (dentro de unos límites) cuando el ACC se activaba.  Así, solo debía controlar la dirección, haciendo los viajes más relajados y seguros.

En un sistema ACC, como en el resto de sistemas de Nivel 1, el conductor es siempre responsable de la conducción y no puede embarcarse en ninguna actividad paralela. El sistema, simplemente, ayuda a que la conducción sea más confortable. Hoy día sistemas como ACC son legión y se pueden encontrar desde los segmentos más bajos del mercado.

NIVEL 2

Mientras en un Nivel 1 el sistema controla el vehículo longitudinal o lateralmente, en un Nivel 2 el control es longitudinal y transversal, de forma simultánea. Este pequeño matiz, sin embargo, hace que la percepción del conductor en cuanto a autonomía sea mucho may

Los vehículos autónomos nivel 2 son POR TANTO capaces de tomar el control de algunos sistemas, aunque el conductor debe estar alerta por si se necesita su intervención.

Al sistema ACC añaden un control de posición en el carril (centrado). El conductor no ha de tener los pies en los pedales (como en un sistema ACC), pero además existe un par de fuerza inducido en el volante que “guía” al vehículo al centro del carril. En ocasiones, se pueden soltar las manos del volante, y el vehículo seguirá en el centro del carril en vías de curvas amplias. 

Características:

  • Al menos dos funciones están automatizadas al mismo tiempo.
  • El coche autoconducido se mantiene en el carril y a una distancia segura de los otros elementos en la vía.
  • Se permite que el conductor deje de controlar el volante y el acelerador (conducción manos libres).
  • Estos vehículos autónomos detectan los límites del carril y de la carretera. Incluso sin necesidad de líneas o señalización en el pavimento.

Limitaciones:

  • El coche toma el control por períodos cortos de tiempo, solo de algunas funciones y bajo ciertas condiciones .
  • El conductor debe estar alerta para retomar el control si fuera necesario.

MODELOS

  • La lista de modelos que se encuentran ya en el nivel 2 de conducción autónoma es larga: son los llamados coches semiautónomos
  • Aquí hablamos de sistemas relativamente populares y que se pueden encontrar en utilitarios como un Peugeot 208
  • Mercedes en 1998 lanzó en el Clase S un sistema capaz de ajustar la velocidad de forma automática al vehículo precedente, usando información de un radar situado en la parte frontal. Controlaba sistema de gestión de motor y sistema de frenado, liberando al conductor de la necesidad de pisar pedal alguno (dentro de unos límites) cuando el ACC se activaba.  Así, solo debía controlar la dirección, haciendo los viajes más relajados y seguros.
  • Otros ejemplos reales ProPilot de Nissan
  • EL Mercedes-Benz Clase E.
  • El BMW Serie 7
  • Volvo, Mercedes, Audi y BMW son las más avanzadas en este terreno.

NIVEL 2+

Para complicar aún más las cosas, existe algo llamado Nivel 2+. No está registrado per se en la SAE, pero es un estándar de facto en la industria. ¿Y que es un Nivel 2+? Pues un Nivel 2 en el cual no se obliga al conductor a tener las manos en el volante. Sin embargo, el conductor sigue siendo responsable total de la conducción, y como tal no puede hacer ninguna tarea adicional.

Siguen siendo sistemas de asistencia. No son conducción autónoma. El conductor es responsable siempre, y para validar que está prestando atención a la conducción aun estando las manos fuera del volante, se suele usar una cámara que monitoriza al conductor (todos los mencionados arriba salvo Tesla, de momento). Si no hay atención, el sistema le recordará al conductor de hacerlo. En caso de ignorar el aviso, pasaremos al modo “parar en modo seguro”.

Estos sistemas Nivel 2+, por lo general, solo funcionan en zonas determinadas (por ejemplo, autopistas). Serían capaces de hacer más cosas (adelantamientos con o sin confirmación del conductor, etc). Pero seguirán siendo Nivel 2+… por mucho que los llevemos hasta el extremo, como Tesla con su FSD. En principio, con el FSD se podría disponer de un sistema de Nivel 2+ funcionando en aquellas zonas que Tesla haya “desbloqueado” primero, mediante el uso de mapas crowd-sourced. Y están en ello, basándose en la gran cantidad de vehículos grabando datos (vehículos de cliente). Pero seguirá siendo un Nivel 2. Por mucho que haya videos de Tesla gestionando rotondas, cruces e intersecciones en la versión beta de FSD, el conductor sigue siendo el único responsable. Es un nivel 2

MODELOS

  • El pionero fue Cadillac con su SuperCruise en US, que hoy día se encuentra hasta en un Chevrolet Bolt.
  • Después otras muchas le han seguido: BMW, NIO, Nissan (ProPilot II),
  • Próximamente Ford, Jeep, Lexus, Hyundai… y Tesla, claro.

NIVEL 3

El sistema controla el vehículo longitudinal y lateralmente, como en un nivel 2. Pero la diferencia estriba en que aquí el sistema es el que conduce el coche mientras se encuentre activado. Es decir – y aquí está la gran ventaja de un nivel 3 – el conductor podría dedicarse a realizar alguna actividad secundaria mientras esté en el coche. Pero (porque tiene que haber un pero), esta actividad secundaria no puede ser de una naturaleza tal que no le permita volver a retomar el control del vehículo en unos segundos si el sistema se lo pide

En este nivel 3, los vehículos autónomos comienzan a analizar su entorno y son capaces de tomar decisiones. Utilizan sensores LIDAR para registrar lo que ocurre alrededor. Estos sensores combinan visión computarizada, cámaras, radar y localización.

Características:

  • Los coches son capaces de controlar funciones críticas de conducción circular en una autopista, adelantar un coche o tomar una salida.
  • El vehículo activa automáticamente ajustes de seguridad al detectar determinadas situaciones de tráfico, en la vía o ambientales.
  • El conductor puede dejar de supervisar al coche en períodos extendidos de tiempo.

Limitaciones:

  • Se permite al conductor soltar el volante, pero solo en tramos con tráfico lento, inferior a 60 km/h.
  • Se requiere que el conductor esté detrás del volante de estos vehículos autónomos si se conduce en carreteras públicas.
  • En muchos países, todavía no se ha definido o actualizado el marco legal, limitando su uso.
  • En España se trabaja en la modificación del marco legislativo que afecta a los vehículos autónomos.

MODELOS:

  • Los vehículos autónomos en este nivel son: el clásico Tesla Model S, con el sistema piloto automático,
  • Honda como Mercedes comercializarán Nivel 3 este 2021, tras el intento frustrado de Audi con su actual A8.
  • Otros vendrán – véanse las plataformas de BMW (iX), Lexus o NIO.
  • Otro ejemplo de conducción autónoma de nivel 3 es el Audi A8.

Dado que ahora el sistema es el responsable de la conducción, es necesario un salto tecnológico importante para ofrecer Nivel 3. En primer lugar, es necesaria una redundancia de sistemas (sensores, plataformas de control, actuadores, redes de datos, fuentes de alimentación…), para garantizar que no existen fuentes únicas de error. Después, a nivel de sensórica, es preciso tener información mucho más robusta del entorno (también de forma redundante). Y aquí es donde, casi toda la industria parece estar de acuerdo que el lidar es una solución adecuada para solucionar alguno de los problemas de detección de objetos en nuestro carril en circunstancias donde cámaras o radar tendrían más dificultades. Los mapas de alta resolución también juegan un papel muy importante.

Esto tiene un precio. Los sistemas de Nivel 3 no van a ser baratos, ni para el fabricante ni para el público. Un lidar, por ejemplo, tendrá un precio de entre $700-$1000. Para comparar, un radar de los que se vienen usando en múltiples aplicaciones a día de hoy se puede conseguir por poco más de $30 en grandes volúmenes.

Y finalmente, la polémica. Hay fabricantes que dicen que el Nivel 3 es una trampa mortal.

NIVEL 4 Alta Automatización

En un nivel 4, el conductor no es responsable de la conducción, pero es que tampoco se le reclamara para que tome el control si es necesario. El vehículo funcionará de forma totalmente autónoma dentro de un ODD específico, y antes de llegar al final de ese ODD – con bastante antelación, si es que el destino final cae fuera de ese ODD – podrá informar de que será necesaria intervención humana para llegar al final del trayecto. Si no se consigue que el conductor retome el control, se estacionara de forma segura.

Los vehículos autónomos en este nivel 4 se conducen sin necesidad de intervención de un conductor. Utilizan algoritmos de IA para entrenarse en las distintas condiciones y escenarios de manejo. Hay conexión mediante sistema WiFi en el coche.

Características:

  • El coche puede controlar todas las funciones críticas de conducción.
  • Los vehículos autónomos nivel 4 modifican su respuesta en función de condiciones externas.
  • Si las condiciones son adversas, busca un lugar apropiado y se detiene.
  • Ya no hay conductor, solo pasajeros, los cuales pueden viajar dormidos.

Limitaciones:

  • Se espera estén disponibles entre 2021 y 2030.
  • Inicialmente estarán operativos bajo supervisión (no conducción) y en determinados escenarios.

MODELOS

  • Tesla tiene una variante del Model S,
  • Google el Proyecto Waymo 
  • Audi el Elaine Concept.
  • Mientras tanto, Ford y Volvo anuncian modelos nivel 4 para 2021.

NIVEL 5: Automatización Completa

En este nivel , los vehículos robotizados no requieren ningún tipo de control de conducción (ni volante ni pedales). Ya no hay conductor y las instrucciones se dan por comando de voz o mediante aplicaciones móviles.

Los coches en los niveles 4 y 5 funcionan intercambiando información con su entorno. Aprovechan de compartir y utilizar los datos generados por las telecomunicaciones de las ciudades inteligentes y el IOT. El Audi Aicon es un ejemplo de coche conceptual nivel 5 que solo es posible con tecnología 5G. El Parlamento Europeo espera que estos vehículos autónomos estén disponibles hacia el año 2030.

Características:

  • No requieren interacción humana alguna.
  • Varios prototipos adelantados son coches eléctricos.
  • Utilizan reconocimiento de 360°, en un rango mayor que los humanos.

Limitaciones:

  • Se requiere definir una estructura legal para su uso.
  • Hay que realizar inversiones para la adaptación tecnológica de la infraestructura vial.

EXTRACTO DE LOS NIVELES DE AUTOMTIZACION

  • Hoy estamos entre el nivel 2 y un ‘poquito’ del 3
  • El conductor es SIEMPRE el responsable hasta Nivel 2. A partir de Nivel 3 el sistema es responsable.
  • Hay nivel 2 y nivel 2+. Este último representa un sistema más avanzado que permite circular con las manos fuera del volante. Incluso dentro del nivel 2+ hay diferencias – Tesla por ejemplo, con su FSD, lo lleva al extremo y permitiría conducir “manos libres” pero con responsabilidad del conductor en entornos urbanos.
  • La conducción autónoma comienza en Nivel 3. Hasta nivel 2 es asistida.
  • Nivel 3 se confía en que llegue PRONTO, pero en todo el mundo. Japón y Alemania serán los primeros.
  • Nivel 4, para uso privado, no se espera hasta bien entrada la década.
  • Nivel 5 ni está ni se le espera en el medio plazo. Si alguien dice que es capaz de solucionar el nivel 5 de conducción autónoma, o viene de un futuro muy lejano o miente.

Anuncio publicitario

Primeros pasos con Jupyter Notebook


¿Qué es Jupyter Notebook?

Jupyter Notebook es una herramienta increíblemente poderosa para desarrollar y presentar proyectos de ciencia de datos de forma interactiva. Este post intentara guiarle de cómo usar Jupyter Notebooks para proyectos de ciencia de datos y cómo configurarlo en su máquina local.

jupyter-notebook las mejores herramientas gratuitas de ciencia de datos

Pero primero: ¿qué es un “cuaderno”?

Un cuaderno integra código y su salida en un solo documento que combina visualizaciones, texto narrativo, ecuaciones matemáticas y otros medios enriquecidos. En otras palabras: es un documento único en el que puede ejecutar código, mostrar el resultado y también agregar explicaciones, fórmulas, gráficos y hacer que su trabajo sea más transparente, comprensible, repetible y compartible. 

El uso de Notebooks es ahora una parte importante del flujo de trabajo de la ciencia de datos en empresas de todo el mundo. Si su objetivo es trabajar con datos, el uso de una computadora portátil acelerará su flujo de trabajo y facilitará la comunicación y el intercambio de resultados. 

Lo mejor de todo es que, como parte del proyecto de código abierto  Jupyter , los cuadernos de Jupyter son completamente gratuitos. Puede descargar el software  solo o como parte del kit de herramientas de ciencia de datos de Anaconda .

Aunque es posible utilizar muchos lenguajes de programación diferentes en Jupyter Notebooks, este artículo se centrará en Python, ya que es el caso de uso más común. (Entre los usuarios de R, R Studio  tiende a ser una opción más popular).Jupyter Notebooks también puede actuar como una plataforma flexible para familiarizarse con los pandas e incluso con Python, como se verá en este tutorial.

Algunas cosas que se veran en este post:

  • Cubrir los conceptos básicos de la instalación de Jupyter y la creación de su primer cuaderno
  • Profundizar y aprender toda la terminología importante
  • Explorear la facilidad con la que se pueden compartir y publicar en línea los blocs de notas.

Ejemplo de análisis de datos en un cuaderno Jupyter

Primero, recorreremos la configuración y un análisis de muestra para responder una pregunta de la vida real. Esto demostrará cómo el flujo de una computadora portátil hace que las tareas de ciencia de datos sean más intuitivas para nosotros mientras trabajamos y para otros una vez que llega el momento de compartir nuestro trabajo.

Entonces, digamos que es analista de datos y se le ha encomendado la tarea de averiguar cómo cambiaron históricamente las ganancias de las empresas más grandes de los EE. UU. Encontrará un conjunto de datos de compañías Fortune 500 que abarcan más de 50 años desde la primera publicación de la lista en 1955, reunidos a partir del archivo público de  Fortune . Seguimos adelante y creamos un CSV de los datos que puede usar  aquí .

Como demostraremos, los cuadernos de Jupyter son perfectamente adecuados para esta investigación. Primero, sigamos e instalemos Jupyter.

Instalación

La forma más fácil para que un principiante comience con Jupyter Notebooks es instalando  Anaconda .

Anaconda es la distribución de Python más utilizada para la ciencia de datos y viene precargada con todas las bibliotecas y herramientas más populares. 

Algunas de las bibliotecas de Python más grandes incluidas en Anaconda incluyen NumPy ,  pandas y  Matplotlib , aunque la  lista completa de más de 1000 es exhaustiva.

Por lo tanto, Anaconda nos permite comenzar con un taller de ciencia de datos completamente equipado sin la molestia de administrar innumerables instalaciones o preocuparse por las dependencias y los problemas de instalación específicos del sistema operativo (léase: específicos de Windows).

Para obtener Anaconda, simplemente:

  1. Descargue la última versión de Anaconda para Python 3.8.
  2. Instale Anaconda siguiendo las instrucciones en la página de descarga y / o en el ejecutable.

Si es un usuario más avanzado con Python ya instalado y prefiere administrar sus paquetes manualmente, puede usar pip :

pip3 install jupyter

Creación de su primer cuaderno

En esta sección, aprenderemos a ejecutar y guardar blocs de notas, a familiarizarnos con su estructura y a comprender la interfaz. Nos familiarizaremos con alguna terminología básica que lo guiará hacia una comprensión práctica de cómo usar Jupyter Notebooks por su cuenta y nos preparará para la siguiente sección, que recorre un ejemplo de análisis de datos y da vida a todo lo que aprendemos aquí.

Ejecutando Jupyter

En Windows, puede ejecutar Jupyter a través del acceso directo que Anaconda agrega a su menú de inicio, que abrirá una nueva pestaña en su navegador web predeterminado que debería parecerse a la siguiente captura de pantalla.

Panel de control de Jupyter

Este no es un cuaderno por el momento, ¡pero que no cunda el pánico! No hay mucho que hacer. Este es el panel de control del portátil, diseñado específicamente para administrar sus portátiles Jupyter. Piense en ello como la plataforma de lanzamiento para explorar, editar y crear sus cuadernos.

Tenga en cuenta que el panel le dará acceso solo a los archivos y subcarpetas que se encuentran dentro del directorio de inicio de Jupyter (es decir, donde está instalado Jupyter o Anaconda). Sin embargo, el directorio de inicio se puede cambiar .

También es posible iniciar el tablero en cualquier sistema a través del símbolo del sistema (o terminal en sistemas Unix) ingresando el comando jupyter notebook; en este caso, el directorio de trabajo actual será el directorio de inicio.

Con Jupyter Notebook abierto en su navegador, es posible que haya notado que la URL del panel de control es algo así como https://localhost:8888/tree. Localhost no es un sitio web, pero indica que el contenido se sirve desde su   máquina local : su propia computadora.

Los cuadernos y el tablero de Jupyter son aplicaciones web, y Jupyter inicia un servidor Python local para servir estas aplicaciones en su navegador web, lo que lo hace esencialmente independiente de la plataforma y abre la puerta para compartir más fácilmente en la web.

(Si aún no comprende esto, no se preocupe; el punto importante es que, aunque Jupyter Notebooks se abre en su navegador, está alojado y se ejecuta en su máquina local. Sus blocs de notas no están realmente en la web hasta que decide compartirlos.)

La interfaz del tablero se explica por sí misma, aunque volveremos a ella brevemente más adelante. entonces que estamos esperando ‘ Busque la carpeta en la que le gustaría crear su primer cuaderno, haga clic en el botón desplegable «Nuevo» en la parte superior derecha y seleccione «Python 3»:

Nuevo menú de cuaderno

¡Oye presto, aquí estamos! Su primer cuaderno de Jupyter se abrirá en una nueva pestaña; cada cuaderno usa su propia pestaña porque puede abrir varios cuadernos simultáneamente.

Si regresa al tablero, verá el nuevo archivo Untitled.ipynb y debería ver un texto verde que le indica que su computadora portátil se está ejecutando.

¿Qué es un archivo ipynb?

La respuesta corta: cada  archivo .ipynb es un cuaderno, por lo que cada vez que cree un nuevo cuaderno, se creará un nuevo   archivo .ipynb.  

La respuesta más larga: cada .ipynb archivo es un archivo de texto que describe el contenido de su cuaderno en un formato llamado  JSON . Cada celda y su contenido, incluidos los archivos adjuntos de imágenes que se han convertido en cadenas de texto, se enumeran allí junto con algunos  metadatos .

Puede editarlo usted mismo, ¡si sabe lo que está haciendo! – seleccionando «Editar> Editar metadatos del cuaderno» en la barra de menú del cuaderno. También puede ver el contenido de los archivos de su cuaderno seleccionando «Editar» en los controles del panel.

Sin embargo, la palabra clave puede. En la mayoría de los casos, no hay ninguna razón por la que deba editar manualmente los metadatos de su cuaderno.

La interfaz del portátil

Ahora que tiene un cuaderno abierto frente a usted, es de esperar que su interfaz no se vea del todo extraña. Después de todo, Jupyter es esencialmente un procesador de texto avanzado.

¿Por qué no echar un vistazo? Consulte los menús para familiarizarse con ellos, especialmente tómese unos minutos para desplazarse hacia abajo en la lista de comandos en la paleta de comandos, que es el botón pequeño con el ícono del teclado (o Ctrl + Shift + P).

Nuevo cuaderno de Jupyter

Hay dos términos bastante prominentes que debe notar, que probablemente sean nuevos para usted: las  células  y los  núcleos  son clave tanto para comprender Jupyter como para lo que lo convierte en algo más que un procesador de texto. Afortunadamente, estos conceptos no son difíciles de entender.

  • Un kernel es un «motor computacional» que ejecuta el código contenido en un documento de cuaderno.
  • Una celda es un contenedor para el texto que se mostrará en el cuaderno o el código que ejecutará el kernel del cuaderno.

Celdas

Regresaremos a los núcleos un poco más tarde, pero primero hablemos de las celdas. Las células forman el cuerpo de un cuaderno. En la captura de pantalla de un nuevo cuaderno en la sección anterior, ese cuadro con el contorno verde es una celda vacía. Hay dos tipos de células principales que cubriremos:

  • Una  celda de código contiene código que se ejecutará en el kernel. Cuando se ejecuta el código, el portátil muestra el resultado debajo de la celda de código que lo generó.
  • Una  celda de Markdown contiene texto formateado con Markdown y muestra su salida en el lugar cuando se ejecuta la celda de Markdown.

La primera celda de un cuaderno nuevo es siempre una celda de código.

Probémoslo con un ejemplo clásico de Hello World: escriba print('Hello World!') en la celda y haga clic en el botón Ejecutar  Botón de ejecución del cuaderno en la barra de herramientas de arriba o presione  Ctrl + Enter.

El resultado debería verse así:

print('Hello World!')
Hello World!

Cuando ejecutamos la celda, su salida se muestra a continuación y la etiqueta a su izquierda habrá cambiado de In [ ] a  In [1].

La salida de una celda de código también forma parte del documento, por lo que puede verla en este artículo. Siempre puede notar la diferencia entre el código y las celdas de Markdown porque las celdas de código tienen esa etiqueta a la izquierda y las celdas de Markdown no.

La parte «En» de la etiqueta es simplemente la abreviatura de «Entrada», mientras que el número de etiqueta indica cuándo se ejecutó la celda en el kernel; en este caso, la celda se ejecutó primero.

Ejecute la celda nuevamente y la etiqueta cambiará a In [2] porque ahora la celda fue la segunda en ejecutarse en el kernel. Será más claro por qué esto es tan útil más adelante cuando echemos un vistazo más de cerca a los núcleos.

En la barra de menú, haga clic en  Insertar  y seleccione  Insertar celda debajo  para crear una nueva celda de código debajo de la primera y pruebe el siguiente código para ver qué sucede. ¿Notas algo diferente?

import time
time.sleep(3)

Esta celda no produce ningún resultado, pero tarda tres segundos en ejecutarse. Observe cómo Jupyter significa cuando la celda se está ejecutando actualmente cambiando su etiqueta a In [*]

En general, la salida de una celda proviene de cualquier dato de texto impreso específicamente durante la ejecución de la celda, así como del valor de la última línea de la celda, ya sea una variable solitaria, una llamada de función u otra cosa. Por ejemplo:

def say_hello(recipient):
    return 'Hello, {}!'.format(recipient)

say_hello('Tim')
'Hello, Tim!'

Te encontrarás usando esto casi constantemente en tus propios proyectos, y veremos más de eso más adelante.

Atajos de teclado

Una última cosa que puede haber observado al ejecutar sus celdas es que su borde se vuelve azul, mientras que era verde mientras estaba editando. En un Jupyter Notebook, siempre hay una celda «activa» resaltada con un borde cuyo color denota su modo actual:

  • Contorno verde : la celda está en «modo de edición»
  • Contorno azul : la celda está en «modo de comando»

Entonces, ¿qué podemos hacer con una celda cuando está en modo comando? Hasta ahora, hemos visto cómo ejecutar una celda  Ctrl + Enter, pero hay muchos otros comandos que podemos usar. La mejor manera de usarlos es con atajos de teclado.

Los atajos de teclado son un aspecto muy popular del entorno de Jupyter porque facilitan un flujo de trabajo rápido basado en celdas. Muchas de estas son acciones que puede realizar en la celda activa cuando está en modo de comando.

A continuación, encontrará una lista de algunos de los atajos de teclado de Jupyter. No es necesario que los memorice todos de inmediato, pero esta lista debería darle una buena idea de lo que es posible.

  • Alternar entre los modos de edición y comando con  Esc y  Enter, respectivamente.
  • Una vez en el modo de comando:
    • Desplácese hacia arriba y hacia abajo en sus celdas con las   teclas Up y  Down.
    • Presione  A o  B para insertar una nueva celda encima o debajo de la celda activa.
    • M transformará la celda activa en una celda de Markdown.
    • Y establecerá la celda activa en una celda de código.
    • D + D ( D dos veces) eliminará la celda activa.
    • Z deshará la eliminación de la celda.
    • Mantenga  Shift presionado y presione  Up o  Downpara seleccionar varias celdas a la vez. Con varias celdas seleccionadas, Shift + M fusionará su selección.
  • Ctrl + Shift + -, en el modo de edición, dividirá la celda activa en el cursor.
  • También puede hacer clic Shift + Click en y  en el margen a la izquierda de sus celdas para seleccionarlas.

Continúe y pruébelos en su propio cuaderno. Una vez que esté listo, cree una nueva celda de Markdown y aprenderemos a formatear el texto en nuestros cuadernos.

Reducción

Markdown es un lenguaje de marcado ligero y fácil de aprender para formatear texto sin formato. Su sintaxis tiene una correspondencia uno a uno con las etiquetas HTML, por lo que algunos conocimientos previos aquí serían útiles, pero definitivamente no son un requisito previo.

Recuerda que este artículo fue escrito en un cuaderno de Jupyter, por lo que todo el texto narrativo y las imágenes que has visto hasta ahora se lograron escribiendo en Markdown. Cubramos los conceptos básicos con un ejemplo rápido:

# This is a level 1 heading

## This is a level 2 heading

This is some plain text that forms a paragraph. Add emphasis via **bold** and __bold__, or *italic* and _italic_. 

Paragraphs must be separated by an empty line. 

* Sometimes we want to include lists. 
* Which can be bulleted using asterisks. 

1. Lists can also be numbered. 
2. If we want an ordered list.

[It is possible to include hyperlinks](https://www.example.com)

Inline code uses single backticks: `foo()`, and code blocks use triple backticks: 
```
bar()
``` 
Or can be indented by 4 spaces: 

    foo()
    
And finally, adding images is easy: ![Alt text](https://www.example.com/image.jpg)

Así es como se vería Markdown una vez que ejecute la celda para renderizarlo:

(Tenga en cuenta que el texto alternativo de la imagen se muestra aquí porque en realidad no usamos una URL de imagen válida en nuestro ejemplo)

Al adjuntar imágenes, tiene tres opciones:

  • Utilice una URL para una imagen en la web.
  • Use una URL local para una imagen que mantendrá junto a su cuaderno, como en el mismo repositorio de git.
  • Agregue un archivo adjunto a través de «Editar> Insertar imagen»; esto convertirá la imagen en una cadena y la almacenará dentro de su .ipynbarchivo de cuaderno  . ¡Tenga en cuenta que esto hará que su .ipynb archivo sea mucho más grande!

Hay mucho más en Markdown, especialmente en torno a los hipervínculos, y también es posible incluir simplemente HTML simple. Una vez que se encuentre superando los límites de los conceptos básicos anteriores, puede consultar la guía oficial  del creador de Markdown, John Gruber, en su sitio web.

Granos

Detrás de cada portátil hay un kernel. Cuando ejecuta una celda de código, ese código se ejecuta dentro del kernel. Cualquier salida se devuelve a la celda para que se muestre. El estado del kernel persiste a lo largo del tiempo y entre celdas; pertenece al documento como un todo y no a celdas individuales.

Por ejemplo, si importa bibliotecas o declara variables en una celda, estarán disponibles en otra. Probemos esto para sentirlo. Primero, importaremos un paquete de Python y definiremos una función:

import numpy as np
def square(x):
    return x * x

Una vez que hayamos ejecutado la celda de arriba, podemos hacer referencia a np y  squareen cualquier otra celda. 

x = np.random.randint(1, 10)
y = square(x)
print('%d squared is %d' % (x, y))
1 squared is 1

Esto funcionará independientemente del orden de las celdas de su cuaderno. Siempre que se haya ejecutado una celda, las variables que declaró o las bibliotecas que importó estarán disponibles en otras celdas.

Puede probarlo usted mismo, imprimamos nuestras variables nuevamente.

print('Is %d squared %d?' % (x, y))
Is 1 squared 1?

¡No hay sorpresas aquí! Pero, ¿qué pasa si cambiamos el valor de  y?

y = 10
print('Is %d squared is %d?' % (x, y))

Si ejecutamos la celda de arriba, ¿qué crees que pasaría?

Obtendremos una salida como:  Is 4 squared 10?. Esto se debe a que una vez que hemos ejecutado la  y = 10celda de código, yya no es igual al cuadrado de x en el kernel. 

La mayoría de las veces, cuando crea un cuaderno, el flujo será de arriba hacia abajo. Pero es común volver atrás para realizar cambios. Cuando necesitamos realizar cambios en una celda anterior, el orden de ejecución que podemos ver a la izquierda de cada celda, por ejemplo In [6], puede ayudarnos a diagnosticar problemas al ver en qué orden se han ejecutado las celdas. 

Y si alguna vez deseamos restablecer las cosas, hay varias opciones increíblemente útiles en el menú Kernel:

  • Reiniciar: reinicia el kernel, borrando así todas las variables, etc.que fueron definidas.
  • Reiniciar y borrar la salida: igual que el anterior, pero también borrará la salida que se muestra debajo de las celdas de código.
  • Reiniciar y ejecutar todo: igual que el anterior, pero también ejecutará todas sus celdas en orden de la primera a la última.

Si su kernel se atasca alguna vez en un cálculo y desea detenerlo, puede elegir la opción Interrumpir.

Elegir un kernel

Es posible que haya notado que Jupyter le brinda la opción de cambiar el kernel y, de hecho, hay muchas opciones diferentes para elegir. Cuando creó un nuevo cuaderno desde el panel de control seleccionando una versión de Python, en realidad estaba eligiendo qué kernel usar.

Hay kernels para diferentes versiones de Python, y también para más de 100 lenguajes,  incluidos Java, C e incluso Fortran. Los científicos de datos pueden estar particularmente interesados ​​en los núcleos para  R  y  Julia , así como en  imatlab  y  Calysto MATLAB Kernel  para Matlab.

El kernel de SoS  proporciona compatibilidad con varios idiomas en un solo portátil.

Cada kernel tiene sus propias instrucciones de instalación, pero probablemente requiera que ejecute algunos comandos en su computadora.

¿Aprendiendo Python para la ciencia de datos?

¡Prueba una de nuestras más de 60 misiones gratuitas hoy!Empiece >>

Análisis de ejemplo

Ahora que hemos visto  qué es  un Jupyter Notebook, es hora de ver  cómo se utilizan en la práctica, lo que debería darnos una comprensión más clara de por  qué son tan populares.

Finalmente es hora de comenzar con ese conjunto de datos de Fortune 500 mencionado anteriormente. Recuerde, nuestro objetivo es averiguar cómo han cambiado históricamente las ganancias de las empresas más grandes de EE . UU .

Vale la pena señalar que todos desarrollarán sus propias preferencias y estilo, pero los principios generales aún se aplican. Si lo desea, puede seguir esta sección en su propio cuaderno o utilizarla como guía para crear su propio enfoque.

Nombrar sus cuadernos

Antes de comenzar a escribir su proyecto, probablemente querrá darle un nombre significativo. nombre de archivo Untitleden la parte superior izquierda de la pantalla para ingresar un nuevo nombre de archivo, y presione el icono Guardar (que parece un disquete) debajo de él para guardar.

Tenga en cuenta que cerrar la pestaña del cuaderno en su navegador no “cerrará” su cuaderno de la forma en que lo haría cerrar un documento en una aplicación tradicional. El kernel del portátil seguirá ejecutándose en segundo plano y debe cerrarse antes de que se «cierre» realmente, aunque esto es muy útil si cierra accidentalmente la pestaña o el navegador.

Si el kernel se apaga, puede cerrar la pestaña sin preocuparse de si todavía se está ejecutando o no. 

La forma más sencilla de hacerlo es seleccionar «Archivo> Cerrar y detener» en el menú de la libreta. Sin embargo, también puede apagar el kernel yendo a «Kernel> Shutdown» desde la aplicación de la computadora portátil o seleccionando la computadora portátil en el panel de control y haciendo clic en «Apagar» (vea la imagen a continuación).

Un cuaderno para correr

Configuración

Es común comenzar con una celda de código específicamente para las importaciones y la configuración, de modo que si elige agregar o cambiar algo, simplemente puede editar y volver a ejecutar la celda sin causar efectos secundarios.

%matplotlib inline
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns sns.set(style="darkgrid")

Importaremos pandas  para trabajar con nuestros datos,  Matplotlib  para trazar gráficos y  Seaborn  para hacer que nuestros gráficos sean más bonitos. También es común importar  NumPy, pero en este caso, pandas lo importa por nosotros.

Esa primera línea no es un comando de Python, pero usa algo llamado magia de línea para indicarle a Jupyter que capture los diagramas de Matplotlib y los represente en la salida de la celda. Hablaremos un poco más sobre la magia de líneas más adelante, y también se tratan en nuestro tutorial avanzado de Jupyter Notebooks .

Por ahora, sigamos adelante y carguemos nuestros datos.

df = pd.read_csv('fortune500.csv')

Es sensato hacer esto también en una sola celda, en caso de que necesitemos recargarlo en algún momento.

Guardar y comprobar

Ahora que hemos comenzado, lo mejor es ahorrar con regularidad. Al presionar  Ctrl + Sguardará nuestro cuaderno llamando al comando «Guardar y punto de control», pero ¿qué es este punto de control?

Cada vez que creamos un nuevo cuaderno, se crea un archivo de punto de control junto con el archivo del cuaderno. Se encuentra dentro de un subdirectorio oculto de su ubicación de guardado llamado .ipynb_checkpoints y también es un  .ipynb archivo.

De forma predeterminada, Jupyter guardará automáticamente su cuaderno cada 120 segundos en este archivo de punto de control sin alterar el archivo de su cuaderno principal. Cuando «Guardar y punto de control», se actualizan tanto el cuaderno como los archivos del punto de control. Por lo tanto, el punto de control le permite recuperar su trabajo no guardado en caso de un problema inesperado.

Puede volver al punto de control desde el menú a través de «Archivo> Volver al punto de control».

Investigando nuestro conjunto de datos

¡Ahora estamos realmente rodando! Nuestro cuaderno se guarda de forma segura y hemos cargado nuestro conjunto de datos  df en la estructura de datos de pandas más utilizada, que se llama  DataFrame ay básicamente se parece a una tabla. ¿Qué aspecto tiene el nuestro?

df.head()
AñoRangoEmpresaIngresos (en millones)Beneficio (en millones)
019551Motores generales9823.5806
119552Exxon Mobil5661.4584,8
219553Acero de EE. UU.3250,4195,4
319554Energia General2959,1212,6
419555Esmark2510,819,1
df.tail()
AñoRangoEmpresaIngresos (en millones)Beneficio (en millones)
254952005496Wm. Wrigley Jr.3648,6493
254962005497Energía Peabody3631,6175,4
254972005498Wendy’s internacional3630,457,8
254982005499Kindred Healthcare3616,670,6
254992005500Cincinnati Financial3614.0584

Luciendo bien. Tenemos las columnas que necesitamos y cada fila corresponde a una sola empresa en un solo año.

Cambiemos el nombre de esas columnas para poder consultarlas más adelante.

df.columns = ['year', 'rank', 'company', 'revenue', 'profit']

A continuación, necesitamos explorar nuestro conjunto de datos. Esta completo? ¿Lo leyeron los pandas como se esperaba? ¿Falta algún valor?

len(df)
25500

De acuerdo, eso se ve bien, son 500 filas por cada año desde 1955 hasta 2005, inclusive.

Comprobemos si nuestro conjunto de datos se ha importado como era de esperar. Una simple verificación es ver si los tipos de datos (o dtypes) se han interpretado correctamente.

df.dtypes
year int64 rank int64 company object revenue float64 profit object dtype: object

UH oh. Parece que hay algún problema con la columna de ganancias; esperaríamos que fuera  float64 similar a la columna de ingresos. Esto indica que probablemente contiene algunos valores que no son enteros, así que echemos un vistazo.

non_numberic_profits = df.profit.str.contains('[^0-9.-]')
df.loc[non_numberic_profits].head()
añorangoempresaingresoslucro
2281955229Norton135,0N / A
2901955291Elaboración de cerveza Schlitz100,0N / A
2941955295Aceite vegetal del Pacífico97,9N / A
2961955297Cervecerías Liebmann96,0N / A
3521955353Minneapolis-Moline77,4N / A

¡Tal como sospechábamos! Algunos de los valores son cadenas, que se han utilizado para indicar datos faltantes. ¿Hay otros valores que se hayan infiltrado?

set(df.profit[non_numberic_profits])
{'N.A.'}

Eso hace que sea fácil de interpretar, pero ¿qué debemos hacer? Bueno, eso depende de cuántos valores falten.

len(df.profit[non_numberic_profits])
369

Es una pequeña fracción de nuestro conjunto de datos, aunque no del todo intrascendente, ya que todavía está en torno al 1,5%.

Si las filas que contienen N.A. están distribuidas de manera aproximada y uniforme a lo largo de los años, la solución más sencilla sería eliminarlas. Así que echemos un vistazo rápido a la distribución.

bin_sizes, _, _ = plt.hist(df.year[non_numberic_profits], bins=range(1955, 2006))
Falta distribución de valor

De un vistazo, podemos ver que los valores más inválidos en un solo año son menos de 25, y como hay 500 puntos de datos por año, eliminar estos valores representaría menos del 4% de los datos de los peores años. De hecho, aparte de un aumento en torno a los 90, la mayoría de los años tienen menos de la mitad de los valores faltantes del pico.

Para nuestros propósitos, digamos que esto es aceptable y continúe y elimine estas filas.

df = df.loc[~non_numberic_profits]
df.profit = df.profit.apply(pd.to_numeric)

Deberíamos comprobar que funcionó.

len(df)
25131
df.dtypes
year int64 rank int64 company object revenue float64 profit float64 dtype: object

¡Estupendo! Hemos terminado la configuración de nuestro conjunto de datos.

Si tuviéramos que presentar su cuaderno como un informe, podríamos deshacernos de las celdas de investigación que creamos, que se incluyen aquí como una demostración del flujo de trabajo con los cuadernos, y fusionar las celdas relevantes (consulte la sección Funcionalidad avanzada a continuación para más sobre esto) para crear una celda de configuración de un solo conjunto de datos.

Esto significaría que si alguna vez estropeamos nuestro conjunto de datos en otro lugar, podemos simplemente volver a ejecutar la celda de configuración para restaurarlo.

Trazando con matplotlib

A continuación, podemos llegar a abordar la cuestión en cuestión trazando el beneficio promedio por año. También podríamos trazar los ingresos, así que primero podemos definir algunas variables y un método para reducir nuestro código.

group_by_year = df.loc[:, ['year', 'revenue', 'profit']].groupby('year')
avgs = group_by_year.mean()
x = avgs.index
y1 = avgs.profit
def plot(x, y, ax, title, y_label):
    ax.set_title(title)
    ax.set_ylabel(y_label)
    ax.plot(x, y)
    ax.margins(x=0, y=0)

¡Ahora tramemos!

fig, ax = plt.subplots()
plot(x, y1, ax, 'Increase in mean Fortune 500 company profits from 1955 to 2005', 'Profit (millions)')
Aumento de las ganancias medias de las empresas incluidas en la lista Fortune 500 de 1955 a 2005

Vaya, eso parece exponencial, pero tiene algunas caídas enormes. Deben corresponder a la recesión de principios de la  década de 1990  y a la  burbuja de las puntocom . Es bastante interesante ver eso en los datos. Pero, ¿cómo es que las ganancias se recuperaron a niveles aún más altos después de cada recesión?

Quizás los ingresos puedan decirnos más.

y2 = avgs.revenue
fig, ax = plt.subplots()
plot(x, y2, ax, 'Increase in mean Fortune 500 company revenues from 1955 to 2005', 'Revenue (millions)')
Aumento de los ingresos medios de las empresas incluidas en la lista Fortune 500 de 1955 a 2005

Eso agrega otro lado a la historia. Los ingresos no se vieron tan afectados; ese es un gran trabajo contable de los departamentos de finanzas.

Con un poco de ayuda  de Stack Overflow , podemos superponer estos gráficos con +/- sus desviaciones estándar.

def plot_with_std(x, y, stds, ax, title, y_label):
    ax.fill_between(x, y - stds, y + stds, alpha=0.2)
    plot(x, y, ax, title, y_label)
fig, (ax1, ax2) = plt.subplots(ncols=2)
title = 'Increase in mean and std Fortune 500 company %s from 1955 to 2005'
stds1 = group_by_year.std().profit.values
stds2 = group_by_year.std().revenue.values
plot_with_std(x, y1.values, stds1, ax1, title % 'profits', 'Profit (millions)')
plot_with_std(x, y2.values, stds2, ax2, title % 'revenues', 'Revenue (millions)')
fig.set_size_inches(14, 4)
fig.tight_layout()
jupyter-notebook-tutorial_48_0

Eso es asombroso, ¡las desviaciones estándar son enormes! Algunas empresas de Fortune 500 ganan miles de millones mientras que otras pierden miles de millones, y el riesgo ha aumentado junto con el aumento de las ganancias a lo largo de los años.

Quizás algunas empresas se desempeñen mejor que otras; ¿Son las ganancias del 10% superior más o menos volátiles que las del 10% inferior?

Hay muchas preguntas que podríamos analizar a continuación, y es fácil ver cómo el flujo de trabajo en un cuaderno puede coincidir con el propio proceso de pensamiento. Para los propósitos de este tutorial, detendremos nuestro análisis aquí, ¡pero siéntase libre de continuar investigando los datos por su cuenta!

Este flujo nos ayudó a investigar fácilmente nuestro conjunto de datos en un solo lugar sin cambiar de contexto entre aplicaciones, y nuestro trabajo se puede compartir y reproducir de inmediato. Si quisiéramos crear un informe más conciso para una audiencia en particular, podríamos refactorizar rápidamente nuestro trabajo fusionando celdas y eliminando el código intermediario.

Compartir sus cuadernos

Cuando la gente habla de compartir sus cuadernos, generalmente hay dos paradigmas que pueden estar considerando.

La mayoría de las veces, las personas comparten el resultado final de su trabajo, al igual que este artículo, lo que significa compartir versiones no interactivas y pre-renderizadas de sus cuadernos. Sin embargo, también es posible colaborar en portátiles con la ayuda de sistemas de control de versiones como Git o plataformas online como Google Colab .

Antes de compartir

Un cuaderno compartido aparecerá exactamente en el estado en el que se encontraba cuando lo exporta o lo guarda, incluida la salida de las celdas de código. Por lo tanto, para asegurarse de que su computadora portátil esté lista para compartir, por así decirlo, hay algunos pasos que debe seguir antes de compartir:

  1. Haga clic en «Celda> Todos los resultados> Borrar».
  2. Haga clic en «Kernel> Reiniciar y ejecutar todo».
  3. Espere a que las celdas de su código terminen de ejecutarse y verifique que se haya ejecutado como se esperaba

Esto asegurará que sus cuadernos no contengan salida intermedia, tengan un estado obsoleto y se ejecuten en orden en el momento de compartir.

Exportación de sus cuadernos

Jupyter tiene soporte integrado para exportar a HTML y PDF, así como a varios otros formatos, que puede encontrar en el menú en «Archivo> Descargar como».

Si desea compartir sus cuadernos con un pequeño grupo privado, esta funcionalidad puede ser todo lo que necesite. De hecho, como a muchos investigadores de instituciones académicas se les proporciona un espacio web público o interno, y debido a que puede exportar un cuaderno a un archivo HTML, Jupyter Notebooks puede ser una forma especialmente conveniente para que los investigadores compartan sus resultados con sus pares.

Pero si compartir archivos exportados no es suficiente para usted, también existen algunos métodos inmensamente populares para compartir  .ipynb archivos más directamente en la web.

GitHub

Con la  cantidad de cuadernos públicos en GitHub que  excedieron los 1.8 millones a principios de 2018, seguramente es la plataforma independiente más popular para compartir proyectos de Jupyter con el mundo. GitHub tiene soporte integrado para renderizar  .ipynb archivos directamente tanto en repositorios como en esencias en su sitio web. Si aún no lo sabe,  GitHub  es una plataforma de alojamiento de código para el control de versiones y la colaboración para repositorios creados con  Git. . Necesitará una cuenta para utilizar sus servicios, pero las cuentas estándar son gratuitas.

Una vez que tenga una cuenta de GitHub, la forma más fácil de compartir un cuaderno en GitHub no requiere Git en absoluto. Desde 2008, GitHub ha proporcionado su servicio Gist para alojar y compartir fragmentos de código, cada uno de los cuales tiene su propio repositorio. Para compartir un cuaderno usando Gists:

  1. Inicie sesión y navegue hasta gist.github.com .
  2. Abra su  .ipynb archivo en un editor de texto, seleccione todo y copie el JSON dentro.
  3. Pegue el JSON del cuaderno en la esencia.
  4. Dale a tu Gist un nombre de archivo, recordando agregarlo  .iypnb o esto no funcionará.
  5. Haga clic en «Crear esencia secreta» o «Crear esencia pública».

Esto debería tener un aspecto similar al siguiente:

Creando una esencia

Si creó un Gist público, ahora podrá compartir su URL con cualquier persona, y otros podrán  bifurcar y clonar  su trabajo.

Crear tu propio repositorio de Git y compartirlo en GitHub está más allá del alcance de este tutorial, pero  GitHub proporciona muchas guías  para que comiences por tu cuenta.

Un consejo adicional para aquellos que usan git es  agregar una excepción  a su  .gitignore para los .ipynb_checkpoints directorios ocultos que  crea Jupyter, para no enviar archivos de puntos de control innecesariamente a su repositorio.

Nbviewer

Después de haber crecido hasta renderizar  cientos de miles  de cuadernos cada semana en 2015, NBViewer es el renderizador de cuadernos más popular en la web. Si ya tiene un lugar para alojar sus cuadernos de Jupyter en línea, ya sea en GitHub o en otro lugar, NBViewer renderizará su cuaderno y proporcionará una URL para compartir junto con él. Se proporciona como un servicio gratuito como parte del Proyecto Jupyter y está disponible en  nbviewer.jupyter.org .

Desarrollado inicialmente antes de la integración de Jupyter Notebook de GitHub, NBViewer permite que cualquier persona ingrese una URL, ID de Gist o nombre de usuario / repositorio / archivo de GitHub y mostrará el cuaderno como una página web. La ID de un Gist es el número único al final de su URL; por ejemplo, la cadena de caracteres después de la última barra invertida  https://gist.github.com/username/50896401c23e0bf417e89cd57e89e1de. Si ingresa un nombre de usuario o nombre de usuario / repositorio de GitHub, verá un explorador de archivos mínimo que le permite explorar los repositorios de un usuario y su contenido.

La URL que se muestra en NBViewer cuando se muestra un cuaderno es una constante basada en la URL del cuaderno que se está procesando, por lo que puede compartirla con cualquier persona y funcionará siempre que los archivos originales permanezcan en línea; NBViewer no almacena en caché los archivos durante mucho tiempo. largo.

Si no le gusta Nbviewer, existen otras opciones similares: aquí hay un hilo con algunos para considerar de nuestra comunidad.

Extras: Extensiones de Jupyter Notebook

Ya hemos cubierto todo lo que necesita para empezar a trabajar en Jupyter Notebooks.

¿Qué son las extensiones?

Las extensiones son precisamente lo que parecen: características adicionales que amplían la funcionalidad de Jupyter Notebooks. Si bien un Jupyter Notebook básico puede hacer mucho, las extensiones ofrecen algunas características adicionales que pueden ayudar con flujos de trabajo específicos o que simplemente mejoran la experiencia del usuario.

Por ejemplo, una extensión llamada «Tabla de contenido» genera una tabla de contenido para su cuaderno, para que los cuadernos grandes sean más fáciles de visualizar y navegar. 

Otro, llamado Inspector de variables, le mostrará el valor, el tipo, el tamaño y la forma de cada variable en su cuaderno para una fácil referencia rápida y depuración. 

Otro, llamado ExecuteTime, le permite saber cuándo y durante cuánto tiempo se ejecutó cada celda; esto puede ser particularmente conveniente si está tratando de acelerar un fragmento de su código.

Estos son solo la punta del iceberg; hay muchas extensiones disponibles.

¿Dónde puede obtener extensiones?

Para obtener las extensiones, debe instalar Nbextensions. Puede hacer esto usando pip y la línea de comando. Si tiene Anaconda, puede ser mejor hacerlo a través de Anaconda Prompt en lugar de la línea de comandos normal.

Cerrar Jupyter cuadernos, abierta Anaconda Prompt y ejecute el siguiente comando: pip install jupyter_contrib_nbextensions && jupyter contrib nbextension install.

Una vez que haya hecho eso, inicie un cuaderno y debería ver una pestaña Nbextensions. Al hacer clic en esta pestaña, se le mostrará una lista de extensiones disponibles. Simplemente marque las casillas de las extensiones que desea habilitar y ¡listo para las carreras!

Instalación de extensiones

Una vez que se ha instalado Nbextensions, no es necesario realizar una instalación adicional de cada extensión. Sin embargo, si ya instaló Nbextensons pero no ve la pestaña, no está solo. Este hilo en Github detalla algunos problemas y soluciones comunes.

Extras: Line Magics en Jupyter

Anteriormente mencionamos los comandos mágicos cuando solíamos %matplotlib inlinehacer que los gráficos de Matplotlib se renderizaran directamente en nuestro cuaderno. También hay muchas otras magias que podemos usar.

Cómo usar magia en Jupyter

Un buen primer paso es abrir un Jupyter Notebook, escribir %lsmagicen una celda y ejecutar la celda. Esto generará una lista de las magias de línea y de celda disponibles, y también te dirá si «automagic» está activado. 

  • Las magias de línea operan en una sola línea de una celda de código
  • La magia celular opera en toda la celda de código en la que se llaman

Si automagic está activado, puede ejecutar una magia simplemente escribiéndola en su propia línea en una celda de código y ejecutando la celda. Si está desactivado, deberá poner   %antes de las magias de línea y   %%  antes de las magias de células para usarlas.

Muchas magias requieren información adicional (al igual que una función requiere un argumento) para decirles cómo operar. Veremos un ejemplo en la siguiente sección, pero puede ver la documentación de cualquier magia ejecutándola con un signo de interrogación, así:

%matplotlib?

Cuando ejecute la celda anterior en un cuaderno, aparecerá una larga cadena de documentos en la pantalla con detalles sobre cómo puede usar la magia.

Algunos comandos mágicos útiles

Cubrimos más en el tutorial avanzado de Jupyter , pero aquí hay algunos para comenzar:

Mando mágicoQue hace
%correrEjecuta un archivo de secuencia de comandos externo como parte de la celda que se está ejecutando.
Por ejemplo, si aparece % run myscript.py en una celda de código, el kernel ejecutará myscript.py como parte de esa celda.
%cronométraloCuenta bucles, mide e informa cuánto tiempo tarda en ejecutarse una celda de código.
% archivo de escrituraGuarde el contenido de una celda en un archivo.
Por ejemplo,  % savefile myscript.py guardaría la celda de código como un archivo externo llamado myscript.py.
%TiendaGuarde una variable para usarla en un cuaderno diferente.
% pwdImprima la ruta del directorio en el que está trabajando actualmente.
%% javascriptEjecuta la celda como código JavaScript.

Hay mucho más de donde vino eso. Ingrese a Jupyter Notebooks y comience a explorar usando%lsmagic !

Pensamientos finales

Comenzando desde cero, nos hemos familiarizado con el flujo de trabajo natural de Jupyter Notebooks, profundizamos en las funciones más avanzadas de IPython y finalmente aprendimos cómo compartir nuestro trabajo con amigos, colegas y el mundo. ¡Y logramos todo esto desde un propio cuaderno!

Debe quedar claro cómo los cuadernos promueven una experiencia de trabajo productiva al reducir el cambio de contexto y emular un desarrollo natural de pensamientos durante un proyecto. El poder de usar Jupyter Notebooks también debería ser evidente, y cubrimos muchos clientes potenciales para que comience a explorar más funciones avanzadas en sus propios proyectos.

Si desea obtener más inspiración para sus propios cuadernos, Jupyter ha creado  una galería de cuadernos de Jupyter interesantes  que pueden resultarle útiles y la  página de inicio de Nbviewer.  enlaces a algunos ejemplos realmente elegantes de cuadernos de calidad.

Fáciles medidas de c.a. con Arduino


Medir la tensión de ca de la red de suministro con Arduino puede ser una labor compleja dado el rango de tensiones que manejamos ,pero gracias a los transformadores de tensión vamos a ver cómo medir voltaje CA hasta 250 V, tanto en 50 Hz como en 60 Hz, usando el ZMPT101B, (ese es el nombre del transformador solamente, pero lo encontrará con este nombre o «sensor de voltaje CA»).

Este módulo basado en un transformador de precisión para medidas (el zMPT101B) y un circuito operacional (el LM358) con la electronica asociada

Hemos de dicir que ,usado el código correcto, es mucho mejor esta electronica para las medidas, que los otros métodos que usan transformador + rectificador + divisor de voltaje….que no siempre dan los valores correctos. Puede que otros sistemas muestren la señal cuadrada o triangular,lo cual afecta seriamente el RMS, pues el RMS es lo que queremos medir, y para ello debemos mantener la misma forma de la señal asi que al adaptarlo para el Arduino,y aquí es cuando el módulo es útil.

Debemos advertir nuevamente que este tipo de circuitos pueden ser peligrosas si no se extrema las medidas pues en los bornes atornillados debemos conectar la carga de ca de 220V

Sineses.png

El módulo toma la señal que queremos medir, aquí una potencia doméstica de 220V, tiene alrededor de 311V como pico.

El transformador del módulo lo devuelve al pico de 2.5V

Luego agrega un desplazamiento de 2.5V para adaptarlo al Arduino.

       

  Y aquí preste atención, algunos códigos se usan con este módulo, solo hacen una muestra de la señal y miden los picos, luego una pequeña multiplicación, y puede mostrarle el «RMS» de esta señal, pero esos códigos funcionan solo para señal de onda sinusoidal perfecta, si está midiendo otra forma de la señal sería falsa.

Y, por ejemplo, aquí utilizamos un atenuador de luz(dimmer), que se basa en un Triac y ya conoces la forma «extraña» de la señal que hace un Triac.

artículo-2014julio-ics-responde-el-desafío-de-fig1

Aquí puede ver que para medir el RMS no solo debe medir los picos y hacer los mismos cálculos para la señal de onda sinusoidal.

Pero debe hacerlo de la manera correcta y es muy difícil de codificar, por eso usaremos una biblioteca simple que como siempre hará el trabajo por nosotros. 

Visualización de la información

Para mostrar las medidas se puede usar por ejemplo una pantalla OLED en lugar de las tipicas basadas en LCD con el controlador de Toshiba HD44780,

LCD es el acrónimo de Liquid Crystal Display (en español Pantalla de Cristal Líquido). No podemos considerar que se trate de una tecnología novedosa. El LCD lleva con nosotros mucho tiempo, solo tenemos que echar la mirada hacia atrás y recordar esos relojes Casio o las calculadoras que llevamos a clase de matemáticas.

Estamos acostumbrados a que la materia pueda estar en estado sólido, líquido o gaseoso, los llamados estados de la materia. Pero ya en el siglo XIX se descubrió que había más estados en los que podía encontrarse la materia. El cristal líquido se encuentra en algún lugar entre el sólido y líquido.No es el objetivo de este post la física involucrada detrás de los LCD, solo decir que utiliza las propiedades de la luz polarizada para mostrarnos la información en una pantalla. A partir de una serie de filtros, se consigue mostrar la información gracias a la iluminación de fondo.

Hay una amplia gama de pantallas LCDs que podemos utilizar con Arduino. Aparte de las funcionalidades extra que nos puedan dar cada una de ellas, las podemos diferenciar por el número de filas y columnas, su tamaño.

Por ejemplo, una pantalla LCD de 16×1 tendrá una fila de 16 caracteres es decir, solo podremos mostrar 16 caracteres simultáneamente, al igual que un LCD de 20×4 tendrá 4 filas de 20 caracteres cada una.

LCD

En este artículo vamos a trabajar con un LCD típico, de 16×2. Esto significa que vamos a poder mostrar 16 caracteres en la primera fila y los mismos en la segunda fila.

La mayoría de las pantallas LCD que se están haciendo ahora, vienen con una fila de dieciséis pines. Los primeros catorce pines se utilizan para controlar la visualización. Los dos últimos son para la iluminación de fondo.

Aunque el dato se puede enviar en 8 bits , lo normal es usarlo partido en «trozos» de 4 bits, labor que será transparente al usuario gracias a las librería LiquidCrystal.h y que como es obvio se emplea para ahorrarnos 4 lineas de datos del GPIO de modo que necesitaríamos 4 para datos + 3 de control =7 pines de datos lógicamente mas 2 mas para la alimentación de 5v DC

PINFUNCIÓN
1GND (Tierra)
25 Voltios
3Control de contraste pantalla
4RS – Selector entre comandos y datos
5RW – Escritura y lectura de comandos y datos
6Sincronización de lectura de datos
7-14Pines de datos de 8-bit
15Alimentación luz de fondo (5V)
16GND (Tierra) luz de fondo (0V)

En la siguiente imagen vemos la correspondencia con los pines físicos del LCD.

Pines LCD 16x2

Esta imagen muestra la parte de abajo del LCD. Cuando lo conectes a la protoboard los pines estarán invertidos horizontalmente.

Otra alternativa es usar una pantalla OLED i2c de 128 * 32 , cuyo coste es irrisorio. Este tipo de pantallas esde reducidasa dimensiones y , puede usarlas en algunos proyectos pequeños de bricolaje y también les brinda muchas posibilidades para hacer (diferentes fuentes y tamaños de textos, diferentes formas, desplazamiento, imágenes bmp …) Tenga en cuenta que este tipo de pantalla no es una pantalla a color, las «nornales » solo imprimen en azul (Izquierda) pero las hay en blanco, y algunos pueden tener amarillo + uno de los colores anteriores .

Este es un ejemplo cableado con una pantalla OLED .Este cableado depende de su versión de pantalla ,( el que vemos usa 4 pines : dos para la alimentacion con 3,3V DC y los dos de datos no cableando el pin RST).

circuito

Conexiones finales

Wiring.png

Este es todo el cableado y, como se mencionó, estamos usando una pantalla OLED de 128 × 32, puede usarla o no, el módulo está alimentado por 5v y entrega una señal analógica.

Configuración:

Lo primero que debe hacer es calibrar el módulo con su potenciómetro, cablear el módulo, enchufar el Arduino y cargar este simple código, y no olvide colocar las sondas de medición en la toma de corriente (¡¡¡CUIDADO !!! ) y ya conoce el voltaje.

El código para probar esto es realmente simple , usando eso si, el Serial Plotter de Arduino IDE:

void setup() {
Serial.begin(9600);
}

void loop() 
{
Serial.println(analogRead(A0));
}

Abra el trazador de serie del IDE de Arduino:

parcela1
plot2

Verá algo como esto en su trazador de serie, significa que no adquiere toda la señal, ajuste el potenciómetro hasta que tenga algo que parezca una onda sinusoidal. Sé que esa no es la señal de onda sinusoidal de CA.

plot3

Cuando tenga algo como esto, puede agregar un retraso para ver una buena onda sinusoidal, aquí es porque estoy midiendo justo después de mi atenuador de luz, verá un pequeño pico antes del pico de señal si mide el enchufe directamente, no lo hará

sinewaveee.png

Ahora que su módulo está calibrado, las calibraciones del código se basarán en él, así que trate de no cambiarlo.

Código:

La biblioteca que usamos es Filters.h, reduce la cantidad de trabajo para usted, descargue aquí o desde Github . 

Bibliotecas de pantallas OLED de Adafruit

 /* This code works with ZMPT101B AC voltage sensor module and 128x32 OLED display
 * It permits you to measure any AC voltage up to 250V, BE CAREFUL !!!
 * The functions from Filters library permits you to calculate the True RMS of a signal
 * Refer to www.surtrTech.com or SurtrTech YouTube channel for more details
 */

#include <Filters.h> //Easy library to do the calculations
#include <SPI.h>     //Libraries for the OLED display
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 32 // OLED display height, in pixels
#define OLED_RESET    -1 //

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); //Declaring the display name (display)

float testFrequency = 50;                     // test signal frequency (Hz)
float windowLength = 40.0/testFrequency;     // how long to average the signal, for statistist

int Sensor = 0; //Sensor analog input, here it's A0

float intercept = -0.04; // to be adjusted based on calibration testing
float slope = 0.0405; // to be adjusted based on calibration testing
float current_Volts; // Voltage

unsigned long printPeriod = 1000; //Refresh rate
unsigned long previousMillis = 0;


void setup() {
  Serial.begin( 9600 );    // start the serial port
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C); //Start the OLED display 
  display.clearDisplay();
  display.setTextSize(2);                   
  display.setTextColor(WHITE);              
  display.setCursor(1,1);               
  display.print("SurtrTech");
  display.setCursor(1,20);
  display.setTextSize(1);
  display.print("AC Voltmeter");
  display.display();
  delay(5000);

}

void loop() {
  
  RunningStatistics inputStats;                //Easy life lines, actual calculation of the RMS requires a load of coding
  inputStats.setWindowSecs( windowLength );
   
  while( true ) {   
    Sensor = analogRead(A0);  // read the analog in value:
    inputStats.input(Sensor);  // log to Stats function
        
    if((unsigned long)(millis() - previousMillis) >= printPeriod) {
      previousMillis = millis();   // update time every second
            
      Serial.print( "\n" );
      
      current_Volts = intercept + slope * inputStats.sigma(); //Calibartions for offset and amplitude
      current_Volts= current_Volts*(40.3231);                //Further calibrations for the amplitude
      
      Serial.print( "\tVoltage: " );
      Serial.print( current_Volts ); //Calculation and Value display is done the rest is if you're using an OLED display
      
      
      display.clearDisplay();
      display.setTextSize(3);       //size of the text that will follow              
      display.setTextColor(WHITE);  //its color            
      display.setCursor(1,1);      //position from where you want to start writing           
      display.print(current_Volts,1);
      display.setCursor(115,00);
      display.setTextSize(2);
      display.print("V");
      display.setCursor(115,15);
      display.setTextSize(1);
      display.print("AC");
      display.display();
    }
  }

}

Pruebas:

Los valores seguramente no son perfectos y 100% precisos, pero como ve, necesita calibraciones muy precisas para hacerlo perfecto, y no olvide que está usando un módulo de 10 $ o menos, y allí se compara con un multímetro que usa TRMS. , Verdadero valor eficaz.

     Un multímetro que no sea TRMS también le dará una lectura falsa para una señal que no sea de onda sinusoidal,

Fuente: https://surtrtech.com/

¿Cómo medir la potencia real de CA y la potencia aparente con Arduino?


Cuando se habla de potencia en corriente alterna (CA), es más complicado, ya que implica forma de onda y diferencia de fase, pero básicamente, hay 3 términos para la alimentación de CA: la potencia aparente , la potencia activa y la potencia reactiva . 

  • La potencia aparente se refiere a la potencia total en un circuito de CA que incluye la potencia disipada y absorbida. Este término es importante para el diseño de generadores de energía y cables para asegurarse de que todo el cableado y la energía puedan soportar todo tipo de cargas. La potencia aparente se puede calcular multiplicando el valor de voltaje de raíz cuadrada media (RMS) y el valor de corriente (RMS).
  • El segundo término es el Poder Activo / Real . Es la potencia real consumida por la carga. La potencia activa se puede calcular promediando el producto de los valores instantáneos de forma de onda de voltaje y corriente. 
  • El tercer término es la potencia reactiva, que se refiere a la potencia que se desperdicia y que la carga no utiliza como trabajo útil debido a la diferencia de fase entre las formas de onda de voltaje y corriente. Cuando la potencia reactiva se suma a la potencia activa, le dará la potencia aparente. 

Usaremos un Arduino para medir la  potencia aparente y la potencia real por lo que para medir la energía de CA , necesitamos usar 2 sensores separados que son el módulo de voltaje de CA monofásico y el módulo de corriente de CA. 

Cada módulo puede encajar en el pin de entrada analógica Arduino  . Para un Arduino UNO, hay  6 pines de entrada analógicas  (A0-A5)pero para un Arduino NANO tiene 8 pines, mientras que Arduino MEGA tiene 16 pines de entrada. Los pines de entrada analógica asignarán voltajes de entrada entre 0 y 5 V en valores enteros entre 0 y 1023 con una resolución de 4,9 mV por unidad (5,00 V / 1024 unidades). 

!Cuidado ! Asumimos que tiene los conocimientos básicos de electricidad y sabe a qué se enfrenta. Es posible que necesite la orientación de personas con experiencia si es nuevo en el trabajo eléctrico. La seguridad y la precaución deben tenerse siempre en cuenta. No seremos responsables de nada que le suceda.

Puede medir voltaje CA como 110Vac, 220Vac y 240Vac mediante el uso de la disposición en el mercado  individual  Fase V de CA módulo de voltaje. Puede detectar la forma de onda instantánea para el valor de voltaje. La señal se puede utilizar con el sensor de corriente CA para determinar más información útil, como el  factor de potencia, la dirección del flujo de corriente, la potencia real y la potencia aparente. 

Es posible que deba precalibrar el módulo. Mediante el uso del potenciómetro trimpot, se puede ajustar la amplitud de la forma de onda de voltaje. Se recomienda utilizar un segundo medidor que lea el voltaje RMS para facilitar la calibración. 

Módulo de voltaje CA monofásico

Este módulo ZMPT101 B está equipado con un transformador de voltaje de alta precisión ZMPT101B y un circuito de amplificador operacional. Puede medir voltaje CA dentro de 250V. La señal de salida correspondiente se puede ajustar utilizando el potenciómetro de ajuste. 

La imagen tiene un atributo ALT vacío; su nombre de archivo es 51tDdSO3u+L._AC_SL1000_.jpg

Estas resumidamente algunas de sus características:

  • Módulo de transformador de voltaje monofásico activo Sensor de voltaje de salida de CA
  • Equipado con la serie ZMPT101B de transformador de voltaje de alta precisión y corriente de amplificador operacional de alta precisión, fácil de 250V dentro de la adquisición de señal de alimentación de CA
  • Transformador de voltaje: Transformador de micro voltaje de precisión a bordo
  • Salida de voltaje de modo: el módulo puede medir el voltaje de CA dentro de 250 V, el modo de salida correspondiente se puede ajustar
  • Circuito amplificador operacional: circuito amplificador integrado de alta precisión, la señal para hacer el muestreo exacto y la compensación adecuada y otras funciones

El sensor de Intensidad

El segundo sensor del que queremos hablar es el Módulo Sensor de Corriente. El sensor de corriente ampliamente utilizado que es compatible con Arduino es el módulo de sensor de corriente ACS712 . Utiliza el fenómeno de efecto hall cuyo voltaje se produce a partir del movimiento de la corriente dentro de la región del campo magnético. El voltaje producido por el efecto hall es directamente proporcional a la corriente aplicada, lo que lo hace adecuado para estimar la corriente aplicada a partir del voltaje detectado.

El módulo de sensor de corriente estándar  ACS712  se vende en tres versiones de   5A, 20A y 30A  que sons adecuadas para la mayoría de las aplicaciones.  El módulo 5A tiene una resolución de 185 mV / amperio, el módulo 20A tiene 100 mV / amperio, mientras que el módulo 30A tiene una resolución de 66 mV / amperio.

Estos módulos requieren contacto directo, lo cual podria ser un gran inconveniente pues debe conectarse en serie al valor medido . El cableado del sistema existente debe modificarse para que el módulo encaje en el sistema existente. 

Si no tiene experiencia con la alimentación de CA, personalmente no recomiendo este módulo. Este módulo es aceptable para CC de bajo voltaje, pero puede ser  peligroso en CA si no se toma en serio ,por lo que una alternativa es usar un tipo de sensor de efecto Hall con transformador de núcleo dividido (como se muestra en la imagen de la izquierda). Es el   módulo HSTS016L del sensor de núcleo dividido de efecto Hall . El modelo va desde 10A hasta 200A . Con el tipo de sensor de corriente de núcleo dividido, no se requiere alteración en el sistema existente. !!! El voltaje de salida de este sensor es de  2,5 V +/- 0,625 V  con una precisión decente. Recomiendo encarecidamente este sensor para medir la corriente alterna en caso de no tener experiencia con BT.

YHDC Hall Split Core Current Sensor HSTS016L ±10A/2.5±0.625V

Codigo arduino

Para fines de demostración, usaremos el sensor de núcleo dividido de efecto Hall que no requiere contacto eléctrico con el sistema de cableado existente, lo que definitivamente es una forma más segura  !!!Las señales detectadas por Arduino están en valores analógicos. A continuación se muestran las señales detectadas por el voltaje (azul) y el sensor de corriente (rojo). Puede copiar el siguiente código para probar el suyo. Puede ver la forma de onda en Serial Plotter. Conecte el módulo de voltaje en el pin A2 de Arduino mientras que el módulo de corriente en el pin A3 . La magnitud del voltaje (onda azul) se puede calibrar mediante el módulo de voltaje de CA utilizando el potenciómetro integrado y se puede comparar con el voltímetro RMS de referencia. Para una onda sinusoidal pura como esta, el valor RMS en el voltímetro multiplicado por la raíz cuadrada 2 es igual al voltaje máximo(magnitud desde la mitad de la oscilación). La magnitud de la onda de corriente (onda roja) está sujeta a su carga aplicada. Puede modificar el código Arduino para aumentar su magnitud con fines de visualización. El patrón de onda de CA puede no ser 100% suave como una onda de voltaje y está sujeto a la carga sobre cómo se extrae la corriente. El cambio de fase o la diferencia de fase entre el voltaje y la corriente también están sujetos a la carga aplicada.

float vAnalogRead;
float iAnalogRead;
int voltageInputPin = A2; // Analog input pin for voltage sensor
int currentInputPin = A3; // Analog input pin for current sensor
int currentOffset = 0; // key in value for current offset setting
int voltageOffset = 0; // key in value for voltage offset setting
float virtualMagnification = 5; // to increase the magnification of current value in display

 void setup()
{
Serial.begin(9600);
}


 void loop()
{
vAnalogRead = analogRead(voltageInputPin) – 512 + voltageOffset;
iAnalogRead = virtualMagnification*(analogRead(currentInputPin) – 512) + currentOffset;
 Serial.print(vAnalogRead)
;Serial.print(» «);
Serial.println(iAnalogRead);delay(300); 
}

 El punto medio para Ambas ondas debería estar técnicamente en 512 (valor analógico) y fluctúa entre 0 y 1023 de forma predeterminada. Sin embargo, he modificado el código para que las ondas oscilen en el punto medio del  valor 0  entre 512 y -512 para facilitar el cálculo más adelante. Antes de continuar, es necesario realizar una calibración antes de la medición,  ya que algunos módulos pueden tener un error de desviación diferente. Puede ir a la publicación de sensores individuales para obtener más información.

Cómo se procesa la señal

Necesitamos determinar los 2 valores de potencia de CA, el valor de potencia de CA RMS  y el valor de potencia de CA activa . Antes de continuar, comencemos con la calibración inicial de ambos sensores. Necesitamos minimizar cualquier error potencial de desviación o inexactitud tanto como sea posible. Los sensores son muy sensibles, asegúrese de utilizar conectores ajustados y terminales de cable. 

Necesitamos una calibración de 2 veces para cada sensor de módulo . Ambas calibraciones deben realizarse sin medir la corriente y el voltaje. La primera calibración es asegurarse de que cuando no se mide voltaje o corriente, se muestra exactamente en el punto 0. Es una calibración de valor analógico. Es posible que algunos módulos no se muestren exactamente en el valor analógico 512 (lo he cambiado al punto 0 usando el código Arduino para una fácil comprensión) cuando no se detecta ningún valor. Necesitamos agregar un valor de compensación para que esto vuelva a ajustarlo al origen cuando no se detecta ningún valor.

La segunda calibración es para eliminar aún más el valor de la señal falsa durante el cálculo RMS. Incluso después de que se realiza la primera calibración, todavía hay algún ruido fantasma o eléctrico menor incluso cuando no se miden voltaje ni corriente. Tenemos que agregar otro desplazamiento para llegar al valor cero en la etapa final de visualización. Esta segunda calibración debe realizarse solo después de que la primera calibración entre en vigor. Ambas calibraciones se pueden realizar manualmente (la forma más difícil) o automáticamente presionando el botón SELECT en el protector de la pantalla LCD y espere unos 5 segundos. Por eso es necesario tener el escudo para que funcione. ¡Puede comprar en nuestro enlace de afiliado aquí !

El cálculo de la potencia cuadrática media de la raíz

La  potencia de CA RMS  es el producto de los   valores de voltaje CA RMS  y  corriente CA RMS . El voltaje CA RMS y la corriente CA RMS se calculan por separado. Al encontrar la potencia de CA RMS, el voltaje RMS y la corriente RMS se encuentran indirectamente. 

Nuestro código está diseñado para calcular o mostrar un valor que se deriva de un  promedio de 1000 muestras por conjunto. Encontré un problema de que un tiempo de grabación de muestra más corto (menos de 1 milisegundo para 1 lectura de muestra) podría retrasar el tiempo de procesamiento, lo que hizo que el tiempo de visualización se ralentizara. He configurado que cada muestra se registre cada 1 milisegundo (0,001 segundos). En otras palabras, el conjunto completo total equivale a 50 ondas con cada onda dividida en 20 secciones o lecturas (para 50 Hz). Técnicamente, debería durar 1 segundo para 1 conjunto de lectura. También es adecuado para el sistema de 60 Hz, ya que el tiempo de medición para 1 juego de lectura es de 1 segundo.

Cada valor analógico de muestra individual se eleva al  cuadrado  inicialmente y una vez que se  acumulan los valores  de 1000 muestras , el  valor promedio de las 1000 muestras se establece   en raíz cuadrada para obtener el   valor analógico RMS (para 1 sensor). Convierta el valor analógico RMS en voltaje medido o valor actual. Realice el cálculo similar por separado para el otro sensor y multiplique ambos valores RMS para convertirlos en energía CA RMS. A continuación se muestra un ejemplo de cómo funciona el código. Tomo un  cuarto de onda como ejemplo .

En la conversión de  voltaje RMS , multiplico  el valor analógico RMS por 2 . Durante la calibración de este módulo, reduje la amplitud de onda a la mitad (es por eso que en el código es necesario multiplicar por 2) porque la onda de voltaje comenzó a distorsionarse o cortarse cerca de 250Vac, lo que puede dar inexactitud en la medición. Puede aumentar el voltaje de suministro al módulo para eliminar el efecto de corte (según el manual del módulo) pero creo que lo dejaré así ya que no voy a agregar suministro de voltaje adicional. En cuanto a la conversión de corriente RMS, el mV / A es la clasificación del sensor de corriente y lo dejo como el símbolo de la unidad. 1023 es la conversión de valor analógico, mientras que 5000 es el valor de voltaje en mV. Para obtener más información sobre esto, puede ir a mi publicación sobre el sensor de CA  aquí..

El cálculo de la potencia instantánea

Active o Real Power  es más simple en comparación con RMS Power.  Es el  valor promedio  de todas las  multiplicaciones  de  voltaje instantáneo  y   valor de corriente instantánea . Los valores analógicos de tensión y corriente   se convierten primero en  valores de tensión y corriente medidos . Luego, el voltaje se multiplica por su valor de corriente instantánea y se convierte en una lectura de muestra. 

Similar al método de potencia RMS, la potencia activa también se deriva de un promedio de 1000 muestras por conjunto. Cada muestra se registra cada milisegundo, es decir, el conjunto completo total equivale a 50 ondas con cada onda dividida en 20 secciones o lecturas (para 50 Hz). 

Puede ser interesante añadir una pantalla LCD de 16X2   que se puede colocar directamente en la parte superior de la placa Arduino sin la necesidad de cableado adicional para la pantalla LCD. Sin la pantalla LCD, solo puede monitorear el valor de corriente medido en la PC a través del Monitor en serie. 

La buena noticia es que no necesita calibrar manualmente la configuración de compensación si tiene la pantalla LCD  con usted. A continuación, adjuntamos el código que utiliza la función del botón que podría  calibrarse automáticamente  por sí mismo cuando presionó el  botón SELECT . Puede descargar desde el final de esta página a continuación.  

Conexión de hardware

Es posible que deba encontrar una manera de colocar el cable del sensor de CA en el pin Arduino. El cable del sensor que compré venía presoldado en la punta, lo que facilita el acceso a los pines de Arduino. Abra el módulo de corriente Split Core y se mostrará un símbolo de flecha que indica el camino del flujo de corriente. Una vez que todo esté listo, asegúrese de que el núcleo partido esté bien cerrado.  

Asegúrese de que debajo del sensor de voltaje no haya conductores expuestos o placas de metal que puedan causarle un cortocircuito accidental en el terminal del módulo. Debe obtener el fusible rápido de baja corriente para el cable del sensor de voltaje, mientras que el MCB o el fusible de corriente nominal suficiente según su carga para protegerlo contra cualquier posible cortocircuito y riesgo de incendio.

Para conectar el cableado entre la placa Arduino y el módulo, necesita los  cables de línea dupont macho a hembra . ¡Puedes conseguirlo en nuestro enlace de afiliado aquí ! 

Necesita el conector que pueda asegurar los cables y aislarlos del contacto accidental. ¡Obtenga el  conector rápido  en nuestro enlace de afiliado  aquí  !

Código final Arduino

El paso final sería agregar el código fuente a la placa Arduino. Supongo que ha instalado el software Arduino. Si no ha instalado el software, el enlace  aquí  puede llevarlo al sitio oficial de descarga. Una vez que haya descargado el software, puede descargar el archivo de código (.ino) para esta aplicación a continuación (haga clic con el botón derecho en el enlace para guardar). 

Hay 2  archivos de códigos fuente adjuntos  que son código fuente con y sin función de protección de pantalla LCD. Si no tiene el protector de pantalla LCD con usted, elija el código que no tiene el protector de pantalla LCD, pero debe calibrar manualmente e ingresar los 2 valores de compensación para ambos sensores. Sin embargo, le recomiendo encarecidamente que obtenga un protector de pantalla LCD.

Con el protector de pantalla LCD, una vez que el código se carga en la placa Arduino, el valor actual se mostrará en la pantalla LCD. Hemos agregado la función de autocalibrado, una vez que se presiona el botón SELECT, el valor regresa al punto cero exacto. Puede que tenga que esperar entre 5 y 8 segundos hasta que se vuelvan a calibrar todos los valores. Si la primera pulsación no está satisfecha, puede repetir pulsando de nuevo .

Proceso de calibracion 

Una vez que el código se carga en el Arduino, si tiene un protector de pantalla LCD adjunto, verá la corriente, el voltaje, la potencia activa y el valor de potencia aparente. Asegúrese de apagar la fuente de voltaje de CA  que está midiendo. Presione el botón SELECT del protector de pantalla LCD y espere 5 segundos. Debería llegar a  0 voltios . Lo mismo para la corriente CA que muestra 0A . Para las personas que no tienen el protector de pantalla LCD, puede compensar manualmente ingresando el valor de compensación en el código y volver a cargarlo. Hay 2 valores de compensación (voltageOffset1 y voltageOffset2) que se deben calibrar. Haga lo mismo para el módulo de corriente CA para 2 valores de compensación (currentOffset1 y currentOffset2) y finalmente es el powerOffset.

Ajuste de voltaje de CA del potenciómetro de trimpot 

Esta configuración es para ajustar la magnitud de la onda de voltaje de CA. A diferencia de la corriente CA, calculamos y obtenemos la corriente esperada, pero para el voltaje CA, necesitamos un voltaje de referencia para el ajuste.

Una vez realizada la calibración, debería ver el valor 0 voltios cuando no se detecta voltaje. Ahora, encienda la fuente de voltaje y encienda el lector de voltaje de referencia (el multímetro o el medidor de energía). Compare ambos valores de voltaje. Gire el potenciómetro de ajuste (trimpot) con un destornillador pequeño para reducir o aumentar el valor de voltaje detectado por Arduino. Debe girar el potenciómetro hasta que el voltaje que se muestra en la pantalla LCD Shield o Monitor serial sea el mismo que el valor de referencia de voltaje en el medidor de voltaje o energía. ¡¡¡Y felicitaciones, ya está hecho !!!!

Si realmente lee los códigos, en realidad hemos reducido la amplitud de onda potencial a la mitad (en la fórmula es por 2). 

RMSVoltageMean = (sqrt (voltageMean)) * 2;

Es por eso que cuando se aplica voltaje de monitoreo, el valor medido es alto y es necesario reducirlo. La amplitud de onda completa (x 1) se distorsiona cuando está cerca de 250 V, lo que nos hizo tener esta opción para superar el problema de distorsión.

Resultado: en monitor de serie

Para archivos de código Arduino, recuerde hacer clic derecho> Guardar enlace como …  Puede modificar el código interno como desee. ¡Feliz codificación! 

AC Power.ino

// AC Power Monitoring By Solarduino 

// Note Summary
// Note :  Safety is very important when dealing with electricity. We take no responsibilities while you do it at your own risk.
// Note :  This AC Power Monitoring Code needs AC current module and AC Voltage Module to determine AC Power value. 
// Note :  This Code monitors RMS Voltage, RMS current, RMS AC Power (Apparent Power) and Instantaneous AC Power (Active Power)
// Note :  The value shown in Serial Monitor is refreshed every second, can be used for 50Hz and 60Hz.
// Note :  The frequency is measured by counting time and average it for every 50 samples taken (1 sample is 1 cycle for 50Hz by default).
// Note :  You have to manually calibrate 5 offsets readings : voltageOffset1,voltageOffset2,currentOffset1,currentOffset2 & powerOffset.  
// Note :  The unit provides reasonable accuracy and may not be comparable with other expensive branded and commercial product.
// Note :  All credit shall be given to Solarduino.

/*/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/////////////*/


        /* 0- General */

        int decimalPrecision = 2;                         // decimal places for all values shown in LED Display & Serial Monitor

        /* 1- AC Voltage Measurement */
        
        int voltageOffset1  = 0;                          // key in offset value
        int voltageOffset2  = 0;                          // key in offset value
        int VoltageAnalogInputPin = A2;                   // Which pin to measure voltage Value
        float voltageSampleRead  = 0;                     /* to read the value of a sample*/
        float voltageLastSample  = 0;                     /* to count time for each sample. Technically 1 milli second 1 sample is taken */
        float voltageSampleSum   = 0;                     /* accumulation of sample readings */
        float voltageSampleCount = 0;                     /* to count number of sample. */
        float voltageMean ;                               /* to calculate the average value from all samples*/ 
        float RMSVoltageMean ;                            /* square roof of voltageMean*/


        /* 2- AC Current Measurement */

        int currentOffset1  = 0;                          // key in offset value
        int currentOffset2  = 0;                          // key in offset value
        int CurrentAnalogInputPin = A3;                   // Which pin to measure Current Value
        float mVperAmpValue = 31.25;                      // If using ACS712 current module : for 5A module key in 185, for 20A module key in 100, for 30A module key in 66
                                                          // If using "Hall-Effect" Current Transformer, key in value using this formula: mVperAmp = maximum voltage range (in milli volt) / current rating of CT
                                                          /* For example, a 20A Hall-Effect Current Transformer rated at 20A, 2.5V +/- 0.625V, mVperAmp will be 625 mV / 20A = 31.25mV/A */
        float currentSampleRead  = 0;                     /* to read the value of a sample*/
        float currentLastSample  = 0;                     /* to count time for each sample. Technically 1 milli second 1 sample is taken */
        float currentSampleSum   = 0;                     /* accumulation of sample readings */
        float currentSampleCount = 0;                     /* to count number of sample. */
        float currentMean ;                               /* to calculate the average value from all samples*/ 
        float RMSCurrentMean =0 ;                         /* square roof of currentMean*/
        float FinalRMSCurrent ;                           /* the final RMS current reading*/


        /* 3- AC Power Measurement */
        
        int powerOffset =0;                               // key in offset value
        float sampleCurrent1 ;                            /* use to calculate current*/
        float sampleCurrent2 ;                            /* use to calculate current*/
        float sampleCurrent3 ;                            /* use to calculate current*/
        float apparentPower;                              /* the apparent power reading (VA) */
        float realPower = 0;                              /* the real power reading (W) */
        float powerSampleRead  = 0;                       /* to read the current X voltage value of a sample*/
        float powerLastSample   = 0;                      /* to count time for each sample. Technically 1 milli second 1 sample is taken */       
        float powerSampleCount  = 0;                      /* to count number of sample. */
        float powerSampleSum    = 0;                      /* accumulation of sample readings */         
        float powerFactor = 0;                            /* to display power factor value*/ 


void setup()                                              /*codes to run once */

{                                      

        /* 0- General */
        
        Serial.begin(9600);                               /* to display readings in Serial Monitor at 9600 baud rates */

}


void loop()                                                                                       /*codes to run again and again */
{                                      


        /* 1- AC Voltage Measurement */
 
        if(millis() >= voltageLastSample + 1 )                                                    /* every 1 milli second taking 1 reading */
          {
            voltageSampleRead = 2*(analogRead(VoltageAnalogInputPin)- 512) + voltageOffset1;      /* read the sample value */           
            voltageSampleSum = voltageSampleSum + sq(voltageSampleRead) ;                         /* accumulate value with older sample readings*/     
            voltageSampleCount = voltageSampleCount + 1;                                          /* to move on to the next following count */
            voltageLastSample = millis() ;                                                        /* to reset the time again so that next cycle can start again*/ 
          }
        
        if(voltageSampleCount == 1000)                                                            /* after 1000 count or 1000 milli seconds (1 second), do the calculation and display value*/
          {           
            voltageMean = voltageSampleSum/voltageSampleCount;                                    /* calculate average value of all sample readings taken*/
            RMSVoltageMean = sqrt(voltageMean)+ voltageOffset2;                                   /* square root of the average value*/
            Serial.print("Voltage RMS: ");
            Serial.print(RMSVoltageMean,decimalPrecision);
            Serial.println("V  ");
            voltageSampleSum =0;                                                                  /* to reset accumulate sample values for the next cycle */
            voltageSampleCount=0;                                                                 /* to reset number of sample for the next cycle */
          }


        /* 2- AC Current Measurement */
        
        if(millis() >= currentLastSample + 1)                                                     /* every 1 milli second taking 1 reading */
          {
            currentSampleRead = analogRead(CurrentAnalogInputPin)-512 + currentOffset1;           /* read the sample value */
            currentSampleSum = currentSampleSum + sq(currentSampleRead) ;                         /* accumulate value with older sample readings*/
            currentSampleCount = currentSampleCount + 1;                                          /* to move on to the next following count */
            currentLastSample = millis();                                                         /* to reset the time again so that next cycle can start again*/ 
          }
        
        if(currentSampleCount == 1000)                                                            /* after 1000 count or 1000 milli seconds (1 second), do the calculation and display value*/
          {       
            currentMean = currentSampleSum/currentSampleCount;                                    /* calculate average value of all sample readings taken*/
            RMSCurrentMean = sqrt(currentMean)+currentOffset2 ;                                   /* square root of the average value*/
            FinalRMSCurrent = (((RMSCurrentMean /1024) *5000) /mVperAmpValue);                    /* calculate the final RMS current*/
            Serial.print("Current RMS: ");
            Serial.print(FinalRMSCurrent,decimalPrecision);
            Serial.println(" A  ");
            currentSampleSum =0;                                                                  /* to reset accumulate sample values for the next cycle */
            currentSampleCount=0;                                                                 /* to reset number of sample for the next cycle */
          }

       
        /* 3- AC Power with Direction */

        if(millis() >= powerLastSample + 1)                                                       /* every 1 milli second taking 1 reading */
          {
            sampleCurrent1 = analogRead(CurrentAnalogInputPin)-512+ currentOffset1;
            sampleCurrent2 = (sampleCurrent1/1024)*5000;
            sampleCurrent3 = sampleCurrent2/mVperAmpValue;
            voltageSampleRead = 2*(analogRead(VoltageAnalogInputPin)- 512)+ voltageOffset1 ;
            powerSampleRead = voltageSampleRead * sampleCurrent3 ;                                /* real power sample value */
            powerSampleSum = powerSampleSum + powerSampleRead ;                                   /* accumulate value with older sample readings*/
            powerSampleCount = powerSampleCount + 1;                                              /* to move on to the next following count */
            powerLastSample = millis();                                                           /* to reset the time again so that next cycle can start again*/ 
          }
        
        if(powerSampleCount == 1000)                                                              /* after 1000 count or 1000 milli seconds (1 second), do the calculation and display value*/
          {
            realPower = ((powerSampleSum/powerSampleCount)+ powerOffset) ;                        /* calculate average value of all sample readings */
            Serial.print("Real Power (W): ");
            Serial.print(realPower);
            Serial.println(" W  ");           
            apparentPower= FinalRMSCurrent*RMSVoltageMean;                                       /*Apparent power do not need to recount as RMS current and RMS voltage values available*/
            Serial.print("Apparent Power (VA): ");
            Serial.print(apparentPower,decimalPrecision);
            Serial.println(" VA ");
            powerFactor = realPower/apparentPower;    
            if(powerFactor >1 || powerFactor<0)
            {
              powerFactor = 0;
            }
            Serial.print("Power Factor: ");
            Serial.println(powerFactor,decimalPrecision);  
            Serial.println(" ");                                           
            powerSampleSum =0;                                                                    /* to reset accumulate sample values for the next cycle */
            powerSampleCount=0;                                                                   /* to reset number of sample for the next cycle */
          }
  
}









lcd (AP Power with LCD Disply.ino)

// AC Power Monitoring with LCD By Solarduino 

// Note Summary
// Note :  Safety is very important when dealing with electricity. We take no responsibilities while you do it at your own risk.
// Note :  This AC Power Monitoring Code needs AC current module and AC Voltage Module to determine AC Power value. 
// Note :  This Code monitors RMS Voltage, RMS current, RMS AC Power (Apparent Power) and Instantaneous AC Power (Active Power)
// Note :  The value shown in Serial Monitor is refreshed every second, can be used for 50Hz and 60Hz.
// Note :  The frequency is measured by counting time and average it for every 25 samples taken (1 sample is 1 cycle).
// Note :  The auto calibration (voltageOffset1 & currentOffset1) is using averaged analogRead value of 1000 samples.
// Note :  The auto calibration (voltageOffset2 & currentOffset2) is using calculated RMS value including Offset1 value for calibration.    
// Note :  The unit provides reasonable accuracy and may not be comparable with other expensive branded and commercial product.
// Note :  All credit shall be given to Solarduino.

/*/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/////////////*/


        /* 0- General */

        int decimalPrecision = 2;                         // decimal places for all values shown in LED Display & Serial Monitor

        /* 1- AC Voltage Measurement */
        
        int VoltageAnalogInputPin = A2;                   // Which pin to measure voltage Value
        float voltageSampleRead  = 0;                     /* to read the value of a sample*/
        float voltageLastSample  = 0;                     /* to count time for each sample. Technically 1 milli second 1 sample is taken */
        float voltageSampleSum   = 0;                     /* accumulation of sample readings */
        float voltageSampleCount = 0;                     /* to count number of sample. */
        float voltageMean ;                               /* to calculate the average value from all samples*/ 
        float RMSVoltageMean ;                            /* square roof of voltageMean*/

              /*1.1 Offset AC Voltage */
    
              int voltageOffsetRead = 0;                  /* to change the mode for offset */
              float voltageOffset1 = 0;                   // to Offset deviation and accuracy. Offset any fake current when no current operates. 
                                                          // Offset will automatically callibrate when SELECT Button on the LCD Display Shield is pressed.
                                                          // If you do not have LCD Display Shield, look into serial monitor to add or minus the value manually and key in here.
              float voltageOffset2 = 0;                   // to offset value due to calculation error from squared and square root.
              float voltageSampleSumOffset =0;            /* accumulation of sample readings for offset */
              float offsetVoltageMean = 0;                /* to calculate the average value from all samples for offset, in analog values*/
              float voltageOffsetLastSample = 0;          /* to count time for each sample for offset purpose. */
              float voltageOffsetSampleCount = 0;         /* to count number of sample for offset. */


        /* 2- AC Current Measurement */

        int CurrentAnalogInputPin = A3;                   // Which pin to measure Current Value
        float mVperAmpValue = 31.25;                      // If using ACS712 current module : for 5A module key in 185, for 20A module key in 100, for 30A module key in 66
                                                          // If using "Hall-Effect" Current Transformer, key in value using this formula: mVperAmp = maximum voltage range (in milli volt) / current rating of CT
                                                          /* For example, a 20A Hall-Effect Current Transformer rated at 20A, 2.5V +/- 0.625V, mVperAmp will be 625 mV / 20A = 31.25mV/A */
        float currentSampleRead  = 0;                     /* to read the value of a sample*/
        float currentLastSample  = 0;                     /* to count time for each sample. Technically 1 milli second 1 sample is taken */
        float currentSampleSum   = 0;                     /* accumulation of sample readings */
        float currentSampleCount = 0;                     /* to count number of sample. */
        float currentMean ;                               /* to calculate the average value from all samples*/ 
        float RMSCurrentMean =0 ;                         /* square roof of currentMean*/
        float FinalRMSCurrent ;                           /* the final RMS current reading*/


              /*2.1 Offset AC Current */
    
              int currentOffsetRead = 0;                  /* to change the mode for offset */
              float currentOffset1 = 0;                   // to Offset deviation and accuracy. Offset any fake current when no current operates. 
                                                          // Offset will automatically callibrate when SELECT Button on the LCD Display Shield is pressed.
                                                          // If you do not have LCD Display Shield, look into serial monitor to add or minus the value manually and key in here.
                                                          // 26 means add 26 to all analog value measured
              float currentOffset2 = 0;                   // to offset value due to calculation error from squared and square root.
              float currentSampleSumOffset = 0;           /* accumulation of sample readings for offset */
              float offsetCurrentMean = 0;                /* to calculate the average value from all samples for offset, in analog values*/
              float currentOffsetLastSample = 0;          /* to count time for each sample for offset purpose. */
              float currentOffsetSampleCount = 0;         /* to count number of sample for offset. */


        /* 3- AC Power Measurement */
        
        float sampleCurrent1 ;                            /* use to calculate current*/
        float sampleCurrent2 ;                            /* use to calculate current*/
        float sampleCurrent3 ;                            /* use to calculate current*/
        float apparentPower;                              /* the apparent power reading (VA) */
        float realPower = 0;                              /* the real power reading (W) */
        float powerSampleRead  = 0;                       /* to read the current X voltage value of a sample*/
        float powerLastSample   = 0;                      /* to count time for each sample. Technically 1 milli second 1 sample is taken */       
        float powerSampleCount  = 0;                      /* to count number of sample. */
        float powerSampleSum    = 0;                      /* accumulation of sample readings */         
        float powerFactor = 0;                            /* to display power factor value*/ 


              /*3.1 Offset AC Power */
    
              int powerOffsetRead = 0;                    /* to change the mode for offset */
              float powerOffset = 0;                      // to Offset deviation and accuracy. Offset any fake current when no current operates. 
                                                          // Offset will automatically callibrate when SELECT Button on the LCD Display Shield is pressed.
                                                          // If you do not have LCD Display Shield, look into serial monitor to add or minus the value manually and key in here.
              float powerOffsetLastSample = 0;            /* to count time for each sample for offset purpose. */
              float powerOffsetSampleCount = 0;           /* to count number of sample for offset. */

        
        /* 4 - LCD Display  */

        #include<LiquidCrystal.h>                   /* Load the liquid Crystal Library (by default already built-it with arduino solftware)*/
        LiquidCrystal LCD(8,9,4,5,6,7);             /* Creating the LiquidCrystal object named LCD. The pin may be varies based on LCD module that you use*/
        unsigned long startMillisLCD;               /* start counting time for LCD Display */
        unsigned long currentMillisLCD;             /* current counting time for LCD Display */
        const unsigned long periodLCD = 1000;       // refresh every X seconds (in seconds) in LED Display. Default 1000 = 1 second 
        int page = 1;                               /* flip page to display values*/

void setup()                                              /*codes to run once */

{                                      

        /* 0- General */
        
        Serial.begin(9600);                               /* to display readings in Serial Monitor at 9600 baud rates */

        /* 4 - LCD Display  */

        LCD.begin(16,2);                                  /* Tell Arduino that our LCD has 16 columns and 2 rows*/
        LCD.setCursor(0,0);                               /* Set LCD to start with upper left corner of display*/  
        startMillisLCD = millis();                        /* Start counting time for LCD display*/

}


void loop()                                                                                       /*codes to run again and again */
{                                      

        /* 0- General */


              /* 0.1- Button Function */
        
              int buttonRead;
              buttonRead = analogRead (0);                                                        // Read analog pin A0. Pin A0 automatically assigned for LCD Display Button function (cannot be changed)

              /*Right button is pressed */
              if (buttonRead < 60) 
              {   LCD.setCursor(0,0); LCD.print ("PRESS <SELECT>   "); }       
     
              /* Up button is pressed */
              else if (buttonRead < 200) 
              {   
              page = 1;
              }    
                 
              /* Down button is pressed */
              else if (buttonRead < 400)
              {   
              page = 2;
              }      
     
              /* Left button is pressed */
              else if (buttonRead < 600)
              {   LCD.setCursor(0,0); LCD.print ("PRESS <SELECT>   "); } 
     
              /* Select button is pressed */
              else if (buttonRead < 800)
              {   
              currentOffsetRead = 1;                                                              // to activate offset for current  
              voltageOffsetRead = 1;                                                              // to activate offset for voltage
              powerOffsetRead = 1;                                                                // to activate offset for power
              LCD.setCursor(0,0);                                                                 /* set display words starting at upper left corner*/
              LCD.print ("INITIALIZING..... ");
              LCD.setCursor(0,1);                                                                 /* set display words starting at lower left corner*/
              LCD.print ("WAIT 5 SEC ..... ");
              }


        /* 1- AC Voltage Measurement */
 
        if(millis() >= voltageLastSample + 1 )                                                    /* every 1 milli second taking 1 reading */
          {
            voltageSampleRead = 2*(analogRead(VoltageAnalogInputPin)- 512) + voltageOffset1;      /* read the sample value */
            voltageSampleSumOffset = voltageSampleSumOffset + voltageSampleRead;                  /* values accumulate for offset purpose every milli second */
            
            voltageSampleSum = voltageSampleSum + sq(voltageSampleRead) ;                         /* accumulate value with older sample readings*/     
            voltageSampleCount = voltageSampleCount + 1;                                          /* to move on to the next following count */
            voltageLastSample = millis() ;                                                        /* to reset the time again so that next cycle can start again*/ 
          }
        
        if(voltageSampleCount == 1000)                                                            /* after 1000 count or 1000 milli seconds (1 second), do the calculation and display value*/
          {
            offsetVoltageMean = voltageSampleSumOffset/voltageSampleCount;                        /* average the offset reading*/
            
            voltageMean = voltageSampleSum/voltageSampleCount;                                    /* calculate average value of all sample readings taken*/
            RMSVoltageMean = sqrt(voltageMean)+ voltageOffset2;                                   /* square root of the average value*/
            Serial.print(" The Voltage RMS value is: ");
            Serial.print(RMSVoltageMean,decimalPrecision);
            Serial.println(" V ");
            voltageSampleSum =0;                                                                  /* to reset accumulate sample values for the next cycle */
            voltageSampleCount=0;                                                                 /* to reset number of sample for the next cycle */
            voltageSampleSumOffset=0;
          }
 

              /* 1.1 - Offset AC Voltage */
                  
              if(voltageOffsetRead == 1)                                                          /* Run this code when button SELECT is pressed */
                {
                  voltageOffset1 = 0; 
                  if(millis()>= voltageOffsetLastSample + 1)                                      /* keep countng time for offset1*/
                    {                                                                            
                      voltageOffsetSampleCount = voltageOffsetSampleCount + 1;                    /* 1 milli second add 1 count*/                                                      
                      voltageOffsetLastSample = millis();                                         /* to reset the time again so that next cycle can start again*/                                  
                    }                                                                                 
                  if(voltageOffsetSampleCount == 2000)                                            /* after 2 seconds, run this codes.  */
                    {                                                                            
                      voltageOffset1 = -1*(offsetVoltageMean);                                    /* set the offset values */
                      voltageOffsetRead = 2;                                                      /* go for second offset Settings */                     
                      voltageOffsetSampleCount = 0;                                               /* to reset the time again so that next cycle can start again */                                                             
                    } 
                }   
                    
              if(voltageOffsetRead == 2)                                                          /* Run this code after first offset done */
                {
                  voltageOffset2 = 0;                                                             /* set back currentOffset2 as default*/
                  if(millis()>= voltageOffsetLastSample + 1)                                      /* keep countng time for offset2*/
                    {                                                                            
                      voltageOffsetSampleCount = voltageOffsetSampleCount + 1;                                                                          
                      voltageOffsetLastSample = millis();                                                                          
                    }                                                                                
                  if(voltageOffsetSampleCount == 2000)                                            /* after 2 seconds, run this codes.  */
                    {                                                                            
                      voltageOffset2 = - RMSVoltageMean;                                          /* set the offset values */
                      voltageOffsetRead = 0;                                                      /* change the offset mode to original, wait until the button is pressed again */                     
                      voltageOffsetSampleCount = 0;                                               /* to reset the time again so that next cycle can start again */ 
                    }                                                                             
                } 


        /* 2- AC Current Measurement */
        
        if(millis() >= currentLastSample + 1)                                                     /* every 1 milli second taking 1 reading */
          {
            currentSampleRead = analogRead(CurrentAnalogInputPin)-512 + currentOffset1;           /* read the sample value */
            
            currentSampleSumOffset = currentSampleSumOffset + currentSampleRead;                  /* accumulate offset value */
            
            currentSampleSum = currentSampleSum + sq(currentSampleRead) ;                         /* accumulate value with older sample readings*/
            currentSampleCount = currentSampleCount + 1;                                          /* to move on to the next following count */
            currentLastSample = millis();                                                         /* to reset the time again so that next cycle can start again*/ 
          }
        
        if(currentSampleCount == 1000)                                                            /* after 1000 count or 1000 milli seconds (1 second), do the calculation and display value*/
          {
            offsetCurrentMean = currentSampleSumOffset/currentSampleCount;                        /* average offset value*/
            
            currentMean = currentSampleSum/currentSampleCount;                                    /* calculate average value of all sample readings taken*/
            RMSCurrentMean = sqrt(currentMean)+currentOffset2 ;                                   /* square root of the average value*/
            FinalRMSCurrent = (((RMSCurrentMean /1024) *5000) /mVperAmpValue);                    /* calculate the final RMS current*/
            Serial.print(" The Current RMS value is: ");
            Serial.print(FinalRMSCurrent,decimalPrecision);
            Serial.println(" A ");
            currentSampleSum =0;                                                                  /* to reset accumulate sample values for the next cycle */
            currentSampleCount=0;                                                                 /* to reset number of sample for the next cycle */
            currentSampleSumOffset=0;                                                             /* to reset accumulate offset value for the next cycle*/
          }

              /* 2.1 - Offset AC Current */
                  
              if(currentOffsetRead == 1)                                                          /* Run this code when button SELECT is pressed */
                {
                  currentOffset1 = 0;                                                             /* set currentOffset back to default value*/
                  if(millis()>= currentOffsetLastSample + 1)                                      /* keep countng time for offset1*/
                    {                                                                            
                      currentOffsetSampleCount = currentOffsetSampleCount + 1;                                                                          
                      currentOffsetLastSample = millis();                                                                          
                    }                                                                                 
                  if(currentOffsetSampleCount == 2000)                                            /* after 2 seconds, run this codes.  */
                    {                                                                            
                      currentOffset1 = - offsetCurrentMean;                                       /* set the offset values */
                      currentOffsetRead = 2;                                                      /* go for second offset Settings */                     
                      currentOffsetSampleCount = 0;                                               /* to reset the time again so that next cycle can start again */                                                             
                    } 
                }   
                
              if(currentOffsetRead == 2)                                                          /* Run this code after first offset done */
                {
                  currentOffset2 = 0;                                                             /* set back currentOffset2 as default*/
                  if(millis()>= currentOffsetLastSample + 1)                                      /* keep countng time for offset2*/
                    {                                                                            
                      currentOffsetSampleCount = currentOffsetSampleCount + 1;                                                                          
                      currentOffsetLastSample = millis();                                                                          
                    }                                                                             
                          
                  if(currentOffsetSampleCount == 2000)                                            /* after 2 seconds, run this codes.  */
                    {                                                                            
                      currentOffset2 = - RMSCurrentMean;                                          /* set the offset values */
                      currentOffsetRead = 0;                                                      /* change the offset mode to original, wait until the button is pressed again */                     
                      currentOffsetSampleCount = 0;                                               /* to reset the time again so that next cycle can start again */ 
                    }                                                                             
                } 
       
        /* 3- AC Power with Direction */

        if(millis() >= powerLastSample + 1)                                                       /* every 1 milli second taking 1 reading */
          {
            sampleCurrent1 = analogRead(CurrentAnalogInputPin)-512+ currentOffset1;
            sampleCurrent2 = (sampleCurrent1/1024)*5000;
            sampleCurrent3 = sampleCurrent2/mVperAmpValue;
            voltageSampleRead = 2*(analogRead(VoltageAnalogInputPin)- 512)+ voltageOffset1 ;
            powerSampleRead = voltageSampleRead * sampleCurrent3 ;                                /* real power sample value */
            powerSampleSum = powerSampleSum + powerSampleRead ;                                   /* accumulate value with older sample readings*/
            powerSampleCount = powerSampleCount + 1;                                              /* to move on to the next following count */
            powerLastSample = millis();                                                           /* to reset the time again so that next cycle can start again*/ 
          }
        
        if(powerSampleCount == 1000)                                                              /* after 1000 count or 1000 milli seconds (1 second), do the calculation and display value*/
          {
            realPower = ((powerSampleSum/powerSampleCount)+ powerOffset) ;                        /* calculate average value of all sample readings */
            Serial.print(" The Real Power (W) is: ");
            Serial.print(realPower);
            Serial.println(" W ");           
            apparentPower= FinalRMSCurrent*RMSVoltageMean;                                       /*Apparent power do not need to recount as RMS current and RMS voltage values available*/
            Serial.print(" The Apparent Power (VA) is: ");
            Serial.print(apparentPower,decimalPrecision);
            Serial.println(" VA ");
            powerFactor = realPower/apparentPower;    
            if(powerFactor >1 || powerFactor<0)
            {
              powerFactor = 0;
            }
            Serial.print(" The Power Factor is: ");
            Serial.println(powerFactor,decimalPrecision);                                             
            powerSampleSum =0;                                                                    /* to reset accumulate sample values for the next cycle */
            powerSampleCount=0;                                                                   /* to reset number of sample for the next cycle */
          }
 

              /* 3.1 - Offset AC Power */

              if(powerOffsetRead == 1)                                                            /* Run this code after first offset done */
                {                          
                  powerOffset = 0;                                                                /* set back currentOffset2 as default*/
                  if(millis()>= powerOffsetLastSample + 1)                                        /* keep countng time for offset2*/
                    {                                                                            
                      powerOffsetSampleCount = powerOffsetSampleCount + 1;                                                                          
                      powerOffsetLastSample = millis();                                                                          
                    }                                                                                                      
                  if(powerOffsetSampleCount == 5000)                                              /* after 5 seconds, run this codes.  */
                    {                                                                            
                      powerOffset = -realPower;                                                
                      powerOffsetRead = 0;                                                        /* change the offset mode to original, wait until the button is pressed again */                     
                      powerOffsetSampleCount = 0;                                                 /* to reset the time again so that next cycle can start again */ 
                    }                                                                             
                } 


        /* 4 - LCD Display  */
        
        currentMillisLCD = millis();                                                              /* Set current counting time */
        if (currentMillisLCD - startMillisLCD >= periodLCD && page ==1)                           /* for every x seconds, run the codes below*/
          {
            LCD.setCursor(0,0);                                                                   /* Set cursor to first colum 0 and second row 1  */
            LCD.print("I=");
            LCD.print(FinalRMSCurrent,decimalPrecision);                                          /* display current value in LCD in first row  */
            LCD.print("A  ");
            LCD.print("V=");
            LCD.print(RMSVoltageMean,decimalPrecision);                                          /* display current value in LCD in first row  */
            LCD.print("V     ");   
            LCD.setCursor(0,1); 
            LCD.print(realPower,decimalPrecision);
            LCD.print("W ");
            LCD.print(apparentPower,decimalPrecision);                                            /* display current value in LCD in first row  */
            LCD.print("VA    ");
            startMillisLCD = currentMillisLCD ;                                                   /* Set the starting point again for next counting time */
          }
          
        if( currentMillisLCD - startMillisLCD >= periodLCD && page ==2)
         {
            LCD.setCursor(0,0);                                                                   /* Set cursor to first colum 0 and second row 1  */
            LCD.print("PF=");
            LCD.print(powerFactor,decimalPrecision);
            LCD.print("            "); 
            LCD.setCursor(0,1); 
            LCD.print("                "); 
            startMillisLCD = currentMillisLCD ;                                                   /* Set the starting point again for next counting time */
          }

      
    
}

Fuente : solarduino.com/how-to-measure-ac-power-with-arduino/

Cómo convertir su impresora 3D en un plotter en dos pasos


Un plotter o trazador es un dispositivo que puede dibujar texto e imágenes en papel con un utensilio ( por ejemplo un bolígrafo). 

Si pensamos en en el hardware necesario , podemos pensar que un buen atajo puede ser una vieja ( o no) impresora 3D pues estas ya incluyen todo el hardware y la electrónica que necesitamos: sólo hay que encontrar la manera de adjuntar un utensilio de dibujo y cómo decirle que dibuje.

En realidad como vamos a ver es mucho más fácil de lo que nos podemos imaginar, asi que en esta publicación de blog, aprenderá cómo puede hacer su propio dibujo de impresora.

Ejemplo del primer dibujo de su impresora 3D! 

Convertir una impresora 3D en una impresora 2D

Quizás se pregunte cuál es la utilidad de convertir una impresora 3D en algo que pueda dibujar imágenes 2D en un papel. Después de todo, las impresoras convencionales hacen eso desde hace varias décadas, ¿no es eso un paso atrás?

Pues , un plotter le permitirá dibujar con bolígrafo, lápices de colores, crayones, marcadores e incluso una pluma (básicamente todo lo que pueda dejar marcas en un papel). Pero no solo eso, incluso podemos dibujar en diferentes materiales, como cartón o vidrio. También puede ser creativo con tipos de tinta únicos, como dorada, plateada o que brillan en la oscuridad

Una utilidad innegable para los electrónicos es ayudar en la fabricación de circuitos impresos pues normalmente el diseño de la pcb se realiza calcando el diseño en la parte del cobre y luego hay que volver hay que repintar el diseño con un rotulador edding ( Además incluso puede ayudar en el taladrado con un cnc los orificios para los componentes)

Paso 1 – Colocación de un utensilio de dibujo

Desea montar de manera confiable un bolígrafo en el cabezal de la impresora y asegurarse de que la punta del bolígrafo quede un poco por debajo de la boquilla. Empecé diseñando una pequeña parte de este propósito. Se sujeta al cabezal de la impresora utilizando un pequeño tornillo M3 para fijar el bolígrafo en él:

Puede conseguir el modelo en thingiverse aquí . Debe adaptarse a cualquier impresora Creality Ender-3 o CR-20, y posiblemente a otras impresoras Creality. También es personalizable, por lo que puede modificar las dimensiones (si desea colocar un marcador más grande o necesita un ajuste más ajustado con la impresora).

Para otras impresoras, deberá diseñar su propio mecanismo de montaje (cuando lo haga, comparta un enlace en los comentarios). Si bien también es posible usar tornillos para montar el bolígrafo, personalmente prefiero el mecanismo de recorte, ya que me permite cambiar entre los modos de impresora 3D y trazador muy rápido, y también cambiar los bolígrafos muy rápido.

Paso 2 – Calibración

Una vez que haya montado correctamente su lápiz en su impresora, es hora de calibrarlo. Deberá adjuntar una hoja de papel a la cama de la impresora:

Bolígrafo montado, papel adjunto, ¡listo para su comando!

A continuación, deberá encontrar la altura correcta para imprimir. Se recomiendo usar Repetier Host pen lugar del clasico Cura, pues Repetier Host hara todo mucho más fácil ).

Antes de comenzar, asegúrese de que la plataforma de la impresora esté nivelada y que tanto la boquilla como la plataforma de la impresora estén frías.

Después de ubicar su impresora, vaya a la pestaña «Control manual» dentro de Repetier y mueva el cabezal de impresión hacia arriba hasta que la punta del bolígrafo esté por encima del papel. Luego, mueva su eje X / Y al borde de donde desea que esté su dibujo. Finalmente, mueva el eje Z hacia abajo en incrementos de 0,1 mm, hasta que vea que la punta del bolígrafo toca el papel. A continuación, puede mover un poco la X / Y y comprobar que el bolígrafo realmente deja un rastro en el papel. Cuando termine, observe los valores X / Y / Z que aparecen en la línea superior:

Calibración de la posición de su lápiz en Repetier Host.

En mi caso, los valores fueron 47 para X, 40 para Y y 14,6 para Z. Usaremos estos valores en breve cuando generemos el archivo GCode para imprimir.

Paso 3: elegir qué imprimir y generacion del gcode

Esa es una dificil pues existen infinitass opciones. Sin embargo, deberá obtenerlo en formato vectorial, por lo que si usa Google Imágenes, agregue el texto type:svg al final de su consulta de búsqueda. También puede convertir imágenes JPEG y PNG a SVG , pero sugeriría comenzar con algo que ya viene como un vector para simplificar las cosas.

Cuando se comenza un proyecto asi seguro que se piensa en el tiempo para conseguir el hardware correcto, pero se sorprenderalo rápido que se hace funcionar la parte del hardware. Sin embargo, el software es otra historia completamente diferente; como siempre, el software es donde reside la verdadera complejidad .

 Además de Repetier Host mencionado anteriormente, también necesita obtener Inkscape (que, por cierto, ¡también es útil si desea crear arte de PCB !).

Dentro de Inkscape, cree un nuevo archivo y vaya al menú Archivo → Propiedades del documento (Acceso directo: Ctrl + Shift + D). Luego, establezca el tamaño del documento un poco más pequeño que el tamaño de la cama de impresión y asegúrese también de usarlo mm para las unidades.

Una vez que haya establecido el tamaño, puede importar cualquier archivo SVG que desee o simplemente dibujar un texto con la herramienta Texto:

Cuando termine, con el texto aún seleccionado, haga clic en el menú Ruta → Objeto a ruta (Mayús + Ctrl + C). Esto convertirá el texto en una serie de puntos conectados por líneas, lo cual es necesario para alimentar la impresora. Puede agregar más elementos como espirales y formas de estrella, repitiendo la operación «Objeto a ruta» para cada uno:

Al imprimir, los objetos no se rellenarán, por lo que es posible que desee eliminar su color de relleno y establecer su color de trazo en negro (o el color de su lápiz), para obtener una representación más precisa del resultado final. Seleccione todos los objetos (Ctrl + A) y luego elimine el relleno y aplique color negro para el trazo (Ctrl + Shift + F):

Establecer el color de la pintura de trazo en negro

Cuando esté satisfecho con el resultado, es hora de generar el GCode para la impresora. Usaremos una extensión llamada «Gcodetools», que viene incluida con Inkscape (si no, tiene una versión anterior y necesita actualizar).

Comenzaremos definiendo los puntos de orientación, que le dicen a la impresora cómo mapear las líneas en la pantalla en el papel. Vaya al Menú de extensiones → Gcodetools → Puntos de orientación  y después de asegurarse de que el modo “2 puntos” esté seleccionado, haga clic en Aplicar y luego en Cerrar . Ahora debería ver dos nuevos elementos de texto agregados en la parte inferior de su dibujo:

Estos son los puntos de orientación. Cada punto es una lista de coordenadas X, Y, Z que especifica la ubicación de destino de ese punto en el sistema de coordenadas de la impresora. Debe editarlos para que coincidan con la X / Y que encontró en el paso de calibración y establecer la Z (la tercera coordenada) en 0.

Edite el texto en el punto izquierdo y actualícelo para que contenga las coordenadas X / Y que encontró. En mi caso lo fue (47; 40; 0). Para el punto correcto, agregue 100 al valor X, copie el Y / Z del primero, por ejemplo (147; 40; 0):

A continuación, necesitamos generar una herramienta y configurar su velocidad. Este paso es opcional, pero si no lo hace, su impresora se dibujará realmente muy lento. Vaya al menú Extensiones → Gcodetools → Biblioteca de herramientas  y seleccione «predeterminado» en «Tipos de herramientas»:

Haga clic en Aplicar y luego en Cerrar, y debería ver un rectángulo verde con muchas configuraciones agregadas a su dibujo:

Puede alejar este rectángulo (junto con todos los valores) para que no se sobreponga en su dibujo. Luego, desea editar el texto y cambiar los valores de «Alimentación», «Alimentación de penetración», «Alimentación de paso» para establecer la velocidad de movimiento de la impresora al dibujar. Yo uso 4500 para todos ellos (la unidad es mm / min, por lo que este valor corresponde a 75 mm / seg).

¡Finalmente estamos listos para generar el GCode! Seleccione todos los elementos en su dibujo (Ctrl + A) y vaya a Extensiones → Gcodetools → Ruta a Gcode…

Allí, vaya a la pestaña Opciones y establezca «Escala a lo largo del eje Z» en 1, y «Desplazamiento a lo largo del eje Z» al valor Z que encontró en el paso de calibración, menos uno (encontré 14.6, así que lo configuré aquí a 13.6):

A continuación, vaya a la pestaña Preferencias y establezca el nombre del archivo de salida y la ruta del directorio cuando desee que se guarde. También puede configurar la altura segura Z en un valor más bajo, para acelerar la impresión (yo uso 5):

Finalmente, cambie a la pestaña Ruta a Gcode , configure la Función de profundidad en 1y haga clic en Aplicar. Tardará unos segundos y es posible que muestre una advertencia acerca de que no se han seleccionado rutas, que puede ignorar con seguridad. Debería ver una nueva capa en la parte superior de su dibujo, mostrando los movimientos del cabezal de impresión en el archivo Gcode generado:

En este punto, sugiero abrir el archivo .gcode en un editor de texto y verificar que se vea legítimo, especialmente que los valores Z coincidan con el valor de calibración que encontró:

¡GCode generado! Tenga en cuenta que el valor Z es 14.60000 aquí

También sugiero editar la primera linea G00 y agregar F4500 al final, de lo contrario, su impresora podría hacer que el movimiento inicial del cabezal sea realmente lento:

¡Eso es! Estás listo para imprimir. Cargue su archivo Gcode en el host de Repetier y debería ver su dibujo en la pantalla:

Diga su oración, haga clic en el botón «Iniciar impresión» y … ¡disfrute del espectáculo!

Fuente :https://urish.medium.com/

Visualización gráfica en tiempo real del consumo eléctrico en ca


En efecto gracias a la biblioteca PZEM-004T v3.0 para el monitor de energía Peacefair PZEM-004T-10A y PZEM-004T-100A v3.0 utilizando la interfaz ModBUS y una simple placa Arduino UNO podemos monitorizar el consumo eléctrico junto a otras variables eléctricas como la tensión , la frecuencia , el factor de potencia, etc

Es interesante destacar que debemos usar la ultima version del modulo, pues la versión 3.0 PZEM es una versión mejorada del antiguo PZEM-004T para el que puede encontrar la biblioteca aquí

Respecto a las conexiones eléctricas debemos tener especialmente cuidado en el conexionado de las clemas de BT , las cuales viene claramente especificadas en la hoja de característica del modulo PZEM que usemos, pues una parte es para la medida del voltaje ( la medición se hace en paralelo ) y la parte contigua es la parte de la medida de la Intensidad (la medida se toma en serie en versiones de menos intensidad maxima admisible, pero para la version de 100A se suele tomar con una bobina toroidal o con un pinza amperimétrica)

Peor tanto ,debemos extremar el cuidado especialmente en estas conexiones (las que van con tornillo).Observe por ejemplo las conexiones del modulo de 100amp usado para escribir este post:

Este módulo es una versión mejorada del PZEM-004T con funciones de medición de frecuencia y factor de potencia, disponible en los lugares habituales. Se comunica mediante una interfaz TTL sobre un protocolo de comunicación tipo Modbus-RTU, pero es incompatible con la biblioteca @olehs anterior que se encuentra aquí: https://github.com/olehs/PZEM004T .

Respecto a las conexiones del PZEM004 con Arduino Uno , estas no pueden ser mas simples:

  • TX ->GPIO12
  • RX ->GPIO11
  • GND->GND DE ARDUINO
  • VCC->5V DE ARDUINO

Especificaciones del fabricante

FunciónRango de mediciónResoluciónExactitudTODO: especificaciones realistas
Voltaje80 ~ 260 V0,1 V0,5%
Actual0 ~ 10A o 0 ~ 100A *0.01A o 0.02A *0,5%
Poder activo0 ~ 2,3kW o 0 ~ 23kW *0,1 W0,5%
Energia activa0 ~ 9999,99kWh1 Wh0,5%
Frecuencia45 ~ 65 Hz0,1 Hz0,5%
Factor de potencia0,00 ~ 1,000,011%

* Usando el transformador de corriente externo en lugar de la derivación incorporada

Compatibilidad

MCUSerie de hardwareSerie de softwareNo probadoEjemplos deNotas
ATmega168XHardware Serie Software Serie
ATmega328 ( Arduino Uno)( ✅ )✔️Hardware Serie Software SerieHW Serial entra en conflicto con la salida de depuración. Sin embargo, se puede usar sin tener ninguna salida de consola serie
ATmega2560 ( Arduino Mega)✔️✔️Hardware Serie Software Serie
ESP8266( ✅ )✔️SoftwareSerialHW Serial entra en conflicto con la salida de Debug Serial
ESP32✔️HardwareSerialSW Serial no es realmente necesario ya que ESP32 tiene 3 seriales HW con pines configurables
STM32 BluePillX

Principales características
  • Mide voltaje, corriente, potencia, energía, factor de potencia y frecuencia (nuevo en la versión 3.0)
  • 247 direcciones esclavas programables únicas
  • Contador de energía interno hasta 9999,99kWh
Otras características
  • Alarma de sobrecarga
  • Reinicio del contador de energía
  • Suma de comprobación CRC16
  • Aislamiento de red mejor, pero no perfecto

!Peligro de electrocución!

¡Asegúrese de que el dispositivo esté conectado a la alimentación de CA! Los 5V solo alimentan los optoacopladores, no el chip real. Además, tenga cuidado, ¡la tensión de ca es peligrosa! Si no sabe lo que estás haciendo, ¡puedes morir ! Eres responsable de su propia estupidez. Así que no sea estúpido.

Para ciertamente este montaje no conlleve ningún peligro debemos aislar ambas placas (por ejemplo en una caja de conexiones) para asegurarnos de que no recibimos ninguna descarga eléctrica fortuita .

Código arduino:


#include <PZEM004Tv30.h>
#include <SoftwareSerial.h>

/* Use software serial for the PZEM
 * Pin 11 Rx (Connects to the Tx pin on the PZEM)
 * Pin 12 Tx (Connects to the Rx pin on the PZEM)
*/

SoftwareSerial pzemSWSerial(11, 12);
PZEM004Tv30 pzem;

void setup() {
  //Serial.begin(115200);
   Serial.begin(2000000);
  pzem = PZEM004Tv30(pzemSWSerial);
   
      Serial.println("Volts Amp Watts kWh Hz PF%: ");   
    

}

void loop() {
         
  //  Serial.print("Custom Address:");
 //   Serial.println(pzem.readAddress(), HEX);

    // Read the data from the sensor
    float  escala=10;
    float voltage = pzem.voltage()-2.2;
    float current = pzem.current() *escala;/*10*/
    
    float power = pzem.power()* escala;
    float energy = pzem.energy() * escala;
    float frequency = pzem.frequency();
    float pf = pzem.pf();

    // Check if the data is valid
    if(isnan(voltage)){
        Serial.println("Error reading voltage");
    } else if (isnan(current)) {
        Serial.println("Error reading current");
    } else if (isnan(power)) {
        Serial.println("Error reading power");
    } else if (isnan(energy)) {
        Serial.println("Error reading energy");
    } else if (isnan(frequency)) {
        Serial.println("Error reading frequency");
    } else if (isnan(pf)) {
        Serial.println("Error reading power factor");
    } else
    {

        // Print the values to the Serial console
       // Serial.print("Voltage: ");   
        Serial.print(voltage);
          ///   Serial.println("V");
        Serial.print(" ");

        
        //Serial.print("Current: "); 
       Serial.print(current);
       // Serial.println("A");
       Serial.print(" ");
               
        //Serial.print("Power: ");  
        Serial.print(power);      
       // Serial.println("W");
       Serial.print(" ");

               
       //Serial.print("Energy: ");   
        Serial.print(energy,3);  
        // Serial.print("kWh");
         Serial.print(" ");

       // Serial.print("Frequency: ");  
      Serial.print(frequency, 1); 
     //  Serial.println("Hz");
       Serial.print(" ");
        
      //Serial.print("PF: ");     
       Serial.print(pf);
      // Serial.println("PF: ");   
        Serial.print(" ");
    
    
     //delay(20);
  Serial.println();
 
   // delay(2000);
    }

}

Salida monitor serie

Podemos ver las medidas eléctricas separadas por espacios, las cuales son las siguintes :

  • Tensión en Voltios
  • Intensidad en Amperios
  • Potencia en Watios
  • Potencia en Kw/H
  • Frecuencia en Hercios
  • Factor de Potencia(coseno de fi)

Estas lecturas se han adaptado para que el serial plotter no tenga problemas a la hora de presentarlas de forma grafica en la linea del tiempo, pero como se observa también las podemos ver claramente desde el monitor serie:

Salida serial plotter

La salida grafica la conseguimos usando Serial Plotter del Arduino IDE.

El código Arduino debe modificarse tal y como se anexa en este post para poderse representarse correctamente

En el ejemplo se muestra el momento en que se enciende una lampara halógena de 35W.

Recordad por ultimo ,que como ya se ha indicado, el módulo PZEM-004T V3.0 es una versión mejorada de PZEM-004T V2.0 y además el protocolo para comunicar la interfaz es diferente, el programa de biblioteca para PZEM-004T V2 no se puede utilizar para interfaz con PZEM-004T V3.0.

Desbloqueo de un kindle que no arranca


En efecto existe un sistema Linux envo para todos los usuarios de Windows frustrados que están tratando de desbloquear un Kindle y están luchando con la incapacidad de Windows para determinar e instalar correctamente los controladores de dispositiv, o para las personas que solo quieren desmontar un Kindle, sin sumergirse en todos los aspectos internos. Y, de hecho, incluso podría ser útil para las personas que están familiarizadas con esos componentes internos.

Para dar crédito a quien se merece el crédito: aquí están los métodos de eliminación de bloqueos simples originales para los hilos K5-Touch, K4-Mini y K3-Keyboard , que contienen prácticamente toda la información sin la cual Kubrick nunca hubiera sido posible: un enorme GRACIAS a todos. ¡Quién proporcionó información invaluable y quién desarrolló los programas fundamentales en primer lugar!

Ahora tenemos Kubrick, un LiveCD para desmontar Kindle 3, Kindle 4 y Kindle Touch. Significa que no es necesario instalar Linux para utilizar las herramientas de eliminación de ladrillos de Linux. Más noticias (y enlace de descarga) para esta increíble herramienta de eliminación de ladrillos aquí:https://www.mobileread.com/forums/sho…d.php?t=206064

Kubrick es un sistema Live Linux para desmontar dispositivos Kindle. Debería funcionar en casi todas las PC o portátiles que existen. que puede arrancar desde un CD, DVD o unidad USB. Kubrick no modifica su computadora ni su sistema operativo en absoluto – simplemente proporciona un asistente basado en cuadros de diálogo que lo guía a través de la procedimiento para desbloquear un Kindle.

Características de Kubrick:

  • Instala un impecable firmware 3.4 (K3), 4.1.1 (K4) o 5.1.2 (KT); ¡No se admiten otros dispositivos (K1, K2, KDX, Paperwhite)!
  • Instala una partición diags habilitada para SSH (K4 / KT)
  • Puede (opcionalmente) instalar el dispositivo jailbreak (K4 / KT); la imagen de K3 siempre incluye el jailbreak.
  • Puede (opcionalmente) restablecer los ajustes de configuración internos (K4 / KT)
  • Puede (opcionalmente) restaurar los archivos Text-to-Speech (KT)
  • Para los dispositivos K4 y KT, las últimas acciones opcionales también se pueden realizar de forma independiente (es decir, sin sobrescribir el firmware en la partición principal).

Todo el procedimiento implica de 5 a 10 pasos simples, y toma alrededor de 10 minutos en un K4 o KT, y alrededor de 2 horas en un K3 (las 2 horas son el tiempo que necesita para parpadear, no el tiempo que necesita para configurarlo )

CÓMO:

  1. Determine qué archivo (s) necesita, luego descargue y descomprima uno o más de los siguientes archivos:
    • Imagen ISO de Live CD , para desmontardispositivos K4 y KT :
      • Nota: también puede grabar esta imagen en un DVD.
      • Descargar (481 MB; ixtab, versión 3.6 )
      • Mirror 1 (twobob, versión 3.6 )
      • Mirror 2 (dsmid, versión 3.6 )
    • Imagen ISO de Live CD , para desmontardispositivos K3 :
      • Nota: también puede grabar esta imagen en un DVD.
      • Descargar (384 MB; ixtab, versión 3.6 )
      • Mirror 1 (twobob, versión 3.6 )
      • Mirror 2 (dsmid, versión 3.6 )
    • Imagen ISO de DVD en vivo , para desmontar dispositivos K3 , K4 y KT :
      • Nota: esta imagen debe grabarse en un DVD; es demasiado grande para un CD.
      • Descargar (783 MB; ixtab, versión 3.6 )
      • Mirror 1 (dsmid, versión 3.6 )
    • Imagen de disco USB en vivo ( capacidad requerida> = 1 GB ):
      • Nota: Además de este archivo, también se REQUIERE una de las imágenes ISO anteriores . Para actualizar una memoria USB a la versión más reciente de Kubrick, simplemente coloque la última imagen ISO en la memoria USB. Consulte el archivo README.txt contenido en la descarga para obtener más información.
      • Descargar (1,5 MB; ixtab)
      • Espejo 1 (dos bob)
      • Espejo 2 (dsmid)
  2. Lea el archivo README.txt.
    Se copia aquí de nuevo como referencia …Spoiler : 
  3. Coloque el archivo de imagen descargado en el medio de su elección, siguiendo las instrucciones contenidas en el archivo README.
  4. Inicie su computadora desde el CD / DVD o la memoria USB y espere a que se inicie el asistente en pantalla.

Asegúrese de realizar los pasos 3 y 4 con hardware físico, es decir, en una computadora real , y con un CD / DVD o memoria USB real , ¡no en una máquina virtual!
Spoiler : 

Si bien probé exhaustivamente Kubrick muchas veces en mis dispositivos, no puedo garantizar que funcione en todos los hardware en todas las situaciones imaginables. En particular, si su Kindle es FUBAR por alguna razón (por ejemplo, si realmente lo arruinó al borrar TODOS sus datos), esto tampoco ayudará. Pero debería funcionar en la mayoría de situaciones más o menos estándar en las que «mi Kindle dejó de funcionar».

Si algo sale mal durante la remoción de ladrillos:

  1. Empiece de nuevo desde el principio y asegúrese de que todas sus selecciones (¡en particular el dispositivo a desbarbar!) Sean correctas. (Sí, ha habido informes de personas que se equivocaron porque eligieron el dispositivo equivocado).
  2. Asegúrese de que su Kindle esté cargado. Si sigue teniendo problemas, mientras que debricking, PARADA – y cargar la batería con un cargador de pared durante al menos 20 horas . Luego reinicie el procedimiento. Los Kindles descargados son la causa número uno de comportamiento extraño.

Cosas técnicas:
Spoiler : 

A continuación se muestran algunas capturas de pantalla de cómo se ve la interfaz de usuario. Tenga en cuenta que estos se tomaron mientras se ejecutaba en una máquina virtual y son solo algunos ejemplos. Todo el procedimiento implica más acciones y normalmente debería realizarse en un ordenador «real» (¡física!), No en una máquina virtual.

1-Pantalla de bienvenida al arrancar con un USB o cd sera similar a la siguiente:

2-Ahora debemos seleccionar el modelo del kindle

3-Finalmente tenemos que conectar el kindle al ordenador y seguir las instrucciones:

Preguntas y respuestas:
----------------------

P: ¿Cómo preparo Kubrick para su uso?
R1: Si descargó una imagen de CD o DVD:
Grabe boot.iso en un CD o DVD. Cómo hacer esto depende de su
SO y software instalado. En caso de duda, pregunte a su motor de búsqueda favorito.
A2: Si desea crear una memoria USB de arranque:
ANTES DE COMENZAR: El siguiente procedimiento *** BORRARÁ TODOS LOS
DATOS DEL USB STICK *** - Se le ha advertido.
PASO 1:
- Descarga y descomprime kubrick-usb-base.zip. Esto es muy
archivo pequeño que proporciona un sistema de archivos USB básico de 1 GB que puede arrancar
una imagen de Kubrick en muchas computadoras. Sin embargo, * NO * contiene un
sistema actual de Kubrick todavía. Consulte a continuación (paso 2) para obtener más información.
- Escriba kubrick-usb-base.img en su memoria USB. Cómo hacer esto depende
en su sistema operativo y el software instalado, pero aquí hay algunas sugerencias:
* En Windows, puede utilizar http://sourceforge.net/projects/win32diskimager/
* En Linux o MacOS, puede usar la línea de comando, por ejemplo:
sudo dd if = kubrick.img of = <DISPOSITIVO_USB>. En caso de duda, busque el
Internet para obtener detalles sobre cómo usar correctamente dd en su
plataforma, hay muchos tutoriales.
PASO 2:
- Descargue y descomprima una imagen ISO (CD o DVD) que admita la
Kindle (s) que desea desmontar.
- Copie el "boot.iso" de esa descarga en el "efi / boot /" existente
directorio en la memoria USB de Kubrick. No cree ni modifique otros
archivos o directorios en la memoria USB.
- Expulse de forma segura la memoria USB. La memoria USB ya está preparada para arrancar.
y desmonte los dispositivos que seleccionó.

P: Después de la preparación, ¿cómo lo uso?
R: Inserte el CD, DVD o dispositivo USB en su computadora.
Haga que la computadora arranque desde el dispositivo Kubrick.
Nuevamente, el procedimiento exacto realmente depende de su hardware, por lo que
No puedo dar más instrucciones específicas. La mayoría de las computadoras
le permite elegir el dispositivo de arranque mediante una tecla de función,
como F8, F9, F10 o F12.
- En computadoras más antiguas, es posible que deba ingresar al BIOS para seleccionar manualmente
el orden de arranque.
- En computadoras Apple, mantenga presionada la tecla "alt" ("opción") izquierda mientras
encender la computadora. El CD / DVD se mostrará con un icono de CD etiquetado
"Windows" y la memoria USB con un icono de disco USB con la etiqueta "EFI Boot".
Consulte a continuación para obtener más notas de Apple.
P: ¿Qué hago en la pantalla de inicio?
R: Por lo general, no es necesario que haga nada. Espere unos segundos.

P: Ok, arrancó, ¿y ahora qué?
R: El asistente de eliminación de ladrillos debería iniciarse automáticamente.
Las únicas teclas que realmente necesita a partir de ahí son las teclas de flecha,
y la tecla ENTER. Sigue las instrucciones en la pantalla.

P: Estoy usando una computadora Apple con la memoria USB y no arranca.
R: Bienvenido al universo de Apple. En primer lugar, Kubrick solo funcionará en Intel
Macs. No funcionará en modelos antiguos de Mac (PowerPC), porque estos usan un
procesador completamente diferente. Dicho esto, la mayoría de las Mac modernas pueden arrancar
desde esa memoria USB, pero posiblemente solo si también instala Boot Camp.
Intente arrancar desde un CD o DVD. Si eso no funciona, bueno,
vea el credo de "pensar diferente" en acción.

P: El archivo kubrick-usb-base.img funciona, pero ahora mi memoria USB
solo aparece como 1GB, en lugar de su capacidad real de 4/16 / X GB.
R: Sí, eso es normal. Utilice una herramienta que le permita (de forma no destructiva)
cambiar el tamaño de las particiones. Un ejemplo sería GParted:
http://gparted.sourceforge.net/

P: Soy un usuario avanzado y quiero arrancar Kubrick con un kernel personalizado
parámetros. Cómo puedo...?
R1: Al iniciar desde un CD o DVD, edite el indicador de inicio o siga las
instrucciones de isolinux.
R2: al arrancar desde una memoria USB en hardware x86 estándar, utilice GRUB
Mecanismos incorporados para modificar el comportamiento de arranque. Alternativamente, edite el
boot / grub / grub.cfg en la memoria USB.
A3: al arrancar desde una memoria USB en hardware EFI (por ejemplo, un dispositivo Apple),
edite el archivo efi / boot / grub.cfg.

P: ¿Permitirá Kubrick desmontar Kindle 1, 2, DX, Paperwhite?
R: No, porque estos dispositivos no se pueden eliminar a través de USB. Lo siento.

P: ¿Por qué "Kubrick"?
R: Solo porque 🙂
Bueno, está bien: inicialmente le puse un nombre en código a este proyecto KindleDebrick, luego
KDebrick (o KUnbrick o algo así) ... y luego terminó con Kubrick

Monitorización de corriente continua


La medición de la Intensidad de la corriente siempre es un poco desafiante, ya que tenemos que medirla en un circuito en serie pues por lo general, la medición no es posible sin romper un circuito, insertando algunos cables para la medida.

Hay algunos métodos directos que utilizan una masa comun entre el dispositivo medido y el dispositivo de medición con la ayuda de un registro entre ellos. Pero tales métodos son nunca tan confiables debido al uso de una masa común, que puede hacer que los sistemas sean inestables.

Los sensores podrían ayudar a resolver este desafío. Los sensores como el INA219 de Texas Instruments operan en una configuración de bus I2C que hace posible medir la corriente viva.

  • El módulo del sensor de corriente está configurado para monitorear la caída de voltaje de los pines y el voltaje de alimentación del bus, tiempos de conversión y opciones de filtro.
  • El valor de calibración programado del módulo de corriente digital de alta precisión se combina con un multiplicador interno para admitir la lectura directa de corriente.
  • El INA219 es un monitor de alimentación y bypass que admite la interfaz I2C o SMBUS.
  • La función de consumo de energía ultrabajo del módulo del sensor de corriente de la interfaz I2C se puede utilizar de manera adecuada y adecuada en equipos que funcionan con baterías.
  • El módulo del sensor de corriente se caracteriza por una salida de señal I2C, que puede comunicarse directamente con el sistema principal.

ina219 Stromsensormodul

En este proyecto, la primera parte fue conectar este sensor con una MCU , que en este caso fue un ESP32 con Arduino IDE debido a su facilidad de uso y capacidad para monitoreo remoto a través de internet ,aunque también puede funcionar con una Raspberry Pi como vamos a ver.

INA219

En el caso de usar como MCU una Raspberry el desafío que se enfrentó el autor fue encender esta a través de GPIO usando un convertidor de USB a TTL. El Raspberry Pi no se inicia y las medidas tampoco aparecen ,pero el autor encontró una solución sobre la marcha.

Ahora, se tiene la solución para encender RaspberryPi a través de GPIO. El problema es que se requiere usar GPIO 2 y 4 para suministrar energía de 5V y GPIO 6 para suministrar tierra.

La siguiente imagen muestra el Pi en ejecución a través de Putty y sus actualizaciones, la imagen es el gráfico de la absorción de corriente en mAmps por Pi, alcanzando el máximo alrededor de 900 mAmps solo a veces.

Normalmente permanece alrededor de 500mAmps.

Cuando la RaspberryPi funciona con comandos sudo de apagado todavía hay algo de energía requerida por el LED de estado y otras funciones internas. Si desenchufamos el cable, el consumo de energía será cercano a cero, como en las siguientes capturas de pantalla.

Tambien se puede agregar una pequeña pantalla que pudiera mostrar los datos en vivo para el monitoreo de energía por ejemplo una pantalla LCD SSD1306 para que funcione.

Una idea más es que los datos de monitoreo de energía se pueden enviar a los ruidosos, como AWS IoT, donde los datos se manipulan de manera efectiva, pero eso es demasiado para un dispositivo tan pequeño. Además, no encaja con el proyecto.

Una cosa más interesante es que un PoE HaT para RaspberryPi (básicamente cualquier placa) podría tener capacidad de monitoreo actual con LCD. Sería interesante saber qué parte del software / hardware consume más energía.

A continuación el código del proyecto para Arduino con los comentarios en español;

    #include <Adafruit_GFX.h>  
    #include <Adafruit_SSD1306.h>  
    #include <Wire.h>  
    #include <Adafruit_INA219.h>  
      
      
    #define SCREEN_WIDTH 128 // Ancho de pantalla OLED, en píxeles  
    #define SCREEN_HEIGHT 32 // Altura de la pantalla OLED, en píxeles  
      
      
    #define OLED_RESET 4 // Restablecer el pin # (o -1 si se comparte el pin de restablecimiento de Arduino)  
    #define SCREEN_ADDRESS 0x3C /// <Consulte la hoja de datos para la dirección; 0x3D para 128x64, 0x3C para 128x32  
    Pantalla Adafruit_SSD1306 (SCREEN_WIDTH, SCREEN_HEIGHT, & Wire, OLED_RESET);  
      
      
    Adafruit_INA219 ina219;  
      
     void setup()   
    {  
      Serial.begin ( 115200 );  
      while  (! Serial) {  
          // pausará Zero, Leonardo, etc.hasta que se abra la consola serie  
       delay( 1 );  
      }  
      if (! display.begin (SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {  
        Serial.println (F ( "Falló la asignación SSD1306" ));  
       halt (;;); // No continúes, bucle para siempre  
      }  
      display.display ();  
      delay ( 2000 ); // Pausa por 2 segundos  
      display.clearDisplay ();  
        
      uint32_t currentFrequency;  
          
      Serial.println ( "¡Hola!" );  
        
      // Inicializa el INA219.  
      // Por defecto, la inicialización usará el rango más grande (32V, 2A). Sin embargo  
      // puede llamar a una función setCalibration para cambiar este rango (ver comentarios).  
      if  (! ina219.begin ()) {  
        Serial.println ( "No se pudo encontrar el chip INA219" );  
        while  ( 1 ) {retraso ( 10 ); }  
      }  
      // Para usar un rango de 32V, 1A ligeramente más bajo (mayor precisión en amperios):  
      //ina219.setCalibration_32V_1A();  
      // O para usar un rango más bajo de 16V, 400mA (mayor precisión en voltios y amperios):  
      //ina219.setCalibration_16V_400mA();  
      
      
      Serial.println ( "Medición de tensión y corriente con INA219 ..." );  
    }  
      
      
     void loop ()   
    {  
       tensión de derivación de flotación =  0 ;  
       voltaje del bus flotante =  0 ;  
      flotar  current_mA =  0 ;  
       voltaje de carga flotante =  0 ;  
      flotación  power_mW =  0 ;  
      
      
      shuntvoltage = ina219.getShuntVoltage_mV ();  
      busvoltage = ina219.getBusVoltage_V ();  
      current_mA = ina219.getCurrent_mA ();  
      power_mW = ina219.getPower_mW ();  
      tensión de carga = tensión de bus + (tensión de derivación /  1000 );  
        
      //Serial.print("Bus Voltage: "); Serial.print (busvoltage); Serial.println ("V");  
      //Serial.print("Shunt Voltage: "); Serial.print (shuntvoltage); Serial.println ("mV");  
      //Serial.print("Load Voltage: "); Serial.print (voltaje de carga); Serial.println ("V");  
      Serial.print ( "Actual:" ); Serial.print (current_mA); Serial.println ( "mA" );  
      //Serial.print("Power: "); Serial.print (potencia_mW); Serial.println ("mW");  
      Serial.println ( "" );  
      
      
      delay( 10 );  
        
      display.clearDisplay ();  
      display.setTextSize ( 2 );  
      display.setTextColor (SSD1306_WHITE);  
      display.setCursor ( 5 , 5 );  
      display.print (current_mA);  
      display.print ( "mA" );  
      
      
        
    // display.setCursor (0,0);  
    // display.print (power_mW);  
    // display.print ("mWatt");  
        
      display.display ();  
      delay( 100 );  
      display.clearDisplay ();  
            
    }  


Fuente :https://www.element14.com