Konuyu Oyla:
  • Derecelendirme: 0/5 - 0 oy
  • 1
  • 2
  • 3
  • 4
  • 5
3D lidar veri analizi için PPL veya Thread
#1
Merhabalar 

Delphi ile haritalama ve otonom robot tasarımı yapmaktayım. Projede ilk olarak 2D lidar kullanmaktaydım. bu lidardan gelen veriyi Thread kullanarak işlemekteydim. 2D lidar kullanırken Thread' ler kullanarak yaptığım işlemler; engel analizi, boşluk analizi, rota takibi ve tabiki vazgeçilmez olan işlemlerin grafiksel olarak gösterimi. Robotun çalışma hızı ile bu işlemler kılpayı bir zamanda olabilmekte idi. 

Projenin gelişimi esnasında 3D lidar' a geçme zorunluğu doğdu kullandığım lidarı [/url][url=https://velodynelidar.com/products/puck/]https://velodynelidar.com/products/puck/ bu linkte inceleyebilirsiniz. Benim sorum şu lidardan saniyede UPD üzerinden 300.000 pointlik(x,y,z) veri gelmektedir. Ürünün kulanım kılavuzuna göre her gelen 1206 bytelık verinin analizi aşağıdaki kod örneğindeki gibidir. Bu gelen verinin tamamını işlemek istediğimde aşırı CPU kullanımı olmakta ve 300.000 noktanın tamamını analiz edememekteyim. Bu konuda PPL veya Thread kullanımı açısından önerileriniz nelerdir ? 

procedure VLP16_DataBlock_Olustur(Gelen_Veri : TIdBytes);
var
 I: Integer;
 J: Integer;
 Nokta_Mesafesi : Float32;
 Lazer_Yansimasi : Byte;
 Sayac: Integer;
begin
 SetLength(VLP16_Data_Blok_Veri,0);
 if (Length(Gelen_Veri) = 1206) then
 begin
     for I := 0 to 11 do
     begin
         SetLength(VLP16_Data_Blok_Veri,Length(VLP16_Data_Blok_Veri)+1);
         with VLP16_Data_Blok_Veri[High(VLP16_Data_Blok_Veri)] do
         begin
           Data_Block_No := I;
           Flag_Low      := Gelen_Veri[I*100+0];
           Flag_High     := Gelen_Veri[I*100+1];
           Azimuth       := (Gelen_Veri[I*100+3]*$FF+Gelen_Veri[I*100+2]) / 100.0;
           IMU_VLP16     := IMU;
           Time_Stamp    := (Gelen_Veri[1203]*$FFFFFF + Gelen_Veri[1202]*$FFFF + Gelen_Veri[1201]*$FF + Gelen_Veri[1200]) / 1000000;
           for J := 0 to 15 do
           begin
             Channel_Data[J].Distance       := ((Gelen_Veri[I*100+J*3+5]*$FF+Gelen_Veri[I*100+J*3+4]) * 2.0)/1000.0;
             Channel_Data[J].Reflectivity   := Gelen_Veri[I*100+J*3+6];
             Channel_Data[J].Vertical_Angel := Dikey_Aci[J];
             Nokta_Mesafesi  := Channel_Data[J].Distance;
             Lazer_Yansimasi := Channel_Data[J].Reflectivity;
             if (Nokta_Mesafesi > 0) and (Lazer_Yansimasi > 0) then
             begin
               Anlik_Verileri_Ciz(Channel_Data[J].Distance, Azimuth, Channel_Data[J].Vertical_Angel, IMU_VLP16, Channel_Data[J].Reflectivity);
             end;
           end;
         end;

   end;
   SetLength(Gelen_Veri_VLP16,0);
 end;
end;

procedure Anlik_Verileri_Ciz(Distance,Azimuth : Float32;  Vertical_Angel : SmallInt; IMU_VLP16 : TIMU; Reflectivity : Byte);
var
Azimuth_Radyan : Float32;
Vertical_Angel_Radyan : Float32;
begin
   Azimuth_Radyan          := DegToRad(Azimuth);
   Vertical_Angel_Radyan   := DegToRad(Vertical_Angel);

   Tampon_Nokta.X := Robot_Pozisyonu.X + RoundTo(Distance*Cos(DegToRad(Vertical_Angel))*Sin(DegToRad(Azimuth+IMU_VLP16.Yaw)),-2);
   Tampon_Nokta.Y := Robot_Pozisyonu.Y + RoundTo(Distance*Cos(DegToRad(Vertical_Angel))*Cos(DegToRad(Azimuth+IMU_VLP16.Yaw)),-2);
   Tampon_Nokta.Z := Robot_Pozisyonu.Z + RoundTo(Distance*Sin(DegToRad(Vertical_Angel)),-2);

   SetLength(Tampon_Nokta_Bulutu,Length(Tampon_Nokta_Bulutu)+1);
   Tampon_Nokta_Bulutu[High(Tampon_Nokta_Bulutu)].Nokta_Bulutu := Tampon_Nokta;
   Tampon_Nokta_Bulutu[High(Tampon_Nokta_Bulutu)].Reflectivity := Reflectivity;
   Form_Ana.Noktalar.Positions.Add(Tampon_Nokta);

