Monday 8 June 2020

GPS module

We need:
  • Raspberry Pi with Raspbian - in previous articles I described the installation based on Arch Linux distribution, unfortunately there is currently Arch Linux has no installer. Sorry, but I don't have time for low-level Arch Linux installation
  • USB GPS Receiver

Raspberry Pi with GPS Receiver



From bash we can list usb devices:
$ lsusb
USB devices list

In second line is GPS receiver (U-Blox AG)


Next step, we must install python module for decoding NMEA messages:
$ sudo pip install pynmea2

And we write first code:
import io
import serial
import pynmea2

GPS_RECIVER_PORT = '/dev/ttyACM0'

ser = serial.Serial(GPS_RECIVER_PORT, 9600, timeout=5.0)
sio = io.TextIOWrapper(io.BufferedRWPair(ser, ser))

while 1:
    try:
        line = sio.readline()
        msg = pynmea2.parse(line)
        print(repr(msg))
     
    except serial.SerialException as e:
        print('Device error: {}'.format(e))
        break
We must set valid GPS reciver port definied in variable GPS_RECIVER_PORT

If we have done everything right after running the application we should see NMEA messages. To get the correct GPS position we have to wait a few minutes.

Examples messages NMEA

We can read position from GGA and GLL NMEA messages and velocity from VTG message.

Next step we will print only position and last speed:

import io
import serial
import pynmea2

GPS_RECIVER_PORT = '/dev/ttyACM0'

global lastVTG

ser = serial.Serial(GPS_RECIVER_PORT, 9600, timeout=5.0)
sio = io.TextIOWrapper(io.BufferedRWPair(ser, ser))

while 1:
    try:
        line = sio.readline()
        msg = pynmea2.parse(line)
       
        if isinstance(msg, pynmea2.types.talker.VTG):
           lastVTG = msg

        if isinstance(msg, pynmea2.types.talker.GGA):
           print('lat={}, lng={}, speed={}, alt={}'.format(msg.latitude, msg.longitude, lastVTG.spd_over_grnd_kmph, msg.altitude))
     
    except serial.SerialException as e:
        print('Device error: {}'.format(e))
        break

We can track device location on the map at https://pilnuj.com/
Api is described on the site https://pilnuj.com/app/swagger-ui.html, generally we must send one POST with JSON data:
import io
import serial
import pynmea2
import requests

GPS_RECIVER_PORT = '/dev/ttyACM0'
DEVICE_UID = '123456789012345'
GEOLOCATION_SERVER_API = 'https://pilnuj.com/app/open-api/position'

global lastVTG


def sendPosition(msg):
   if lastVTG:
      response = requests.post(GEOLOCATION_SERVER_API, json={"imei": DEVICE_UID, "lat" : msg.latitude, "lng" : msg.longitude, "velocity" : lastVTG.spd_over_grnd_kmph, "altitude" : msg.altitude})


ser = serial.Serial(GPS_RECIVER_PORT, 9600, timeout=5.0)
sio = io.TextIOWrapper(io.BufferedRWPair(ser, ser))

while 1:
    try:
        line = sio.readline()
        msg = pynmea2.parse(line)
       
        if isinstance(msg, pynmea2.types.talker.VTG):
           lastVTG = msg

        if isinstance(msg, pynmea2.types.talker.GGA):
           sendPosition(msg)
     
    except serial.SerialException as e:
        print('Device error: {}'.format(e))
        break

Important note, we must set random value DEVICE_UID, this value we must write as IMEI when you added new device on https://pilnuj.com

Adding device

sources:
https://gitlab.com/sebastian_dzk/letsmakearobot


links:
https://github.com/Knio/pynmea2
https://en.wikipedia.org/wiki/NMEA_0183
https://www.gpsinformation.org/dale/nmea.htm
https://pilnuj.com/



Saturday 30 September 2017

Stepper motors


Introduction

For some applications, stepper motors are useful. precise alignment of the motor axis in the preset position. The problem with control is that the control signals are sent hundreds, thousands of times per second.

Devices

In my test I use chap driver build on ULN2003 chip and stepper motor  28BYJ-48

Cheap ULN2003 stepper motor driver


Arduino Nano connection with two ULN2003 drivers and 28BYJ-48 motors

Solution


