jacekgrab
Posts: 3
Joined: Thu Sep 21, 2017 10:32 am

Laser dust sensor

Thu Sep 21, 2017 10:48 am

Hello
i have dust sensor SDS011 + USB adapter
https://pl.aliexpress.com/store/product ... 05049.html
I connect the sensor to raspberry pi, basic to read a sensor I use command:

sudo od --endian=big -x -N10 < /dev/ttyUSB0

so it is giving me for example:
0000000 aac0 8c00 9400 bcf9 d5ab

every packet of data begins "aac0" (that is correct according to datasheet) and rest of the data are converted to useful values (in bash script), basically everything work ok (for graphic representation of data I use RRDtool). But I want compare data from SDS011 sensor with similar sensor PMS7003. I don't have any USB adapter so I connected PMS7003 to raspberry pi pins (Vcc 5V, GND, RX TX).
In PMS7003 datasheet I see that start of the packet of data should be "424d". First I tryed this command:

sudo od –endian=big -x -N10 < /dev/serial0

but this give me that kind of data:
3500 8200 0a54 008c 000a (first try)
8100 9f00 0a78 0094 000a (second try)
2900 6400 2900 6400 2900 (third try)
I don't see beginning the data packet "424d"

I tried Python script:

import serial
from time import gmtime, strftime
port = serial.Serial("/dev/serial0", baudrate=9600, timeout=1.5)
data = port.read(32);
PM01 = str(ord(data[5])*256+ord(data[6]))
PM25 = str(ord(data[7])*256+ord(data[8]))
PM10 = str(ord(data[9])*256+ord(data[10]))
print(PM01)
print(PM25)
print(PM10)

but this also give me strange no real value. Why data packet never start from "424d"?
Attachments
Capture4.JPG
Capture4.JPG (84.86 KiB) Viewed 4058 times

klricks
Posts: 5922
Joined: Sat Jan 12, 2013 3:01 am
Location: Grants Pass, OR, USA
Contact: Website

Re: Laser dust sensor

Thu Sep 21, 2017 12:45 pm

Did you re configure the serial port so that is is a standard serial port and not a Linux console?

viewtopic.php?f=44&t=190709#p1206913
Unless specified otherwise my response is based on the latest and fully updated Raspbian Stretch w/ Desktop OS.

scotty101
Posts: 3265
Joined: Fri Jun 08, 2012 6:03 pm

Re: Laser dust sensor

Thu Sep 21, 2017 12:48 pm

Try using something like Minicom to look at the data coming in to the serial port continuously and look in that data for the '0x42 0x4d' prefix.
I suspect that the code you have written is picking up the data mid way through the 32 bytes.
You might have to read the data byte by byte until you receive two successive bytes containing 0x42 0x4d and then start reading in the rest of the payload.
Electronic and Computer Engineer
Pi Interests: Home Automation, IOT, Python and Tkinter

jacekgrab
Posts: 3
Joined: Thu Sep 21, 2017 10:32 am

Re: Laser dust sensor

Thu Sep 21, 2017 6:54 pm

Yes I have correctly configure UART, but I notice that 424d appears in the data packet, what is the easiest way to "catch" this starting point of the data?
Attachments
Przechwytywanie.JPG
Przechwytywanie.JPG (99.03 KiB) Viewed 4002 times

Hoagie
Posts: 119
Joined: Sun Sep 23, 2012 7:19 pm

Re: Laser dust sensor

Fri Sep 22, 2017 6:48 pm

If it just pumps the packets out continuously, you could read twice the length and then throw out all the data up to the 424d. The remainder will be at least one full reading.

jacekgrab
Posts: 3
Joined: Thu Sep 21, 2017 10:32 am

Re: Laser dust sensor

Fri Sep 22, 2017 8:08 pm

You have some example how to do this?
something like this?
if ord(data[0]) == 66 and ord(data[1])==77:

Hoagie
Posts: 119
Joined: Sun Sep 23, 2012 7:19 pm