//  Form_Ana.Noktalar.Colors.Add(1,1,1,1);
//  Form_Ana.Noktalar.Size := 2;
end;
Cevapla
#2
Hocam oldukça ilgi çekici bir alanda çalışıyorsunuz. 3B lazer haritalayacıları da bayağı gelişmiş, sayenizde öğrenmiş olduk.
Saniyede 300.000 nokta bilgi akışını idare etmekten bahsediyorsanız, PPL ve thread kararı ile birlikte GPU Computing with OpenCL https://www.youtube.com/watch?v=c4BigmnQhB0  ve High Performance Computing in Delphi with MtxVec https://www.youtube.com/watch?v=g8CSBthCCSM kullanmayı da düşünebilirsiniz.
saygılar mustafa ֍zgün 
Cevapla
#3
Hem meraktan hem de çözüm için kaynak olacağını değerlendirdiğimden soruyorum;

* Gelen 1206 byte(s) değer içeren bir nokta ile başlandığında, saniyede 300 veri bloğu x 1206 byte(s) = yaklaşık 350 KB veri demek oluyor.
* Bu her değerin Form_Ana.Noktalar.Positions.Add ile eklediğinizde, aynı class func altında eklemeyi takiben değerin görsel haline gelmesi için yapılan işlemlerden dolayı yaşanan gecikme vs. hesaba katarak geçen süreyi en kısa ve en uzun zaman alan haliyle hesapladınız mı ? Bunu bir memoya NoktaSıraNo,  Veri giriş Tickcount, işlem sonu   TickCount, FARK milisec şeklinde hesaplama imkanınız var.

* Bunu strateji belirlemede temel kurmak için soruyorum; bir thread içinde üretilecek iş sayısı saniyede kaç noktayı üzerine alabilir onu hesaplayıp, 300 verinin hiçbirini kaçırmadan en az kaç kulvardan iş yürütülmesi gereğini değerlendirerek, yük dengeleme için gerekli bilgi edinilmesi gerekmektedir.

* Bunu hesapladığınızda kaçırmamak için paralel işlem sayısını hesaplayabilirsiniz. Zaten paralel işlemler oluşturulunca işlemci gücünü dengelemek için işlemci çekirdek seçimi işletim sisteminde olacağından basit bir kaç thread ile çözüm önünüzde de olabilir.

* Thread ve işletim sistemleri denetimi konusundaki deneyimi için ek olarak @Tuğrul HELVACI'yı da konuyu etiketliyorum.
Saygılarımla
Muharrem ARMAN