In my idea, control is separated by the following:
- main control app is write in Java and working on RaPi. App use library to communication with Arduino and sending high level intruction: turn left 20 steps, turn right 100 steps, turn on motor pernamently, stop motor, etc.
- on Arduino is installed app, receiveing command from USB port (from RaPi) encode and send appropriate signals to  selected motors.
- app can control unlimited Arduino modules, and control max 3 motors per Arduino (limit is the number of arduino outputs)

Idea of stepper motor control

How to install


Download Arduino sources from stepper_motor_ctrl_by_serial.ino, use Arduino IDE and compile and install on Arduino.

Download jar library stepper-motor-connector-4j-0.1.0.jar and add to your Java project.

Full project sources are available on GitLab https://github.com/SulacoSoft/stepper-motor-connector-4j.

Available functions


Init motor on port COM7 (Windows USB port name, on linux example name is ttyUSB7) and define stepper motor controler pins on Arduino 6, 7, 8, 9:
StepperMotor motor = StepperMotorFabric.create("COM7", 6, 7, 8, 9);

Rotate 2048 steps to left:
motor.rotateLeftSteps(2048);

Waiting to estimated time end operation (rotateLeftSteps or rotateRightSteps):
while (!motor.isReady())
    Thread.sleep(10L);

Turn right 512 steps:
motor.rotateRightSteps(512);

Turn pernamently rotate right:
motor.rotateRightOn();

Turn pernamently rotate left:
motor.rotateLeftOn();

Stop motor (when motor is run rotateLeftOn or rotateRightOn):
motor.rotateOff();

Disconnect motor (releas pins and motor instantion):
StepperMotorFabric.disconnect(motor);

We can change delay time between motor steps in microseconds. This parameter change delay time on all connected motors to selected Arduino board:
motor.setDelay(1200);

We can connect several motors:
StepperMotor motorA = StepperMotorFabric.create("COM7", 2, 3, 4, 5);
StepperMotor motorB = StepperMotorFabric.create("COM7", 6, 7, 8, 9);

Completly example


Full Java example:

import com.sulacosoft.robots.steppermotor.StepperMotor;
import com.sulacosoft.robots.steppermotor.StepperMotorException;
import com.sulacosoft.robots.steppermotor.StepperMotorFabric;

public class Main {
  public static void main(String[] args) throws StepperMotorException {
  StepperMotor motor = StepperMotorFabric.create("COM7", 2, 3, 4, 5);
    try {
      motor.rotateRightSteps(4096);
              while (!motor.isReady())
        Thread.sleep(10L);
              motor.rotateLeftOn();
      Thread.sleep(2000);
      motor.rotateOff();
         } catch (InterruptedException e) {
      e.printStackTrace();
    } finally {
      StepperMotorFabric.disconnect(motor);
    }
  }
}



links:
https://github.com/SulacoSoft/stepper-motor-connector-4j
https://www.codeproject.com/Tips/801262/Sending-and-receiving-strings-from-COM-port-via-jS
https://github.com/scream3r/java-simple-serial-connector
https://github.com/nyholku/purejavacomm
http://kishor15389.blogspot.hk/2011/05/how-to-install-java-communications.html
https://code.google.com/archive/p/java-simple-serial-connector/
http://search.maven.org/#artifactdetails%7Corg.scream3r%7Cjssc%7C2.8.0%7Cjar
http://www.instructables.com/id/BYJ48-Stepper-Motor/
http://42bots.com/tutorials/28byj-48-stepper-motor-with-uln2003-driver-and-arduino-uno/

Sunday 27 August 2017

Firmata - Raspberry Pi (part 2b, access from Java)

Introdution


We have prepared earlier Arduino with an installed library Firmata (post how to prepare Arudino with firmata - link). Now we connect from the Raspberry to the Arduino with Firmata. We have the possibility to connect from most programming languages. In my opinion, best choice is Java.



We need

  • Raspberry Pi with installed ArchLinux
  • Arduino(Mega) with installed Firmata library (Firmata - Arduino)
The ArduinoMega connected to the Raspberry Pi



Installation Java Development Kit


refresh of all package list:
# pacman -Syy
 install open JDK:
# pacman -S jdk8-openjdk
 test jvm:
# java -version
test java compiler:
# javac -version
 you should see something similar to:


Java firmata library


There are many implementations firmata on java. My choice fell on firmata4j.

Writing Arduino equivalent "Hello world" application


We have two basic software way to build java application:
  • connect Arduino to your PC computer (not Raspberry), write appliction, compile, tests and move copiled binary to Raspberry
  • connect Arduino to Raspberry, write application, compile, test and run on Raspberry
I'm going show the example by first scenario. I use on my workstation PC:
  • JDK - Java Development Kit, Oracle or Open Source distirbution, it does not matter.
  • gradle - open source build automation system 
  • Eclipse - IDE for Java development
Now we write simple application that controls LED13 on Arduino.

Localization LED13


Full Java code of this app is below:

import java.io.IOException;
import org.firmata4j.IODevice;
import org.firmata4j.Pin;
import org.firmata4j.Pin.Mode;
import org.firmata4j.firmata.FirmataDevice;

public class Main {

  private static final int PIN_NUMBER = 13;
  private static final long DELAY_MILISECONDS = 1000;
  private static final long LOOP = 10;

  public static void main(String[] args) throws IOException, InterruptedException {
    IODevice device = new FirmataDevice("COM3"); // construct the Firmata device instance using the name of a port
    device.start(); // initiate communication to the device
    device.ensureInitializationIsDone(); // wait for initialization is done
    Pin pin = device.getPin(PIN_NUMBER);
    pin.setMode(Mode.PWM);
   
    for (int i = 0; i < LOOP; i++) {
      Thread.sleep(DELAY_MILISECONDS);
      pin.setValue(1); // on led
      Thread.sleep(DELAY_MILISECONDS);
      pin.setValue(0); // off led
    }
    
device.stop(); // stop communication to the device
 }
}

Full code with gradle configuration file can you download from link.
clone project (or download from page):
# git clone https://github.com/SulacoSoft/robotics-examples-firmata-blink-led13.git
create Eclipse configuration files:
# gradle eclipse
 run Eclipse and import project, click right button on Project Explorer, select Import > Import... > Existing Projects into Workspace.

Change port on line:
IODevice device = new FirmataDevice("COM3");
If you run on windows, set valid port definied as: COM1, COM2, COM3, ...

If you run app on linux, you must definied port have style: /dev/ttyUSB0, /dev/ttyUSB1, /dev/ttyUSB2, ...

Remember, port on your workstation is different than a port on Raspberry. When you move binary from workstation to Rasberry, you must change port number. Best practices is to store configuration in a external file.


links:


Sunday 22 February 2015

Power supply

Introduction

We need a power source for robot, the cheapest and easiest-to-use source is Pb battery for UPS and electonic devices. The battery is unfortunately very hight weight, this is important disadvantage. Typical PB battery 12V/5Ah weights 2kg.