Re: Laser dust sensor

Sun Sep 24, 2017 9:31 am

I'm not a python person, but something like a loop through the data where a variable (x for instance) is the index. If the data at x t x is 42 and the data at (x+1) is 4d (there must be some notation for hex in python) then you know the start of the data. You can read the values you need by adding the offsets to x. Make sure you declare the variables to hold your readings before entering the loop, otherwise you won't be able to use them after the loop.

jhardesty
Posts: 1
Joined: Wed Nov 29, 2017 10:48 pm

Re: Laser dust sensor

Wed Nov 29, 2017 10:54 pm

Have you been able to get this working. I Have a RP3 and a PMS5003. I have not been able to get any meaningful data from the serial port. You seem to have gotten farther than me. Would you mind sharing the wiring you have used and where you have gotten.

this is as far as I have gotten

[email protected]:~ $ sudo od --endian=big -x -N64 < /dev/serial0
0000000
[email protected]:~ $ sudo od --endian=big -x -N64 < /dev/serial0
0000000
[email protected]:~ $ sudo od --endian=big -x -N64 < /dev/serial0
0000000
[email protected]:~ $ sudo od --endian=big -x -N64 < /dev/serial0
0000000 424d 001c 0006 0009 0009 0006 0009 0009
0000020 059a 0194 002e 0002 0001 0000 9300 02d3
0000040
[email protected]:~ $

Any help would be greatly appreciated.

jeffrey

Massi
Posts: 1687
Joined: Fri May 02, 2014 1:52 pm
Location: Italy

Re: Laser dust sensor

Thu Nov 30, 2017 9:43 am

well, nice to see this topic :)
ive just bought a plantower PMS-A003 from china, so IF (and I say IF) it will arrive, i'll have to manage it.
as of today, i've not found any datasheet lol.
Do you have any?

Massi
Posts: 1687
Joined: Fri May 02, 2014 1:52 pm
Location: Italy

Re: Laser dust sensor

Sun Dec 10, 2017 5:01 pm

eventually, i got my sensor :)
i started writing some code, see if this is useful for you..

Code: Select all

import serial
import time
import pigpio
import struct

class PMSA003: 
	#constants
	PMS_FRAME_LENGTH = 0
	PMS_PM1_0 = 1
	PMS_PM2_5 = 2
	PMS_PM10_0 = 3
	PMS_PM1_0_ATM = 4
	PMS_PM2_5_ATM = 5
	PMS_PM10_0_ATM = 6
	PMS_PCNT_0_3 = 7
	PMS_PCNT_0_5 = 8
	PMS_PCNT_1_0 = 9
	PMS_PCNT_2_5 = 10
	PMS_PCNT_5_0 = 11
	PMS_PCNT_10_0 = 12
	PMS_VERSION = 13
	PMS_ERROR = 14
	PMS_CHECKSUM = 15
	PMS_WAIT_TIME = 30 #time to wait when sensor exits sleep mode
	
	def __init__(self, resetPin = 17, setPin = 18): 
		#defining GPIO for RESET line and SET line
		self.resetPin = resetPin
		self.setPin = setPin
		#opening serial port
		self.device = serial.Serial(port		= '/dev/ttyAMA0',
									baudrate	= 9600,
									stopbits	= serial.STOPBITS_ONE,
									parity		= serial.PARITY_NONE,
									bytesize	= serial.EIGHTBITS,
									timeout		= 5
									)
		if not self.device.isOpen(): raise IOError("Unable to open serial") 
		#open connection to pigpio
		self.pi = pigpio.pi()
		if not self.pi.connected: raise IOError("Unable to connect to PiGPIOd")
 
	def getLastReading(self):
		#get last sensor reading
		#flushing input buffer if it's bigger than one reading because i want last reading
		if self.device.in_waiting > 32:
			self.device.reset_input_buffer()

		readEnd = False
		while readEnd is not True:
			while True:
				#checking start frame: 0x42 and 0x4D
				firstByte = self.device.read(1)
				if len(firstByte) < 1 or ord(firstByte) != 0x42: break
				secondByte = self.device.read(1)
				if len(secondByte) < 1 or ord(secondByte) != 0x4D: break

				#reading all the rest!
				readBuffer = self.device.read(30)
				if len(readBuffer) < 30: break

				#decoding data
				data = struct.unpack('!HHHHHHHHHHHHHBBH', readBuffer)

				#checking checksum
				checksum = 0x42 + 0x4D
				for c in readBuffer[0:28]: checksum += c
				if checksum != data[self.PMS_CHECKSUM]:
					print("Incorrect check code: received : {:04x}, calculated : {:04x}".format(data[self.PMS_CHECKSUM],checksum))
				
				#parsing sensor data
				#0-1: frame length
				print("Frame length: {}".format(data[self.PMS_FRAME_LENGTH]))
				
				#2-3: pm1
				print("pm1: {}".format(data[self.PMS_PM1_0]))
				
				#4-5: pm2.5
				print("pm2.5: {}".format(data[self.PMS_PM2_5]))
				
				#6-7: pm10
				print("pm10: {}".format(data[self.PMS_PM10_0]))
				
				#8-9: pm1 atm
				print("pm1 atm: {}".format(data[self.PMS_PM1_0_ATM]))

				#10-11: pm2.5 atm
				print("pm2.5 atm: {}".format(data[self.PMS_PM2_5_ATM]))

				#12-13: pm10 atm
				print("pm10 atm: {}".format(data[self.PMS_PM10_0_ATM]))

				#14-15: pm0.3 count
				print("pm0.3 count: {}".format(data[self.PMS_PCNT_0_3]))

				#16-17: pm0.5 count
				print("pm0.5 count: {}".format(data[self.PMS_PCNT_0_5]))

				#18-19: pm1 count
				print("pm1 count: {}".format(data[self.PMS_PCNT_1_0]))

				#20-21: pm2.5 count
				print("pm2.5 count: {}".format(data[self.PMS_PCNT_2_5]))

				#22-23: pm5 count
				print("pm5 count: {}".format(data[self.PMS_PCNT_5_0]))

				#24-25: pm10 count
				print("pm10 count: {}".format(data[self.PMS_PCNT_10_0]))

				#26: Version
				print("Version: {}".format(data[self.PMS_VERSION]))

				#27: Error
				print("Error: {}".format(data[self.PMS_ERROR]))

				#28-29: checksum
				print("Checksum: {}".format(data[self.PMS_CHECKSUM]))

				readEnd = True
				break
			
	def setSleepMode (self, sleepMode):
		#set sensor sleep mode - SETPIN
		if sleepMode is True:
			self.pi.write(self.setPin, 0)
		else:
			self.pi.write(self.setPin, 1)
			#need to wait some time to get proper readings
			time.sleep(self.PMS_WAIT_TIME)
	
	def setStandbyMode (self, standbyMode):
		#set sensor standby mode - SERIAL
		#command is built as: 0x42 0x4d 0xe4 0x00 0x00/01 checksum
		#standbyMode TRUE sets standby
		if standbyMode is True:
			checksum = 0x42+0x4D+0xE4+0x00+0x00
			serCmd = struct.pack('!BBBBBH',0x42,0x4D,0xE4,0x00,0x00,checksum)
			self.device.write(serCmd)
			self.device.reset_input_buffer()
			#checking response: 42 4D 00 04 E4 00 chckH chckL
			response = self.device.read(8)
			if len(response) < 8: print("Response error")
			expected = bytes([0x42,0x4D,0x00,0x04,0xE4,0x00,0x01,0x77])
			if(response != expected):
				print("Wrong response received: {} - expected {}".format(response,expected))
			else:
				print("Standby set")
		else:
			checksum = 0x42+0x4D+0xE4+0x00+0x01
			serCmd = struct.pack('!BBBBBH',0x42,0x4D,0xE4,0x00,0x01,checksum)
			self.device.write(serCmd)
			self.device.reset_input_buffer()
			#no answer expected
			#need to wait some time to get proper readings
			time.sleep(self.PMS_WAIT_TIME)
			print("Standby removed")
		
	def setActiveMode (self, active):
		#set sensor state - SERIAL
		#command is built as: 0x42 0x4d 0xe1 0x00 0x00/01 checksum
		#active TRUE sets active mode
		if active is True:
			checksum = 0x42+0x4D+0xE1+0x00+0x01
			serCmd = struct.pack('!BBBBBH',0x42,0x4D,0xE1,0x00,0x01,checksum)
			self.device.write(serCmd)
			self.device.reset_input_buffer()
			#no answer expected
			print("Active mode set")
		else:
			checksum = 0x42+0x4D+0xE1+0x00+0x00
			serCmd = struct.pack('!BBBBBH',0x42,0x4D,0xE1,0x00,0x00,checksum)
			self.device.write(serCmd)
			self.device.reset_input_buffer()
			#checking response: 42 4D 00 04 E1 00 1 74
			response = self.device.read(8)
			if len(response) < 8: print("Response error")
			expected = bytes([0x42,0x4D,0x00,0x04,0xE1,0x00,0x01,0x74])
			if(response != expected):
				print("Wrong response received: {} - expected {}".format(response,expected))
			else:
				print("Passive mode set")
			#in passive mode i expect to have single readings, so i'm trashing all the input buffer
			self.device.reset_input_buffer()
	
	def getSingleReading(self):
		#trigger single reading on passive mode
		checksum = 0x42+0x4D+0xe2+0x00+0x00
		serCmd = struct.pack('!BBBBBH',0x42,0x4D,0xE2,0x00,0x00,checksum)
		self.device.write(serCmd)
		self.getLastReading()
	
	def reset (self):
		#reset sensor - RESETPIN
		self.pi.write(self.resetPin, 0)
		time.sleep(0.5)
		self.pi.write(self.resetPin, 1)
	
	def close(self): 
		''' Close the serial port.'''
		self.device.close()
		self.pi.stop()

if __name__ == "__main__":
			
	sensor = PMSA003()
	
	#print("Setting passive")
	#sensor.setActiveMode(False)
	#time.sleep(1)
	print("Setting active")
	sensor.setActiveMode(True)	
	time.sleep(1)
	#print("Setting standby")
	#sensor.setStandbyMode(True)
	#time.sleep(1)
	#print("Removing standby")
	#sensor.setStandbyMode(False)
	#time.sleep(1)
	
	sensor.getLastReading()
	time.sleep(1)
	sensor.getLastReading()

	#sensor.getSingleReading()
	#time.sleep(1)
	#sensor.getSingleReading()
	
	sensor.close()

dinglydang
Posts: 3
Joined: Mon Aug 06, 2018 6:01 pm

Re: Laser dust sensor

Mon Aug 06, 2018 6:44 pm

Could I ask anyone to update this thread on whether or not the code posted last is working? I'm a complete newbie with serial communication (which I find rather painful and odd to use). So I was thinking about getting data from my arduino onto my RPi, but I'd rather keep all my sensors on one board (RPi).

So does the above python code work with the pms5003?

Thank you.

Massi
Posts: 1687
Joined: Fri May 02, 2014 1:52 pm
Location: Italy

Re: Laser dust sensor

Tue Aug 07, 2018 6:45 am

dinglydang wrote:
Mon Aug 06, 2018 6:44 pm
Could I ask anyone to update this thread on whether or not the code posted last is working? I'm a complete newbie with serial communication (which I find rather painful and odd to use). So I was thinking about getting data from my arduino onto my RPi, but I'd rather keep all my sensors on one board (RPi).
So does the above python code work with the pms5003?
and why don't you try it?

Return to “Automation, sensing and robotics”