Yorumları: 12
Konuları: 3
Kayıt Tarihi: 19-03-2021
Aktif Kullandığınız Delphi Sürümü:
- Delphi 10.3
- Delphi XE Serisi
Rep Puanı: 149 Başlangıç
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;
Yorumları: 120
Konuları: 12
Kayıt Tarihi: 06-06-2020
Aktif Kullandığınız Delphi Sürümü:
Rep Puanı: 1.331 Programcı
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
Yorumları: 1.668
Konuları: 20
Kayıt Tarihi: 05-08-2016
Aktif Kullandığınız Delphi Sürümü:
Rep Puanı: 19.064 Üstad
21-03-2021, Saat: 19:57
(Son Düzenleme: 21-03-2021, Saat: 20:02, Düzenleyen: mrmarman.)
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
Yorumları: 903
Konuları: 68
Kayıt Tarihi: 30-06-2017
Aktif Kullandığınız Delphi Sürümü:
Rep Puanı: 8.400 Üstad
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
Yorumları: 12
Konuları: 3
Kayıt Tarihi: 19-03-2021
Aktif Kullandığınız Delphi Sürümü:
- Delphi 10.3
- Delphi XE Serisi
Rep Puanı: 149 Başlangıç
21-03-2021, Saat: 21:36
(Son Düzenleme: 21-03-2021, Saat: 21:42, Düzenleyen: nuheroglu.)
(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 . 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.
Yorumları: 1.668
Konuları: 20
Kayıt Tarihi: 05-08-2016
Aktif Kullandığınız Delphi Sürümü:
Rep Puanı: 19.064 Üstad
21-03-2021, Saat: 21:42
(Son Düzenleme: 21-03-2021, Saat: 21:55, Düzenleyen: mrmarman.)
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
Yorumları: 12
Konuları: 3
Kayıt Tarihi: 19-03-2021
Aktif Kullandığınız Delphi Sürümü:
- Delphi 10.3
- Delphi XE Serisi
Rep Puanı: 149 Başlangıç
(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.
Yorumları: 1.668
Konuları: 20
Kayıt Tarihi: 05-08-2016
Aktif Kullandığınız Delphi Sürümü:
Rep Puanı: 19.064 Üstad
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
Yorumları: 12
Konuları: 3
Kayıt Tarihi: 19-03-2021
Aktif Kullandığınız Delphi Sürümü:
- Delphi 10.3
- Delphi XE Serisi
Rep Puanı: 149 Başlangıç
(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;
Yorumları: 1.668
Konuları: 20
Kayıt Tarihi: 05-08-2016
Aktif Kullandığınız Delphi Sürümü:
Rep Puanı: 19.064 Üstad
21-03-2021, Saat: 22:21
(Son Düzenleme: 21-03-2021, Saat: 22:25, Düzenleyen: mrmarman.)
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
|