guplouajuixjzfm15eqb.gif
Cevapla
#4
Uzmanı değilim ve yüzleştiğiniz sorunlarla karşı karşıya kalmadım ama gördüğüm kadarıyla SetLength(Gelen_Veri_VLP16... ve Anlik_Verileri_Ciz kullanırken çok zaman kaybediyorsunuz. Hatta Time_Stamp ve Channel_Data[J].Distance hesaplarken kullandığınız formülleri de muhtemelen sadeleştirebilirsiniz. Biraz kurcalarsanız muhtemelen Pİ sayısı gibi bir çarpan da elde edebilirsiniz.

VLP16_DataBlock_Olustur fonksiyonun içinden Anlik_Verileri_Ciz fonksiyonunu bence çağırmamalısınız. Hem veri okuyup hem de çizmeye çalışırken ikisi birbirine ayak bağı olur.

Her iki metod da ortak bir veri havuzu / matris / nesne / değişken vesair artık o kullandığınız her ne ise onu kullansa daha iyi olur. Böylece Veri toplamak için bir paralel işlem, veriyi çizmek için başka bir paralel işlem başlatabilirsiniz.
YouTube Delphi Tips
"Yaşlanarak değil, yaşayarak tecrübe kazanılır. Zaman insanları değil, armutları olgunlaştırır" Peyami Safa
WWW
Cevapla
#5
(21-03-2021, Saat: 19:57)mrmarman Adlı Kullanıcıdan Alıntı: Hem meraktan hem de çözüm için kaynak olacağını değerlendirdiğimden soruyorum;

* Gelen 1206 byte(s) değer içeren bir nokta ile başlandığında, saniyede 300 veri bloğu x 1206 byte(s) = yaklaşık 350 KB veri demek oluyor.
* Bu her değerin Form_Ana.Noktalar.Positions.Add ile eklediğinizde, aynı class func altında eklemeyi takiben değerin görsel haline gelmesi için yapılan işlemlerden dolayı yaşanan gecikme vs. hesaba katarak geçen süreyi en kısa ve en uzun zaman alan haliyle hesapladınız mı ? Bunu bir memoya NoktaSıraNo,  Veri giriş Tickcount, işlem sonu   TickCount, FARK milisec şeklinde hesaplama imkanınız var.

* Bunu strateji belirlemede temel kurmak için soruyorum; bir thread içinde üretilecek iş sayısı saniyede kaç noktayı üzerine alabilir onu hesaplayıp, 300 verinin hiçbirini kaçırmadan en az kaç kulvardan iş yürütülmesi gereğini değerlendirerek, yük dengeleme için gerekli bilgi edinilmesi gerekmektedir.

* Bunu hesapladığınızda kaçırmamak için paralel işlem sayısını hesaplayabilirsiniz. Zaten paralel işlemler oluşturulunca işlemci gücünü dengelemek için işlemci çekirdek seçimi işletim sisteminde olacağından basit bir kaç thread ile çözüm önünüzde de olabilir.

* Thread ve işletim sistemleri denetimi konusundaki deneyimi için ek olarak @Tuğrul HELVACI'yı da konuyu etiketliyorum.

Merhaba 
1206 Byte içinde 2*(12(Azimuth : Yer yüzüne paralel açı)*16(3D lidar lazer sayısı)) = 384 Nokta (TVector3F tipinde) vermektedir.  Ürünün kitapçığında bu her bir paket için 1251 microsaniye olarak hesaplanmıştır.  Saniyede verdiği nokta sayısı ise 300.000 dir. Bu yüzden ikinci 1206 Byte'lık paketi işlemek için süre 384/300000 = 0,00128 sn'dir. Saniyede yaklaşık 7MB a denk gelmektedir.  Gelen 1206 Byte'ın yorumlanması için bir paralel işlem çalıştırıyorum fakat mecburen CPU'daki aşırı çalışmayı engellemek için FTasks[0].Wait(1) ile bekleme yapmak ve CPU yu rahatlatmak gerekiyor. Dediğiniz gibi diğer süre kayıplarını da eklediğimizde verinin büyük kısmını yorumlayamıyorum. 

(21-03-2021, Saat: 17:10)emozgun Adlı Kullanıcıdan Alıntı: Hocam oldukça ilgi çekici bir alanda çalışıyorsunuz. 3B lazer haritalayacıları da bayağı gelişmiş, sayenizde öğrenmiş olduk.
Saniyede 300.000 nokta bilgi akışını idare etmekten bahsediyorsanız, PPL ve thread kararı ile birlikte GPU Computing with OpenCL https://www.youtube.com/watch?v=c4BigmnQhB0  ve High Performance Computing in Delphi with MtxVec https://www.youtube.com/watch?v=g8CSBthCCSM kullanmayı da düşünebilirsiniz.

Merhaba cevap için teşekkür ederim. Projede GLscene Kullandığım için GPU tarafı baya yoğun çalışmaktatır Smile MtxVec tam olarak aradığım bir çözüm. Burdan sonra fiyatlarına bakmak gerekiyor.

(21-03-2021, Saat: 20:17)uparlayan Adlı Kullanıcıdan Alıntı: Uzmanı değilim ve yüzleştiğiniz sorunlarla karşı karşıya kalmadım ama gördüğüm kadarıyla SetLength(Gelen_Veri_VLP16... ve Anlik_Verileri_Ciz  kullanırken çok zaman kaybediyorsunuz. Hatta Time_Stamp ve Channel_Data[J].Distance hesaplarken kullandığınız formülleri de muhtemelen sadeleştirebilirsiniz. Biraz kurcalarsanız muhtemelen Pİ sayısı gibi bir çarpan da elde edebilirsiniz.

VLP16_DataBlock_Olustur fonksiyonun içinden Anlik_Verileri_Ciz fonksiyonunu bence çağırmamalısınız. Hem veri okuyup hem de çizmeye çalışırken ikisi birbirine ayak bağı olur.

Her iki metod da ortak bir veri havuzu / matris / nesne / değişken vesair artık o kullandığınız her ne ise onu kullansa daha iyi olur. Böylece Veri toplamak için bir paralel işlem, veriyi çizmek için başka bir paralel işlem başlatabilirsiniz.

"VLP16_DataBlock_Olustur fonksiyonun içinden Anlik_Verileri_Ciz fonksiyonunu bence çağırmamalısınız. Hem veri okuyup hem de çizmeye çalışırken ikisi birbirine ayak bağı olur." cümlenize katılıyorum ve bunun bir çözümünü aramaktayım. 

Teşekkür ederim
NUH EROĞLU
Elektrik-Elektronik Yük. Müh.
Cevapla
#6
Soruma cevap alamadım, cihazı her bir paket için 1251 microsec hesaplamış, bu niyet okuma yani beklenti. 
* Sizin proje bunu süre kayıpları dahil veri başına kaç tick (milisaniye micro değil hatırlatayım)  ile işleyebiliyor şu an.
Hesaplarken en hızlısı ilk paket, en yavaşı ise toplam tarama süresi sonundaki en son paket üzerinden hesaplarsanız daha sağlıklı olur.


* EKLEME :
Bu hesap sonunda bir de farklı bir yoldan, yani tüm noktalar elde edildikten yani derleme işi bittikten sonra, noktaları sıfırdan çizmeye başladığınız taktirde süreler nasıl değişiyor ona bir değerleme yapmanızı salık veririm. Böylece kombine işlemleri iş paketleri haline de dönüştürerek CPU kaynak harcaması üzerinde verim arttırım yapılabilir mi ? cevap için faydalı olacaktır.

Yanlış anlaşılma olmasın "iş bitince çizdir" anlamına gelen bir çalışma değil, işlemlerin ( Wait[1] vb ) sadece süreç üzerindeki etkisini yargılıyoruz !!
Saygılarımla
Muharrem ARMAN

guplouajuixjzfm15eqb.gif
Cevapla
#7
(21-03-2021, Saat: 21:42)mrmarman Adlı Kullanıcıdan Alıntı: Soruma cevap alamadım, cihazı her bir paket için 1251 microsec hesaplamış, bu niyet okuma yani beklenti. 
* Sizin proje bunu süre kayıpları dahil veri başına kaç tick (milisaniye micro değil hatırlatayım)  ile işleyebiliyor şu an.
Hesaplarken en hızlısı ilk paket, en yavaşı ise toplam tarama süresi sonundaki en son paket üzerinden hesaplarsanız daha sağlıklı olur.

Tekrar Merhaba 

Procedure VLP16_DataBlock_Olustur(Gelen_Veri : TIdBytes) için Gettickcount ile ölçtüğümde sonuç 15 olarak çıkmaktadır.
Cevapla
#8
1251 microniyelik her veri için 15000 microsaniye işlem süresi lazım. Yani yani sizin her mevcut sistemi koruyarak 12 thread kurmanız gerekiyor ki yetişsin. 13. veri geldiğinde ilk thread sona ersin.

Bunu bir de boş olarak hesaplayın... Yukarıda mesajıma ek yazmıştım.
Saygılarımla
Muharrem ARMAN

guplouajuixjzfm15eqb.gif
Cevapla
#9
(21-03-2021, Saat: 21:59)mrmarman Adlı Kullanıcıdan Alıntı: 1251 microniyelik her veri için 15000 microsaniye işlem süresi lazım. Yani yani sizin her mevcut sistemi koruyarak 12 thread kurmanız gerekiyor ki yetişsin. 13. veri geldiğinde ilk thread sona ersin.

Bunu bir de boş olarak hesaplayın... Yukarıda mesajıma ek yazmıştım.

Hocam çok özür dileyerek ben bir kaç farklı procedure üzerinde çalışıyordum önceki 15ms olan procedure'de gelen veriyi bir dizide toplayım ne kadar veri geldi ise o kadar veriyi işliyordum. sadece 1206Byte'lık veriyi işlediğim diğer procedure' de GettickCount ile ölçüm yaptım ve sonuç 0 olarak geri döndü kodu aşığıda paylaşıyorum. 

procedure VLP16_DataBlock_Olustur(Gelen_Veri : TIdBytes);inline;
var
 I: Integer;
 J: Integer;
 Nokta_Mesafesi : Float32;
 Lazer_Yansimasi : Byte;
 Sayac: Integer;
Baslangic, Bitis : Cardinal;
begin
 Baslangic := GetTickCount;
 SetLength(VLP16_Data_Blok_Veri,0);
 if (Length(Gelen_Veri) = 1206) then
 begin
     //Application.ProcessMessages;
     for I := 0 to 11 do
     begin
         SetLength(VLP16_Data_Blok_Veri,Length(VLP16_Data_Blok_Veri)+1);
         with VLP16_Data_Blok_Veri[High(VLP16_Data_Blok_Veri)] do
         begin
           Data_Block_No := I;
           Flag_Low      := Gelen_Veri[I*100+0];
           Flag_High     := Gelen_Veri[I*100+1];
           Azimuth       := (Gelen_Veri[I*100+3]*$FF+Gelen_Veri[I*100+2]) / 100.0;
           IMU_VLP16     := IMU;
           Time_Stamp    := (Gelen_Veri[1203]*$FFFFFF + Gelen_Veri[1202]*$FFFF + Gelen_Veri[1201]*$FF + Gelen_Veri[1200]) / 1000000;
           for J := 0 to 15 do
           begin
             Channel_Data[J].Distance       := ((Gelen_Veri[I*100+J*3+5]*$FF+Gelen_Veri[I*100+J*3+4]) * 2.0)/1000.0;
             Channel_Data[J].Reflectivity   := Gelen_Veri[I*100+J*3+6];
             Channel_Data[J].Vertical_Angel := Dikey_Aci[J];
             Nokta_Mesafesi  := Channel_Data[J].Distance;
             Lazer_Yansimasi := Channel_Data[J].Reflectivity;
             if (Nokta_Mesafesi > 0) and (Lazer_Yansimasi > 0) then
             begin
               Anlik_Verileri_Ciz(Channel_Data[J].Distance, Azimuth, Channel_Data[J].Vertical_Angel, IMU_VLP16, Channel_Data[J].Reflectivity);
             end;
           end;
         end;

   end;
   SetLength(Gelen_Veri_VLP16,0);
   Bitis := GetTickCount - baslangic;
 end;
end;
Cevapla
#10
0 olması doğal TickCount milisaniye cinsinden, onun altınaki her şey 0 gelir.
Önerime geleyim.  Size iki seçenek sunuluyor.

1. Optimizasyon ile işlem süresini azaltmak. Öncelik projenizin mainthread dahilinde sadece ve sadece noktaları collect etmek. Çizim işlemini bağımsız bir thread'e koyup, hali hazıda sırada bekleyen noktaları demlenerek diye tabir edeyim -tabiri bağışlayın- ekranda görüntülenmesini izlemek. Taa ki veri akışı sona erip de liste sonuna ulaşana kadar listeye syncronize sürecek bir thread.

2. Her gelen veri için bağımsız birer TThread açıp TObjectList altına ekleyip, FreeOnTerminate ile işi biten Thread'in kendini yok ederken EVENT altında TObjectlist altındaki Thread'i DELETE etmek. Bu işlem için öngördüğüm aynı anda çalışacak en fazla 13 thread açıp kapatacaktır diye değerlendiriyorum.
Saygılarımla
Muharrem ARMAN

guplouajuixjzfm15eqb.gif
Cevapla


Konu ile Alakalı Benzer Konular
Konular Yazar Yorumlar Okunma Son Yorum
  Logo Go3 de döviz tablosunda Date_ alanına veri (Çözüldü) yazma cinarbil 4 183 19-04-2024, Saat: 08:25
Son Yorum: cinarbil
  Donanım bilgilerini almak için geliştirilmiş güzel bir proje burakb44 2 258 02-04-2024, Saat: 16:06
Son Yorum: burakb44
  IEC 61850 Potokolünden veri alma shooterman 1 451 14-03-2024, Saat: 11:38
Son Yorum: shooterman
  Veri Tabanına Kontrollü Kayıt Yaptırma bünyamin68 15 845 08-03-2024, Saat: 00:06
Son Yorum: TuncayDelphi
  Problem - ZKTeco Cihazlardan Anlık Veri Alma mad85 16 8.192 25-12-2023, Saat: 11:35
Son Yorum: osiso



Konuyu Okuyanlar: 1 Ziyaretçi