Processing + Arduino + Serial port + Cp5.listbox - user-interface

I would like to create a "listbox" (using the controlP5 GUI library) containing the serial port list: the goal is to create a stand alone app using Processing to communicate with Arduino Uno, independently from which OS I'm going to use (win, mac or linux), and select (with the "listbox") the correct Serial Port to communicate with Arduino.
is it possible??

ControlP5 cp5 = new ControlP5(this);
ListBox listBox = cp5.addListBox("serialPorts");
Serial serial;
String[] ports = Serial.list();
for (int i=0; i<ports.length; i++) {
listBox.addItem(ports[i]);
}
void controlEvent(ControlEvent theEvent) {
if(theEvent.isGroup() && theEvent.name().equals("myList")){
int val = (int)theEvent.group().value();
serial = new Serial(this, ports[val], 9600);
}
}
untested, but that's the basic idea...

Related

How to display microbit's orientation as a 3d model in processing?

I am working on a project with my rocketry club.
I want to have a microbit control the orientation of the fins to auto-stabilize the rocket.
But first, I tried to make a processing code to display in real-time my micro-bit's orientation using its integrated gyroscope.
Here's my processing code :
import processing.serial.*; // import the serial library
Serial myPort; // create a serial object
float xRot = 0; // variables to store the rotation angles
float yRot = 0;
float zRot = 0;
String occ[];
void setup() {
size(400, 400, P3D); // set the size of the window and enable 3D rendering
String portName = Serial.list()[0]; // get the name of the first serial port
myPort = new Serial(this, portName, 115200); // open a connection to the serial port
println((Object[]) Serial.list());
}
void draw() {
background(255); // clear the screen
translate(width/2, height/2, 0); // center the cube on the screen
rotateX(xRot); // apply the rotations
rotateZ(yRot);
rotateY(zRot);
fill(200); // set the fill color
box(100); // draw the cube
}
void serialEvent(Serial myPort) {
// this function is called whenever new data is available
// read the incoming data from the serial port
String data = myPort.readStringUntil('\n'); // read the data as a string
// print the incoming data to the console if it is not an empty string
if (data != null) {
println(data);
}
delay(10);
if (data != null) {
// split the string into separate values
String[] values = split(data, ',');
// convert the values to floats and store them in the rotation variables
xRot = radians(float(values[0]));
yRot = radians(float(values[1]));
zRot = radians(float(values[2]));
}
}
and here's the python code I have on my microbit
pitch = 0
roll = 0
x = 0
y = 0
z = 0
def on_forever():
global pitch, roll, x, y, z
pitch = input.rotation(Rotation.PITCH) + 90
roll = input.rotation(Rotation.ROLL) + 90
servos.P2.set_angle(pitch)
servos.P1.set_angle(roll)
x = input.rotation(Rotation.PITCH)
y = input.rotation(Rotation.ROLL)
z = 1
serial.set_baud_rate(BaudRate.BAUD_RATE115200)
serial.write_string(str(x) + "," + str(y) + "," + str(z) + "\n")
basic.forever(on_forever)
What happens when I run my code is that a cube appears and rotates weirdly for a short time, then, the cube stops and processing prints "Error, disabling serialEvent() for COM5 null".
Please help me out, I really need this code to be working!
Is this the documentation for the micro:bit Python API you're using ?
input.rotation (as the reference mentions), returns accelerometer data:
a number that means how much the micro:bit is tilted in the direction you ask for. This is a value in degrees between -180 to 180 in either the Rotation.Pitch or the Rotation.Roll direction of rotation.
I'd start with a try/catch block to get more details on the actual error.
e.g. is it the actual serial communication (e.g. resetting the baud rate over and over again (serial.set_baud_rate(BaudRate.BAUD_RATE115200)) instead of once) or optimistically assuming there will be 0 errors in serial communication and the string will always split to at least 3 values.
Unfortunately I won't have the resources to test with an actual device, so the following code might contain errors, but hopefully it illustrates some of the ideas.
I'd try simplifying/minimising the amount of data used on the micropython (and setting the baud rate once) and removing the need to read accelerometer data twice in the same iteration. If z is always 1 it can probably be ignored (you always rotate by 1 degree in Processing if necessary):
pitch = 0
roll = 0
x = 0
y = 0
def on_forever():
global pitch, roll, x, y
x = input.rotation(Rotation.PITCH)
y = input.rotation(Rotation.ROLL)
pitch = x + 90
roll = y + 90
servos.P2.set_angle(pitch)
servos.P1.set_angle(roll)
serial.write_string(str(x) + "," + str(y) + "\n")
serial.set_baud_rate(BaudRate.BAUD_RATE115200)
basic.forever(on_forever)
On the processing side, I'd surround serial code with try/catch just in case anything went wrong and double check every step of the string parsing process:
import processing.serial.*; // import the serial library
Serial myPort; // create a serial object
float xRot = 0; // variables to store the rotation angles
float yRot = 0;
void setup() {
size(400, 400, P3D); // set the size of the window and enable 3D rendering
String portNames = Serial.list();
println(portNames);
String portName = portNames[0]; // get the name of the first serial port
try {
myPort = new Serial(this, portName, 115200); // open a connection to the serial port
myPort.bufferUntil('\n');
} catch (Exception e){
println("error opening serial port " + portName + "\ndouble check USB is connected and the port isn't already open in another app")
e.printStackTrace();
}
}
void draw() {
background(255); // clear the screen
translate(width/2, height/2, 0); // center the cube on the screen
rotateX(xRot); // apply the rotations
rotateZ(yRot);
fill(200); // set the fill color
box(100); // draw the cube
}
void serialEvent(Serial myPort) {
try{
// this function is called whenever new data is available
// read the incoming data from the serial port
String data = myPort.readString(); // read the data as a string
// print the incoming data to the console if it is not an empty string
if (data != null) {
println(data);
// cleanup / remove whitespace
data = data.trim();
// split the string into separate values
String[] values = split(data, ',');
if (values.length >= 2){
// convert the values to floats and store them in the rotation variables
xRot = radians(float(values[0]));
yRot = radians(float(values[1]));
}else{
println("received unexpected number of values");
printArray(values);
}
}
} catch (Exception e){
println("error reading serial:");
e.printStackTrace();
}
}
(If the above still produces serial errors I'd also write a separate test that doesn't use the servos, just in case internally some servo pwm timing/interrupts alongside accelerometer data polling interferes with serial communication for some reason.)
(AFAIK there is no full IMU support on the micro::bit (e.g. accelerometer + gyroscope + magnetometer (+ ideally sensor fusion)), just accelerometer + magnetometer. If you want to get basic rotation data, but don't care for full 3D orientation of the device should suffice. Otherwise you'd need an IMU (e.g BNO055 or newer) which you can connect to the micro via I2C (but will also probably need to implement the communications protocol to the sensor if someone else hasn't done so already).(In theory I see there's Python support for the Nordic nRF52840 chipset, however microbit uses nRF51822 for v1 and nRF52833 for v2 :/). Depending on your application you might want to switch to a different microcontroller altogether. (for example the official Arduino 33 BLE has a built-in accelerometer (and Python support) (and even supports TensorFlow Lite))
Since I do not have a microbit I tested your Processing code using an Arduino UNO at 9600 baud rate. The following serialEvent() function runs without error:
void serialEvent(Serial myPort) {
String data = myPort.readStringUntil('\n');
if (data != null) {
String inStr = trim(data);
String[] values = split(inStr, ',');
printArray(values);
// convert the values to floats and store them in the rotation variables
xRot = radians(float(values[0]));
yRot = radians(float(values[1]));
zRot = radians(float(values[2]));
}
}
Arduino code:
byte val1 = 0;
byte val2 = 0;
byte val3 = 0;
void setup() {
Serial.begin(9600);
}
void loop() {
val1 += 8;
val2 += 4;
val3 += 2;
String s = String(String(val1) + "," + String(val2) + "," + String(val3));
Serial.println(s);
}
Thank you very much George Profenza, it works perfectly well now!
I just had to fix some errors in the code.
Here's the functional code if anyone has this problem later :
import processing.serial.*; // import the serial library
Serial myPort; // create a serial object
float xRot = 0; // variables to store the rotation angles
float yRot = 0;
void setup() {
size(400, 400, P3D); // set the size of the window and enable 3D rendering
String portNames[] = Serial.list();
printArray(portNames);
String portName = portNames[0]; // get the name of the first serial port
try {
myPort = new Serial(this, portName, 115200); // open a connection to the serial port
myPort.bufferUntil('\n');
}
catch (Exception e) {
println("error opening serial port " + portName + "\ndouble check USB is connected and the port isn't already open in another app");
e.printStackTrace();
}
}
void draw() {
background(255); // clear the screen
translate(width/2, height/2, 0); // center the cube on the screen
rotateX(xRot); // apply the rotations
rotateZ(yRot);
fill(200); // set the fill color
box(100); // draw the cube
}
void serialEvent(Serial myPort) {
try {
// this function is called whenever new data is available
// read the incoming data from the serial port
String data = myPort.readString(); // read the data as a string
// print the incoming data to the console if it is not an empty string
if (data != null) {
println(data);
// cleanup / remove whitespace
data = data.trim();
// split the string into separate values
String[] values = split(data, ',');
if (values.length >= 2) {
// convert the values to floats and store them in the rotation variables
xRot = radians(float(values[0]));
yRot = radians(float(values[1]));
} else {
println("received unexpected number of values");
printArray(values);
}
}
}
catch (Exception e) {
println("error reading serial:");
e.printStackTrace();
}
}
As for the Micro:Bit, I didn't have to change the code at all...
I assume their was an error with the Z axis since we basically just removed removed that...

How to add a function to dropdown list?

I've added a drop down list in processing using controlp5 library. I want to transmit data serially to Arduino when certain item is selected in the list. How to add the control for this purpose?
Here's my code:
void setup{
d1 = cp5.addDropdownList("color")
.setPosition(((width/4)-50), ((height/2)-40))
.setBackgroundColor(color(37, 126, 214))
.setFont(font1)
.setItemHeight(25)
.setBarHeight(20)
.addItem("red ", d1)
.addItem("blue ", d1)
.addItem("green ", d1)
}
I want to send a character 'r','b','g' to Arduino when each item is selected respectively. Suggest me how to write the code for my purpose.
Dropdown list is deprecated as the author says in the example, I think the simplest way is to implement ScrollableList, which is more flexible, and send the data though Serial Port to Arduino.
// Import java utils, for the list to add to the scrollable list
import java.util.*;
// Import ControlP5 library and declare it
import controlP5.*;
ControlP5 cp5;
// Import the Serial port and declare it
import processing.serial.*;
Serial myPort; // Create object from Serial class
void setup() {
size(400, 400);
// Initialize the Serial port
String portName = Serial.list()[0];
myPort = new Serial(this, portName, 9600);-
// Initialize the dropdown list
cp5 = new ControlP5(this);
List l = Arrays.asList("red", "green", "blue");
/* add a ScrollableList, by default it behaves like a DropdownList */
cp5.addScrollableList("dropdown")
.setPosition(100, 100)
.setSize(200, 100)
.setBarHeight(20)
.setItemHeight(20)
.addItems(l)
;
}
void draw() {
background(255);
}
// Dropdown callback function fromthe ScrollableList, triggered when you select an item
void dropdown(int n) {
/* request the selected item based on index n and store in a char */
String string = cp5.get(ScrollableList.class, "dropdown").getItem(n).get("name").toString();
char c = string.charAt(0);
// Write the char to the serial port
myPort.write(c);
}
On the Arduino side
char val; // Data received from the serial port
void setup() {
Serial.begin(9600); // Start serial communication at 9600 bps
}
void loop() {
while (Serial.available()) { // If data is available to read,
val = Serial.read(); // read it and store it in val
}
}

Pulse sensor coding for Netduino Plus 2 gone wrong

I'm currently doing a project on Netduino Plus 2 using .net micro framework which requires me to code for a pulse sensor. I have tried finding codes for pulse sensor but to no avail. I tried using AnalogInput codes for pulse sensor but the output values seemed wrong (there was a constant high value despite no heartbeat placed near the sensor). Please advise!
Here are my current codes for the heartbeat sensor:
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using SecretLabs.NETMF.Hardware;
using SecretLabs.NETMF.Hardware.Netduino;
namespace heartrate
{
public class Program
{
public static void Main()
{
SecretLabs.NETMF.Hardware.AnalogInput rate =
new SecretLabs.NETMF.Hardware.AnalogInput(Pins.GPIO_PIN_A0);
int sensorvalue = 0;
while (true)
{
sensorvalue = rate.Read();
Debug.Print("" + sensorvalue);
Thread.Sleep(1000);
}
}
}
}
Here are the specs of the sensor, how it looks like and how it is connected.
http://www.elecrow.com/wiki/index.php?title=Pulse_Sensor
(This tutorial is for arduino, but I think the wiring is similar to that of Netduino)
Hard to tell without specs on your pulse device and how it is attached. For Analog input & output in my latest project (https://github.com/osstekz/cncBuddy) I use classes InputPort & OutputPort (Microsoft.SPOT.Hardware)
ex:
public NESControllerAdapter(Cpu.Pin pinClk, Cpu.Pin pinLatch, Cpu.Pin pinData1/*, Cpu.Pin pinData2 = Cpu.Pin.GPIO_NONE*/) {
// Binds to all pins
this._outpClk = new OutputPort(pinClk, false);
this._outpLatch = new OutputPort(pinLatch, false);
this._inpData1 = new InputPort(pinData1, false, Port.ResistorMode.Disabled);
//if (pinData2 != Cpu.Pin.GPIO_NONE) this._inpData2 = new InputPort(pinData2, false, Port.ResistorMode.Disabled);
}
...then like your rate.Read(); loop
public int ButtonPressed() {
// Locks all parms
this._PinTick(this._outpLatch);
// Reads plug state value
for (int i = 0; i < CncBuddyShared.iTOTALNESCONTROLLERBUTTONS; ++i) {
// Read the value, if true return this index as the first pressed button
if (this._inpData1.Read() == false) return i;
// Selects the next value
this._PinTick(this._outpClk);
}
return NESCONTROLLER_PRESSEDBUTTOM_NONE;
}

Serial COM Port Selection by DropDownList in processing

I wrote a program in Processing 2.1.2 to establish a communication via serial Port between two machines. On my laptop, it was working fine but on my desktop where more than one serial ports are available, it is not detecting my functional serial COM port.
So now I want them to appear on Combo Button and I will able to select one from them.
Can you guide me on how do I resolve this issue?
import processing.serial.*;
String input;
Serial port;
void setup() {
size(448, 299,P3D);
println(Serial.list());
port = new Serial(this,Serial.list()[0], 9600);
port.bufferUntil('\n');
}
void draw() {
background(0);
}
void serialEvent(Serial port)
{
input = port.readString();
if(input != null) {
String[] values = split(input, " ");
println(values[0]);
println(values[1]);
println(values[2]);
}
}
As mentioned in the comment, it is possible to use a UI library to display a dropdown. First you have to choose a library, like for example controlP5 which is very popular with Processing. You may choose to use Swing with a native look & feel or G4P. That's totally up to you.
After that it should be a matter of plugging the serial ports list into the dropdown and opening the serial connection on the dropdown listener/callback.
Bellow is a proof of concept sketch based on the controlP5dropdownlist example that comes with the library:
import processing.serial.*;
import controlP5.*;
ControlP5 cp5;
DropdownList serialPortsList;
Serial serialPort;
final int BAUD_RATE = 9600;
void setup() {
size(700, 400,P3D);
String[] portNames = Serial.list();
cp5 = new ControlP5(this);
// create a DropdownList
serialPortsList = cp5.addDropdownList("serial ports").setPosition(10, 10).setWidth(200);
for(int i = 0 ; i < portNames.length; i++) serialPortsList.addItem(portNames[i], i);
}
void controlEvent(ControlEvent theEvent) {
// DropdownList is of type ControlGroup.
// A controlEvent will be triggered from inside the ControlGroup class.
// therefore you need to check the originator of the Event with
// if (theEvent.isGroup())
// to avoid an error message thrown by controlP5.
if (theEvent.isGroup()) {
// check if the Event was triggered from a ControlGroup
println("event from group : "+theEvent.getGroup().getValue()+" from "+theEvent.getGroup());
//check if there's a serial port open already, if so, close it
if(serialPort != null){
serialPort.stop();
serialPort = null;
}
//open the selected core
String portName = serialPortsList.getItem((int)theEvent.getValue()).getName();
try{
serialPort = new Serial(this,portName,BAUD_RATE);
}catch(Exception e){
System.err.println("Error opening serial port " + portName);
e.printStackTrace();
}
}
else if (theEvent.isController()) {
println("event from controller : "+theEvent.getController().getValue()+" from "+theEvent.getController());
}
}
void draw() {
background(128);
}
Also notice any existing connection will be closed when choosing a new serial port and errors handling opening the serial port are handled so the program doesn't crash in case there are issues.
For example, on OSX you get bluetooth serial ports, which may or may not be available or of use:
for processing 3.3.7 doesn't work at all for one string
String portName = serialPortsList.getItem((int)theEvent.getValue()).getName();
So i spent a lot of my neurons and nervs, but my fix is getName change toString();
and
String portName = serialPortsList.getItem((int)theEvent.getValue()).toString();
I don't understand why getName() gives me "The function doesnt exist" but toString works properly. Anybody can explain?
For variable:
String[] portNames = Serial.list();
change to global variable:
String[] portNames;
In:
void setup()
change:
String[] portNames = Serial.list();
to:
portNames = Serial.list();
In code:
String portName = serialPortsList.getItem((int)theEvent.getValue()).toString();
change to:
String portName =portNames.toString();

Developing iTunes like application in c#

I need to develop an application in c# that could automatically detect an iPhone when it is connected to the system and read a particular file for the iPhone file system. I basically want this file to be downloaded automatically from device to the PC. I used USBpcap tool that suggests that iTunes connects to phone using some XML format. Any help or insight greatly appreciated. Is there any documentation of Third party APIs that can get me started? There are some applications that can replicate iTunes functionality e.g Copytrans
Is there any protocol or APIs provided by Apple?
I have been digging the internet and found this link Layered communication for iPhone.
Also I am using the LibUsbDotNet libraries for communicating to the usb device(Example). Can any one suggest which EndPoints should be used.
It seems to me that I have to implement usbmuxd in windows application. It is a multilayer protocol. There must be some libraries that implement usbmuxd(I dont think I have to implement the protocol all by my self)
I dont have much idea about iTunes communication as well as USB communication. I am adding as much information as I can(of course with the things I come up with in my R&D). Any help is highly appreciated.
public static DateTime LastDataEventDate = DateTime.Now;
public static UsbDevice MyUsbDevice;
#region SET YOUR USB Vendor and Product ID!
public static UsbDeviceFinder MyUsbFinder = new UsbDeviceFinder(1452, 4768);
#endregion
private void LibUSB()
{
ErrorCode ec = ErrorCode.None;
try
{
// Find and open the usb device.
MyUsbDevice = UsbDevice.OpenUsbDevice(MyUsbFinder);
// If the device is open and ready
if (MyUsbDevice == null)
throw new Exception("Device Not Found.");
// If this is a "whole" usb device (libusb-win32, linux libusb)
// it will have an IUsbDevice interface. If not (WinUSB) the
// variable will be null indicating this is an interface of a
// device.
IUsbDevice wholeUsbDevice = MyUsbDevice as IUsbDevice;
if (!ReferenceEquals(wholeUsbDevice, null))
{
// This is a "whole" USB device. Before it can be used,
// the desired configuration and interface must be selected.
// Select config #1
wholeUsbDevice.SetConfiguration(1);
// Claim interface #0.
wholeUsbDevice.ClaimInterface(0);
}
// open read endpoint 1.
UsbEndpointReader reader = MyUsbDevice.OpenEndpointReader(ReadEndpointID.Ep03);
// open write endpoint 1.
UsbEndpointWriter writer = MyUsbDevice.OpenEndpointWriter(WriteEndpointID.Ep02);
int bytesWritten;
ec = writer.Write(usbmux_header.GetBytes(), 2000, out bytesWritten);
if (ec != ErrorCode.None)
throw new Exception(UsbDevice.LastErrorString);
byte[] readBuffer = new byte[1024];
while (ec == ErrorCode.None)
{
int bytesRead;
// If the device hasn't sent data in the last 100 milliseconds,
// a timeout error (ec = IoTimedOut) will occur.
ec = reader.Read(readBuffer, 10000, out bytesRead);
if (ec == ErrorCode.Win32Error)
throw new Exception("port not open");
if (bytesRead == 0)
throw new Exception("No more bytes!");
// Write that output to the console.
Console.Write(Encoding.Default.GetString(readBuffer, 0, bytesRead));
}
}
catch (Exception ex)
{
Console.WriteLine();
Console.WriteLine((ec != ErrorCode.None ? ec + ":" : String.Empty) + ex.Message);
}
finally
{
if (MyUsbDevice != null)
{
if (MyUsbDevice.IsOpen)
{
// If this is a "whole" usb device (libusb-win32, linux libusb-1.0)
// it exposes an IUsbDevice interface. If not (WinUSB) the
// 'wholeUsbDevice' variable will be null indicating this is
// an interface of a device; it does not require or support
// configuration and interface selection.
IUsbDevice wholeUsbDevice = MyUsbDevice as IUsbDevice;
if (!ReferenceEquals(wholeUsbDevice, null))
{
// Release interface #0.
wholeUsbDevice.ReleaseInterface(0);
}
MyUsbDevice.Close();
}
MyUsbDevice = null;
// Free usb resources
UsbDevice.Exit();
}
}
}
class usbmux_header
{
public static UInt32 length = 10; // length of message, including header
public static UInt32 reserved = 0; // always zero
public static UInt32 type = 3; // message type
public static UInt32 tag = 2; // responses to this query will echo back this tag
public static byte[] GetBytes()
{
byte[] lgth = BitConverter.GetBytes(length);
byte[] res = BitConverter.GetBytes(reserved);
byte[] tpe = BitConverter.GetBytes(type);
byte[] tg = BitConverter.GetBytes(tag);
byte[] retArray = new byte[16];
lgth.CopyTo(retArray, 0);
res.CopyTo(retArray, 4);
tpe.CopyTo(retArray, 8);
tg.CopyTo(retArray, 12);
return retArray;
}
};
I have been trying to send hello packet bytes to iPhone but I am not able to read any response from phone.
To play with ipod you can use SharePodLib
As I understand it, only one client can use the USB connection to iOS at one time. On both macOS and Windows, that one client is usbmux. That library multiplexes TCP connections with higher-level clients, including iTunes, Photos, and (on macOS) the open-source peertalk library.
So on Windows, you wouldn't want to implement your own usbmux, but rather a client that sits on top of that, analogous to peertalk. I haven't seen anything open-source that does this, but a number of developers have accomplished it with their own proprietary software.
If anybody else has pointers about using usbmux on Windows, I'd love to hear about it.
—Dave
You can use imobiledevice-net. It provides a C# API to connect to iOS devices using your PC.
For example, to list all iOS devices connected to your PC, you would run something like this:
ReadOnlyCollection<string> udids;
int count = 0;
var idevice = LibiMobileDevice.Instance.iDevice;
var lockdown = LibiMobileDevice.Instance.Lockdown;
var ret = idevice.idevice_get_device_list(out udids, ref count);
if (ret == iDeviceError.NoDevice)
{
// Not actually an error in our case
return;
}
ret.ThrowOnError();
// Get the device name
foreach (var udid in udids)
{
iDeviceHandle deviceHandle;
idevice.idevice_new(out deviceHandle, udid).ThrowOnError();
LockdownClientHandle lockdownHandle;
lockdown.lockdownd_client_new_with_handshake(deviceHandle, out lockdownHandle, "Quamotion").ThrowOnError();
string deviceName;
lockdown.lockdownd_get_device_name(lockdownHandle, out deviceName).ThrowOnError();
deviceHandle.Dispose();
lockdownHandle.Dispose();
}

Resources