Advantages:
- low cost
- simple and cheap battery charger
- simple construction (we don't need many batteries installed in battery basket)
- high output current

Disadvantages:
- very high weight  

We need:

  • Pb battery, in my construction 12V/5Ah
  • XL6009 DC/DC converter for computers line (Raspberry and Arduino); output 5V/3-4A; spec
  • DC3 5V0 DC/DC converter for power line (Servos, DC motors); output regulated 1,25-35V/2A
  • Watt meter, optional for easy measurement power consumption
  • some devices to connect, in my test connection Raspberry Pi with camera and Arduino


Battery 12V/5Ah dedicated to UPS.


Watt metter for easy measurement power consumption. This's an optional element.


XL6009 DC/DC converter for low power line.

DC3 5V0 DC/DC converter for hight power line.

Connections

We need two power line. Line of computers can not be affected by the heavily loaded servo or motors. Therefore, I used two DC/DC converters.

Before connecting the Raspberry to XL6009, set the correct voltage using voltometer and resistant load device. Raspberry will be damaged if you do not adjust the valid voltage.

 Connection diagram.



Real connections (without battery charger).

Power consumption

I measuremend power consumption devices:
  • XL6009 DC/DC (converters have efficienty 75-98%)
  • DC3 5V0 DC/DC (converters have efficienty 75-98%)
  • not load RaspberryPi with ArchLinux
  • RaspberryPi Camera
  • WiFi dongle
  • ArduinoMega
Average power consumption is 2,3 Watts, theoretical battery can work 28 hours. In real construction we will add other devices, 28 hours is "standby time".

Saturday 11 October 2014

PyFirmata summary


For using a firmata (Respberry <-> Arduino) you must install it on:


Statement of connection types:

device/connection type get_pin(...) string available values
relay shield d:pin_no:o 0 and 1
DC motor d:pin_no:p 0.0 - 1.0
servo d:pin_no:s 0 - 255
analog input (*) a:pin_no:i 0.0 - 1.0

(*) you must start reading analog input:
from pyfirmata.util import Iterator
...
board = ArduinoMega('/dev/ttyUSB0')
iterator = Iterator(board)
iterator.start()
...

Example use servo:
from pyfirmata import ArduinoMega
board = ArduinoMega('/dev/ttyUSB0') # Arduino usb port
servo = board.get_pin('d:2:s')      # pin PWM no 2
servo.write(50)                     # set servo position 0-255

Temperature sensor LM35


We need:

Sensor LM35:



Connections schema:


We can connect LM35 to 5V or 3.3V, it doesn't matter.


Photo from my LM35 connections:



Example python app lm35_test.py:
from pyfirmata import ArduinoMega
from pyfirmata.util import Iterator
import time

board = ArduinoMega('/dev/ttyUSB0') # connect to arduino usb port

iterator = Iterator(board) # start reading analog input
iterator.start()

pinTemp = board.get_pin('a:0:i') # set valid in analog pin

while True:
    voltage = pinTemp.read() # read voltage input
    if voltage is not None: # first read after startup is somtimes None
        temp = 5.0*100*voltage # convert voltage to temperature
        print "{0} Celsius".format(temp)
        time.sleep(1) # 1 second waiting 


Run python environment (see Firmata - Raspberry Pi (part 2)), for example:
# cd robot/python_firmata_test/
# source bin/activate
and run app:
# python2.7 lm35_test.py
Screenshoot form app:


LM35 is theoretically appropriately calibrated but in my opinion, given the temperature is overestimated by about 2-4 degrees CelsiusI had a reference (room thermometer;) ) thermometer.


links:
http://raspberrypi-aa.github.io/session3/firmata.html
http://www.ladyada.net/learn/sensors/temp36.html
http://www.ti.com.cn/cn/lit/ds/symlink/lm35.pdf

Sunday 5 October 2014

Relay shield control

We need:

Relay shield:

Connections schema:


Photo from my relay shield connections:




Simple app to blinking relay connect to 22 pin:
from pyfirmata import ArduinoMega, time
board = ArduinoMega('/dev/ttyUSB0')
servoA = board.get_pin('d:22:o')

while True:
   servoA.write(1) 
   time.sleep(1)
   servoA.write(0) 
   time.sleep(1)


Command line completely app relay_example.py:
from pyfirmata import ArduinoMega, time
board = ArduinoMega('/dev/ttyUSB0')
firstPin = 22 # number first pin, app use 8 pins

__copyright__ = "Copyright 2014, http://letsmakearobot.blogspot.com/"
__version__ = "0.1.0"
__license__ = "GPL"
__email__ = "sebastian.dziak@gmail.com"

def info():
    print "------------------------------------------------"
    print "Command parameters:"
    print "  1-8 - relay no"
    print "  0-1 - relay status (0 - off, 1 - on)"
    print "  ...and exit from app: exit"
    print 
    print "Examples:"
    print "  2 1 #set on relay no 2"
    print "  2 0 #set off relay no 2"
    print "  5 1 #set off realy no 5 "
    print "  exit"
    print "------------------------------------------------"

def validate(position):
   if not position is None and (float(position)<0 or float(position)>255):
      return "Invalid parameter!"

info()

pins = []
for n in range (0, 8):
   pinNo = firstPin + n
   pins.append( board.get_pin('d:'+str(pinNo)+':o') )

while True:
   cmdLine = raw_input('Relay_no(1-8) set_status(0-1):')
   if cmdLine == 'exit': break 
   args = cmdLine.split()
   pins[int(args[0])-1].write(int(args[1]))

print "goodbye"

Run python environment (see Firmata - Raspberry Pi (part 2)), for example:

# cd robot/python_firmata_test/
# source bin/activate

and run app:
# python2.7 relay_example.py


Screenshoot form app: